Account for TZ offsets for event durations and next occurrence
Summary
Adds a utility function to get the tz offset delta between two dates. Uses the function when calculating the duration of an event and also when we are trying to find the next occurrence.
This fixes
- issue of getting duplicate events for recurring schedules, especially during "fall back" dst changes.
- issue of bad or unexpected durations for events that span the DST
Comments
When a "human" says they want a repeating event from 1a-9a, what they really mean is 1a "local (my) time" to 9a "local (my) time". They would expect the system to handle the DST change and calculate appropriately, they don't really mean "I always want the duration to be 8 hours".
Example
Below is an example script you can use to test with the main branch to see the issue, and then you can test with this branch to see that is fixed. I've also left the results here so you can easily see.
The script
def print(occurrences)
occurrences.each do |occurrence|
puts occurrence
end
end
duration = 8.hours
tz = 'Central Time (US & Canada)'
dst_date = "2021-11-07 01:00:00".in_time_zone(tz) # date of dst switch "fall back" 2021
# dst_date = "2021-03-14 01:00:00".in_time_zone(tz) # date of dst switch "spring foward" 2021
start_time = (dst_date - 2.days).in_time_zone(tz)
end_time = (dst_date + 2.days).in_time_zone(tz)
schedule = IceCube::Schedule.new(start_time, duration: duration)
schedule.add_recurrence_rule(IceCube::Rule.daily.until(end_time))
occurrences = schedule.occurrences(end_time)
print(occurrences)
Results for "fall back" case
The current behavior (seejohnrun/ice_cube#main)
2021-11-05 01:00:00 -0500 - 2021-11-05 09:00:00 -0500
2021-11-06 01:00:00 -0500 - 2021-11-06 09:00:00 -0500
2021-11-07 01:00:00 -0500 - 2021-11-07 08:00:00 -0600 <--- Duplicate (and does not go until 9)
2021-11-07 01:00:00 -0600 - 2021-11-07 09:00:00 -0600 <--- Duplicate (but and forces the offset)
2021-11-08 01:00:00 -0600 - 2021-11-08 09:00:00 -0600
2021-11-09 01:00:00 -0600 - 2021-11-09 09:00:00 -0600
The expected behavior (PagerTree/ice_cube#main)
2021-11-05 01:00:00 -0500 - 2021-11-05 09:00:00 -0500
2021-11-06 01:00:00 -0500 - 2021-11-06 09:00:00 -0500
2021-11-07 01:00:00 -0500 - 2021-11-07 09:00:00 -0600 <--- Fixed and has a true duration of 9 hours
2021-11-08 01:00:00 -0600 - 2021-11-08 09:00:00 -0600
2021-11-09 01:00:00 -0600 - 2021-11-09 09:00:00 -0600
Results for "spring forward" case
The current behavior (seejohnrun/ice_cube#main)
2021-03-12 01:00:00 -0600 - 2021-03-12 09:00:00 -0600
2021-03-13 01:00:00 -0600 - 2021-03-13 09:00:00 -0600
2021-03-14 01:00:00 -0600 - 2021-03-14 10:00:00 -0500 <--- Bad duration
2021-03-15 01:00:00 -0500 - 2021-03-15 09:00:00 -0500
2021-03-16 01:00:00 -0500 - 2021-03-16 09:00:00 -0500
The expected behavior (PagerTree/ice_cube#main)
2021-03-12 01:00:00 -0600 - 2021-03-12 09:00:00 -0600
2021-03-13 01:00:00 -0600 - 2021-03-13 09:00:00 -0600
2021-03-14 01:00:00 -0600 - 2021-03-14 09:00:00 -0500 <--- Correctly has a true timespan of 7 hours
2021-03-15 01:00:00 -0500 - 2021-03-15 09:00:00 -0500
2021-03-16 01:00:00 -0500 - 2021-03-16 09:00:00 -0500