From 4ddc2b5b6433686d55e686f1198681e77c8cc348 Mon Sep 17 00:00:00 2001 From: Austin Miller Date: Thu, 7 Oct 2021 09:04:39 -0500 Subject: [PATCH 1/2] Adds correcting logic for events with durations so we account for the offset of events spanning zones (utc offsets) --- lib/ice_cube/schedule.rb | 7 ++++++- lib/ice_cube/time_util.rb | 11 +++++++++++ lib/ice_cube/validated_rule.rb | 2 ++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/ice_cube/schedule.rb b/lib/ice_cube/schedule.rb index 9f930cb3..6da570c9 100644 --- a/lib/ice_cube/schedule.rb +++ b/lib/ice_cube/schedule.rb @@ -456,7 +456,12 @@ def next_time(time, closing_time) end break unless min_time next (time = min_time + 1) if exception_time?(min_time) - break Occurrence.new(min_time, min_time + duration) + + e_time = min_time + duration + # Make sure to add the timezone difference, in case we span tz zones (offsets) + # majority of cases this will be 0, but when we span tz zones, we need to account for it + e_time += TimeUtil.zone_offset_delta(min_time, e_time) + break Occurrence.new(min_time, e_time) end end diff --git a/lib/ice_cube/time_util.rb b/lib/ice_cube/time_util.rb index ff43399e..e36093a5 100644 --- a/lib/ice_cube/time_util.rb +++ b/lib/ice_cube/time_util.rb @@ -268,6 +268,17 @@ def self.subsec(time) end end + # Returns the timezone delta (seconds) between 2 times. + # - For times in the same timezone this will return 0. + # - For times than span offsets (think Daylight Savings time to Standard Time) + # this number will be positive or negative, depening if you "spring foward" or "fall back". + # - The order of arguments is important, in 99% of use cases t0 is a date *before* t1 (aka time only moves foward). + # - For "fall back" this will be positive, aka we gained time (usually an hour, 3600) + # - For "spring foward" this will be negative, aka we lost time (usually an hour, -3600) + def self.zone_offset_delta(t0, t1) + t0.utc_offset - t1.utc_offset + end + # A utility class for safely moving time around class TimeWrapper diff --git a/lib/ice_cube/validated_rule.rb b/lib/ice_cube/validated_rule.rb index 69830fab..ddbf35fa 100644 --- a/lib/ice_cube/validated_rule.rb +++ b/lib/ice_cube/validated_rule.rb @@ -156,6 +156,8 @@ def shift_time_by_validation(res, validation) return unless (interval = res.min) wrapper = TimeUtil::TimeWrapper.new(@time, validation.dst_adjust?) wrapper.add(validation.type, interval) + # add the zone delta, so we don't get duplicates when we roll across DST + wrapper.add(:sec, TimeUtil.zone_offset_delta(@time, wrapper.to_time)) wrapper.clear_below(validation.type) # Move over DST if blocked, no adjustments From 836900e6c9eaa5a15a0f8bbc219f91f1e7b053e9 Mon Sep 17 00:00:00 2001 From: Austin Miller Date: Mon, 11 Oct 2021 16:52:19 -0500 Subject: [PATCH 2/2] Remove the added shift_time_by_validation, this was due to bad testing --- lib/ice_cube/validated_rule.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/ice_cube/validated_rule.rb b/lib/ice_cube/validated_rule.rb index ddbf35fa..69830fab 100644 --- a/lib/ice_cube/validated_rule.rb +++ b/lib/ice_cube/validated_rule.rb @@ -156,8 +156,6 @@ def shift_time_by_validation(res, validation) return unless (interval = res.min) wrapper = TimeUtil::TimeWrapper.new(@time, validation.dst_adjust?) wrapper.add(validation.type, interval) - # add the zone delta, so we don't get duplicates when we roll across DST - wrapper.add(:sec, TimeUtil.zone_offset_delta(@time, wrapper.to_time)) wrapper.clear_below(validation.type) # Move over DST if blocked, no adjustments