I've got a number of time ranges in Ruby:
period = Time.parse('8:00am')..Time.parse('8:00pm')
incidents = [
Time.parse('7:00am')..Time.parse('9:00am'),
Time.parse('1:00pm')..Time.parse('3:00pm'),
Time.parse('1:30pm')..Time.parse('3:30pm'),
Time.parse('7:00pm')..Time.parse('9:00pm'),
]
I'm trying to get an array of incident free blocks within the period. For the above that'd be:
[
Time.parse('9:00am')..Time.parse('1:00pm')
Time.parse('3:30pm')..Time.parse('7:00pm')
]
From the above it is possible for incidents to overlap or extend outside the period. Do any operations exist on range or something similar that would make this sort of calculation simpler?
Using this range operator gem, this script would (almost) return what you want.
It begins with period
, and substracts every incident
one after the other.
Since substracting a range from another can result in two ranges, the script actually begins with [period]
and keeps an array of free incident ranges between iterations :
require 'range_operators'
incident_free = incidents.inject([period]) do |free_ranges, incident|
free_ranges.flat_map do |free_range|
free_range - incident
end
end
p incident_free
#=> [2016-12-22 09:00:01 +0100..2016-12-22 12:59:59 +0100, 2016-12-22 15:30:01 +0100..2016-12-22 18:59:59 +0100]
It complains that Time#succ
is obsolete. You can either add
class Time
def succ
self+1
end
end
to remove the deprecation warnings, or use a Gemfile with :
gem 'range_operators', :git => 'https://github.com/monocle/range_operators.git'
to install a newer version of the gem, with a fix for Time
.
The script works with a resolution of 1 second, and the first range begins at 09:00:01
because there was an incident until 09:00:00
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With