From 99522388f24df976c92fd072bbbdb170f132b800 Mon Sep 17 00:00:00 2001 From: Lars Kuhnt Date: Wed, 24 Apr 2024 17:18:30 +0200 Subject: [PATCH 1/7] added specs for weekly DST issue --- spec/examples/fixed_value_spec.rb | 17 +++++++++++++++ spec/examples/schedule_spec.rb | 29 +++++++++++++++++++++++++ spec/examples/time_util_spec.rb | 16 ++++++++++++++ spec/examples/weekly_rule_spec.rb | 35 +++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 spec/examples/fixed_value_spec.rb diff --git a/spec/examples/fixed_value_spec.rb b/spec/examples/fixed_value_spec.rb new file mode 100644 index 00000000..93054416 --- /dev/null +++ b/spec/examples/fixed_value_spec.rb @@ -0,0 +1,17 @@ +require "spec_helper" + +RSpec.describe IceCube::Validations::HourOfDay::Validation do + + describe :validate do + let(:timezone) { "Africa/Cairo" } + let(:time) { "2024-05-03 00:20:00" } + let(:time_in_zone) { ActiveSupport::TimeZone[timezone].parse(time) } + let(:start_time) { ActiveSupport::TimeZone[timezone].parse("2024-04-26 01:20:00") } + + let(:validation) { IceCube::Validations::HourOfDay::Validation.new(nil) } + + it "returns the correct offset for the same hour" do + expect(validation.validate(time_in_zone, start_time)).to eq 1 + end + end +end \ No newline at end of file diff --git a/spec/examples/schedule_spec.rb b/spec/examples/schedule_spec.rb index efbf935d..9764028c 100644 --- a/spec/examples/schedule_spec.rb +++ b/spec/examples/schedule_spec.rb @@ -390,6 +390,35 @@ expect(next_hours).to eq [Time.utc(2014, 1, 2, 0o0, 34, 56), Time.utc(2014, 1, 2, 0o1, 34, 56)] end + + context "Cairo timezone" do + let(:schedule) do + IceCube::Schedule.from_yaml("---\n:start_time:\n :time: 2022-05-05 22:20:00.000000000 Z\n :zone: Africa/Cairo\n:end_time:\n :time: 2022-05-06 21:40:00.000000000 Z\n :zone: Africa/Cairo\n:rrules:\n- :validations:\n :day:\n - 5\n :rule_type: IceCube::WeeklyRule\n :interval: 1\n :week_start: 1\n:rtimes: []\n:extimes: []\n") + end + + it "has the correct start time" do + expect(schedule.start_time.iso8601).to eq("2022-05-06T00:20:00+02:00") + end + + it "calculates the corret occurrences from 2024-04-24" do + ref_time = Time.utc(2024, 4, 24, 12, 0, 0) + occurrences = schedule.next_occurrences(3, ref_time) + expect(occurrences.map(&:iso8601)).to eq([ + "2024-04-26T01:20:00+03:00", + "2024-05-03T00:20:00+03:00", + "2024-05-10T00:20:00+03:00" + ]) + end + + it "calculates the corret occurrences from 2024-04-21" do + occurrences = schedule.next_occurrences(3, Time.utc(2024, 4, 21, 12, 0, 0)) + expect(occurrences.map(&:iso8601)).to eq([ + "2024-04-26T01:20:00+03:00", + "2024-05-03T00:20:00+03:00", + "2024-05-10T00:20:00+03:00" + ]) + end + end end describe :next_occurrence do diff --git a/spec/examples/time_util_spec.rb b/spec/examples/time_util_spec.rb index 43491a8b..0cb7359b 100644 --- a/spec/examples/time_util_spec.rb +++ b/spec/examples/time_util_spec.rb @@ -118,5 +118,21 @@ module IceCube end end end + + describe :dst_change do + let(:timezone) { "Africa/Cairo" } + let(:time) { "2024-04-26 00:20:00" } + let(:time_in_zone) { ActiveSupport::TimeZone[timezone].parse(time) } + + subject { TimeUtil.dst_change(time_in_zone) } + + it { is_expected.to eql(1) } + + context "when time is not on a DST change" do + let(:time) { "2024-04-25 00:20:00" } + + it { is_expected.to be_nil } + end + end end end diff --git a/spec/examples/weekly_rule_spec.rb b/spec/examples/weekly_rule_spec.rb index 3e8e5719..c6577d5e 100644 --- a/spec/examples/weekly_rule_spec.rb +++ b/spec/examples/weekly_rule_spec.rb @@ -390,5 +390,40 @@ module IceCube end end end + + context "when start time is within a timezone shift in Africa/Cairo timezone", system_time_zone: "UTC" do + let(:cairo_tz) { ActiveSupport::TimeZone["Africa/Cairo"] } + let(:utc_tz) { ActiveSupport::TimeZone["UTC"] } + let(:start_time) { cairo_tz.parse("2022-05-22 00:20:00") } + let(:rule) { Rule.weekly(1, :monday).day(:friday) } + + it "parses the start time correctly" do + expect(start_time.iso8601).to eq("2022-05-22T00:20:00+02:00") + end + + it "calculates the correct time from 2024-04-24 12:00:00 UTC" do + expect(rule.next_time(utc_tz.parse("2024-04-24 12:00:00"), start_time, nil).iso8601).to eq("2024-04-26T01:20:00+03:00") + end + + it "calculates the correct time from 2024-04-26 00:20:01 Africa/Cairo" do + expect(rule.next_time(cairo_tz.parse("2024-04-26 00:20:01"), start_time, nil).iso8601).to eq("2024-05-03T00:20:00+03:00") + end + end + + describe :realign do + let(:cairo_tz) { ActiveSupport::TimeZone["Africa/Cairo"] } + let(:utc_tz) { ActiveSupport::TimeZone["UTC"] } + let(:start_time) { cairo_tz.parse("2022-05-22 00:20:00") } + let(:time) { utc_tz.parse("2024-04-24 12:00:00") } + let(:rule) { Rule.weekly(1, :monday).day(:friday) } + + subject { rule.realign(time, start_time)} + + it { puts cairo_tz.parse("2024-04-26T00:20:00") } + + it "realigns the start time to the correct time" do + expect(subject.iso8601).to eq("2024-04-26T01:20:00+03:00") + end + end end end From 30a2eb39943c95e1f8e4bbfd1a7350e3851b371b Mon Sep 17 00:00:00 2001 From: Lars Kuhnt Date: Thu, 25 Apr 2024 10:27:16 +0200 Subject: [PATCH 2/7] use timezoneless time for weekly rule realigns --- lib/ice_cube/rules/weekly_rule.rb | 2 +- lib/ice_cube/time_util.rb | 16 ++++++++++++++++ spec/examples/schedule_spec.rb | 2 +- spec/examples/weekly_rule_spec.rb | 4 ++-- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/ice_cube/rules/weekly_rule.rb b/lib/ice_cube/rules/weekly_rule.rb index e24f77f9..038f983b 100644 --- a/lib/ice_cube/rules/weekly_rule.rb +++ b/lib/ice_cube/rules/weekly_rule.rb @@ -35,7 +35,7 @@ def realign(step_time, start_time) time = TimeUtil::TimeWrapper.new(start_time) offset = wday_offset(step_time, start_time) time.add(:day, offset) - super step_time, time.to_time + super step_time, time.to_timezoneless_time end # Calculate how many days to the first wday validation in the correct diff --git a/lib/ice_cube/time_util.rb b/lib/ice_cube/time_util.rb index 001d927d..5db12ab3 100644 --- a/lib/ice_cube/time_util.rb +++ b/lib/ice_cube/time_util.rb @@ -282,6 +282,22 @@ def to_time TimeUtil.build_in_zone(parts, @base) end + # This is used keep the correct hour within the interval during DST + # changes. It will use the time from the schedule start time to lock the + # hour. + def to_timezoneless_time + unwrapped_time = to_time + Time.new( + unwrapped_time.year, + unwrapped_time.month, + unwrapped_time.day, + @time.hour, + @time.min, + @time.sec, + unwrapped_time.utc_offset + ) + end + # DST-safely add an interval of time to the wrapped time def add(type, val) type = :day if type == :wday diff --git a/spec/examples/schedule_spec.rb b/spec/examples/schedule_spec.rb index 9764028c..561890c2 100644 --- a/spec/examples/schedule_spec.rb +++ b/spec/examples/schedule_spec.rb @@ -404,7 +404,7 @@ ref_time = Time.utc(2024, 4, 24, 12, 0, 0) occurrences = schedule.next_occurrences(3, ref_time) expect(occurrences.map(&:iso8601)).to eq([ - "2024-04-26T01:20:00+03:00", + "2024-04-26T00:20:00+03:00", "2024-05-03T00:20:00+03:00", "2024-05-10T00:20:00+03:00" ]) diff --git a/spec/examples/weekly_rule_spec.rb b/spec/examples/weekly_rule_spec.rb index c6577d5e..50c3ec69 100644 --- a/spec/examples/weekly_rule_spec.rb +++ b/spec/examples/weekly_rule_spec.rb @@ -402,7 +402,7 @@ module IceCube end it "calculates the correct time from 2024-04-24 12:00:00 UTC" do - expect(rule.next_time(utc_tz.parse("2024-04-24 12:00:00"), start_time, nil).iso8601).to eq("2024-04-26T01:20:00+03:00") + expect(rule.next_time(utc_tz.parse("2024-04-24 12:00:00"), start_time, nil).iso8601).to eq("2024-04-26T00:20:00+03:00") end it "calculates the correct time from 2024-04-26 00:20:01 Africa/Cairo" do @@ -422,7 +422,7 @@ module IceCube it { puts cairo_tz.parse("2024-04-26T00:20:00") } it "realigns the start time to the correct time" do - expect(subject.iso8601).to eq("2024-04-26T01:20:00+03:00") + expect(subject.iso8601).to eq("2024-04-26T00:20:00+03:00") end end end From c7c19700097497fc47bef11b7f1991ad23ec0658 Mon Sep 17 00:00:00 2001 From: Lars Kuhnt Date: Thu, 25 Apr 2024 10:44:18 +0200 Subject: [PATCH 3/7] fixed some lint issues --- spec/examples/schedule_spec.rb | 2 +- spec/examples/weekly_rule_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/examples/schedule_spec.rb b/spec/examples/schedule_spec.rb index 561890c2..52f4f149 100644 --- a/spec/examples/schedule_spec.rb +++ b/spec/examples/schedule_spec.rb @@ -395,7 +395,7 @@ let(:schedule) do IceCube::Schedule.from_yaml("---\n:start_time:\n :time: 2022-05-05 22:20:00.000000000 Z\n :zone: Africa/Cairo\n:end_time:\n :time: 2022-05-06 21:40:00.000000000 Z\n :zone: Africa/Cairo\n:rrules:\n- :validations:\n :day:\n - 5\n :rule_type: IceCube::WeeklyRule\n :interval: 1\n :week_start: 1\n:rtimes: []\n:extimes: []\n") end - + it "has the correct start time" do expect(schedule.start_time.iso8601).to eq("2022-05-06T00:20:00+02:00") end diff --git a/spec/examples/weekly_rule_spec.rb b/spec/examples/weekly_rule_spec.rb index 50c3ec69..362a4978 100644 --- a/spec/examples/weekly_rule_spec.rb +++ b/spec/examples/weekly_rule_spec.rb @@ -417,7 +417,7 @@ module IceCube let(:time) { utc_tz.parse("2024-04-24 12:00:00") } let(:rule) { Rule.weekly(1, :monday).day(:friday) } - subject { rule.realign(time, start_time)} + subject { rule.realign(time, start_time) } it { puts cairo_tz.parse("2024-04-26T00:20:00") } From b6bad317305da4411915b53e31d62c997dc6d629 Mon Sep 17 00:00:00 2001 From: Lars Kuhnt Date: Thu, 25 Apr 2024 10:45:58 +0200 Subject: [PATCH 4/7] updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0022b92..4689cf6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed use of `delegate` method added in [66f1d797](https://github.com/ice-cube-ruby/ice_cube/commit/66f1d797092734563bfabd2132c024c7d087f683) , reverting to previous implementation. ([#522](https://github.com/ice-cube-ruby/ice_cube/pull/522)) by [@pacso](https://github.com/pacso) ### Fixed +- Fix for weekly occurrences when the next occurrence happens within a DST switch timespan ([#551](https://github.com/ice-cube-ruby/ice_cube/pull/551)) by [@larskuhnt](https://github.com/larskuhnt) - Fix for weekly interval results when requesting `occurrences_between` on a narrow range ([#487](https://github.com/seejohnrun/ice_cube/pull/487)) by [@jakebrady5](https://github.com/jakebrady5) - When using a rule with hour_of_day validations, and asking for occurrences on the day that DST skips forward, valid occurrences would be missed. ([#464](https://github.com/seejohnrun/ice_cube/pull/464)) by [@jakebrady5](https://github.com/jakebrady5) - Include `exrules` when exporting a schedule to YAML, JSON or a Hash. ([#519](https://github.com/ice-cube-ruby/ice_cube/pull/519)) by [@pacso](https://github.com/pacso) From 0df29bc7715b33c305d2b8098d1f75c67211ef1e Mon Sep 17 00:00:00 2001 From: Lars Kuhnt Date: Fri, 26 Apr 2024 11:44:45 +0200 Subject: [PATCH 5/7] review fixes and added comments --- lib/ice_cube/rules/weekly_rule.rb | 9 ++++++++- spec/examples/fixed_value_spec.rb | 2 +- spec/examples/schedule_spec.rb | 24 ++++++++++++++++-------- spec/examples/weekly_rule_spec.rb | 28 +++++++++++++++++++++++----- 4 files changed, 48 insertions(+), 15 deletions(-) diff --git a/lib/ice_cube/rules/weekly_rule.rb b/lib/ice_cube/rules/weekly_rule.rb index 038f983b..6c382d10 100644 --- a/lib/ice_cube/rules/weekly_rule.rb +++ b/lib/ice_cube/rules/weekly_rule.rb @@ -35,7 +35,14 @@ def realign(step_time, start_time) time = TimeUtil::TimeWrapper.new(start_time) offset = wday_offset(step_time, start_time) time.add(:day, offset) - super step_time, time.to_timezoneless_time + realigned_time = time.to_time + # when the realigned time is in a different hour, we need to adjust the + # time to the correct hour with a fixed timezone offset, otherwise + # the time will be off by an hour + # WARNING: if the next DST change is within the interval, the occurrences + # after the next DST change will be off by an hour because the timezone is fixed + realigned_time = time.to_timezoneless_time if realigned_time.hour != start_time.hour + super step_time, realigned_time end # Calculate how many days to the first wday validation in the correct diff --git a/spec/examples/fixed_value_spec.rb b/spec/examples/fixed_value_spec.rb index 93054416..ebee6153 100644 --- a/spec/examples/fixed_value_spec.rb +++ b/spec/examples/fixed_value_spec.rb @@ -14,4 +14,4 @@ expect(validation.validate(time_in_zone, start_time)).to eq 1 end end -end \ No newline at end of file +end diff --git a/spec/examples/schedule_spec.rb b/spec/examples/schedule_spec.rb index 52f4f149..ccc20d56 100644 --- a/spec/examples/schedule_spec.rb +++ b/spec/examples/schedule_spec.rb @@ -391,31 +391,39 @@ Time.utc(2014, 1, 2, 0o1, 34, 56)] end - context "Cairo timezone" do + context "Cairo timezone", system_time_zone: 'Africa/Cairo' do + require "active_support/time" + let(:schedule) do IceCube::Schedule.from_yaml("---\n:start_time:\n :time: 2022-05-05 22:20:00.000000000 Z\n :zone: Africa/Cairo\n:end_time:\n :time: 2022-05-06 21:40:00.000000000 Z\n :zone: Africa/Cairo\n:rrules:\n- :validations:\n :day:\n - 5\n :rule_type: IceCube::WeeklyRule\n :interval: 1\n :week_start: 1\n:rtimes: []\n:extimes: []\n") + # IceCube::Schedule.new(ActiveSupport::TimeZone['Africa/Cairo'].parse("2022-05-05 00:20:00")).tap do |schedule| + # schedule.add_recurrence_rule IceCube::Rule.weekly.day(:friday) + # end end it "has the correct start time" do expect(schedule.start_time.iso8601).to eq("2022-05-06T00:20:00+02:00") end - it "calculates the corret occurrences from 2024-04-24" do - ref_time = Time.utc(2024, 4, 24, 12, 0, 0) - occurrences = schedule.next_occurrences(3, ref_time) + it "has the correct start time timezone" do + expect(schedule.start_time.zone).to eq("EET") + end + + it "calculates the correct occurrences from 2024-04-24" do + occurrences = schedule.next_occurrences(3, Time.utc(2024, 4, 24, 12, 0, 0)) expect(occurrences.map(&:iso8601)).to eq([ "2024-04-26T00:20:00+03:00", "2024-05-03T00:20:00+03:00", - "2024-05-10T00:20:00+03:00" + "2024-05-10T00:20:00+03:00", ]) end - it "calculates the corret occurrences from 2024-04-21" do - occurrences = schedule.next_occurrences(3, Time.utc(2024, 4, 21, 12, 0, 0)) + it "calculates the correct occurrences from 2024-04-17" do + occurrences = schedule.next_occurrences(3, Time.utc(2024, 4, 17, 12, 0, 0)) expect(occurrences.map(&:iso8601)).to eq([ + "2024-04-19T00:20:00+02:00", "2024-04-26T01:20:00+03:00", "2024-05-03T00:20:00+03:00", - "2024-05-10T00:20:00+03:00" ]) end end diff --git a/spec/examples/weekly_rule_spec.rb b/spec/examples/weekly_rule_spec.rb index 362a4978..dc61bab3 100644 --- a/spec/examples/weekly_rule_spec.rb +++ b/spec/examples/weekly_rule_spec.rb @@ -411,19 +411,37 @@ module IceCube end describe :realign do - let(:cairo_tz) { ActiveSupport::TimeZone["Africa/Cairo"] } + require "active_support/time" + + let(:timezone_name) { "Africa/Cairo" } + let(:timezone) { ActiveSupport::TimeZone[timezone_name] } let(:utc_tz) { ActiveSupport::TimeZone["UTC"] } - let(:start_time) { cairo_tz.parse("2022-05-22 00:20:00") } + let(:start_time) { timezone.parse("2022-05-22 00:20:00") } let(:time) { utc_tz.parse("2024-04-24 12:00:00") } - let(:rule) { Rule.weekly(1, :monday).day(:friday) } + let(:recurrence_day) { :friday } + let(:rule) { Rule.weekly(1, :monday).day(recurrence_day) } subject { rule.realign(time, start_time) } - it { puts cairo_tz.parse("2024-04-26T00:20:00") } - it "realigns the start time to the correct time" do expect(subject.iso8601).to eq("2024-04-26T00:20:00+03:00") end + + context "Berlin timezone" do + let(:recurrence_day) { :sunday } + let(:timezone_name) { "Europe/Berlin" } + let(:start_time) { timezone.parse("2024-03-24 02:30:00") } + let(:time) { timezone.parse("2024-03-27 02:30:00") } + + # the next occurrence is on sunday within the DST shift + # where the clock is set forward from 02:00 to 03:00 + # so the next occurrence is on actually on 03:30 but this + # would result in faulty start times for the following + # occurrences (03:30 instead of 02:30) + it "realigns the start time to the correct time" do + expect(subject.iso8601).to eq("2024-03-31T02:30:00+02:00") + end + end end end end From d6b49d251dd92df6a59cd469c5e3c0eac3f229a4 Mon Sep 17 00:00:00 2001 From: Lars Kuhnt Date: Fri, 26 Apr 2024 12:27:27 +0200 Subject: [PATCH 6/7] realign time to the correct hour during DST changes --- lib/ice_cube/rules/weekly_rule.rb | 15 +++++++++------ lib/ice_cube/time_util.rb | 16 ---------------- spec/examples/schedule_spec.rb | 22 +++++++++++++++------- spec/examples/weekly_rule_spec.rb | 21 ++++++++++++++++----- 4 files changed, 40 insertions(+), 34 deletions(-) diff --git a/lib/ice_cube/rules/weekly_rule.rb b/lib/ice_cube/rules/weekly_rule.rb index 6c382d10..4b78733c 100644 --- a/lib/ice_cube/rules/weekly_rule.rb +++ b/lib/ice_cube/rules/weekly_rule.rb @@ -36,12 +36,15 @@ def realign(step_time, start_time) offset = wday_offset(step_time, start_time) time.add(:day, offset) realigned_time = time.to_time - # when the realigned time is in a different hour, we need to adjust the - # time to the correct hour with a fixed timezone offset, otherwise - # the time will be off by an hour - # WARNING: if the next DST change is within the interval, the occurrences - # after the next DST change will be off by an hour because the timezone is fixed - realigned_time = time.to_timezoneless_time if realigned_time.hour != start_time.hour + # when the realigned time is in a different hour, it means that + # time falls to the DST switch timespan. In this case, we need to + # move the time back by one day to ensure that the hour stays the same + # WARNING: this could not work if the DST change is on a monday + # as the realigned time would be moved to the previous week. + if realigned_time.hour != start_time.hour + time.add(:day, -1) + realigned_time = time.to_time + end super step_time, realigned_time end diff --git a/lib/ice_cube/time_util.rb b/lib/ice_cube/time_util.rb index 5db12ab3..001d927d 100644 --- a/lib/ice_cube/time_util.rb +++ b/lib/ice_cube/time_util.rb @@ -282,22 +282,6 @@ def to_time TimeUtil.build_in_zone(parts, @base) end - # This is used keep the correct hour within the interval during DST - # changes. It will use the time from the schedule start time to lock the - # hour. - def to_timezoneless_time - unwrapped_time = to_time - Time.new( - unwrapped_time.year, - unwrapped_time.month, - unwrapped_time.day, - @time.hour, - @time.min, - @time.sec, - unwrapped_time.utc_offset - ) - end - # DST-safely add an interval of time to the wrapped time def add(type, val) type = :day if type == :wday diff --git a/spec/examples/schedule_spec.rb b/spec/examples/schedule_spec.rb index ccc20d56..5b00e994 100644 --- a/spec/examples/schedule_spec.rb +++ b/spec/examples/schedule_spec.rb @@ -391,18 +391,17 @@ Time.utc(2014, 1, 2, 0o1, 34, 56)] end - context "Cairo timezone", system_time_zone: 'Africa/Cairo' do + context "Cairo timezone" do require "active_support/time" let(:schedule) do - IceCube::Schedule.from_yaml("---\n:start_time:\n :time: 2022-05-05 22:20:00.000000000 Z\n :zone: Africa/Cairo\n:end_time:\n :time: 2022-05-06 21:40:00.000000000 Z\n :zone: Africa/Cairo\n:rrules:\n- :validations:\n :day:\n - 5\n :rule_type: IceCube::WeeklyRule\n :interval: 1\n :week_start: 1\n:rtimes: []\n:extimes: []\n") - # IceCube::Schedule.new(ActiveSupport::TimeZone['Africa/Cairo'].parse("2022-05-05 00:20:00")).tap do |schedule| - # schedule.add_recurrence_rule IceCube::Rule.weekly.day(:friday) - # end + IceCube::Schedule.new(ActiveSupport::TimeZone['Africa/Cairo'].parse("2022-05-05 00:20:00")).tap do |schedule| + schedule.add_recurrence_rule IceCube::Rule.weekly.day(:friday) + end end it "has the correct start time" do - expect(schedule.start_time.iso8601).to eq("2022-05-06T00:20:00+02:00") + expect(schedule.start_time.iso8601).to eq("2022-05-05T00:20:00+02:00") end it "has the correct start time timezone" do @@ -412,7 +411,7 @@ it "calculates the correct occurrences from 2024-04-24" do occurrences = schedule.next_occurrences(3, Time.utc(2024, 4, 24, 12, 0, 0)) expect(occurrences.map(&:iso8601)).to eq([ - "2024-04-26T00:20:00+03:00", + "2024-04-26T01:20:00+03:00", "2024-05-03T00:20:00+03:00", "2024-05-10T00:20:00+03:00", ]) @@ -426,6 +425,15 @@ "2024-05-03T00:20:00+03:00", ]) end + + it "preserves the timezone for the next DST switch" do + occurrences = schedule.next_occurrences(28, Time.utc(2024, 4, 24, 12, 0, 0)) + expect(occurrences.map(&:iso8601).last(3)).to eq([ + "2024-10-18T00:20:00+03:00", + "2024-10-25T00:20:00+03:00", + "2024-11-01T00:20:00+02:00", + ]) + end end end diff --git a/spec/examples/weekly_rule_spec.rb b/spec/examples/weekly_rule_spec.rb index dc61bab3..259d07b8 100644 --- a/spec/examples/weekly_rule_spec.rb +++ b/spec/examples/weekly_rule_spec.rb @@ -402,7 +402,7 @@ module IceCube end it "calculates the correct time from 2024-04-24 12:00:00 UTC" do - expect(rule.next_time(utc_tz.parse("2024-04-24 12:00:00"), start_time, nil).iso8601).to eq("2024-04-26T00:20:00+03:00") + expect(rule.next_time(utc_tz.parse("2024-04-24 12:00:00"), start_time, nil).iso8601).to eq("2024-04-26T01:20:00+03:00") end it "calculates the correct time from 2024-04-26 00:20:01 Africa/Cairo" do @@ -412,7 +412,7 @@ module IceCube describe :realign do require "active_support/time" - + let(:timezone_name) { "Africa/Cairo" } let(:timezone) { ActiveSupport::TimeZone[timezone_name] } let(:utc_tz) { ActiveSupport::TimeZone["UTC"] } @@ -424,10 +424,10 @@ module IceCube subject { rule.realign(time, start_time) } it "realigns the start time to the correct time" do - expect(subject.iso8601).to eq("2024-04-26T00:20:00+03:00") + expect(subject.iso8601).to eq("2024-04-25T00:20:00+02:00") end - context "Berlin timezone" do + context "Berlin timezone CET -> CEST " do let(:recurrence_day) { :sunday } let(:timezone_name) { "Europe/Berlin" } let(:start_time) { timezone.parse("2024-03-24 02:30:00") } @@ -439,7 +439,18 @@ module IceCube # would result in faulty start times for the following # occurrences (03:30 instead of 02:30) it "realigns the start time to the correct time" do - expect(subject.iso8601).to eq("2024-03-31T02:30:00+02:00") + expect(subject.iso8601).to eq("2024-03-30T02:30:00+01:00") + end + end + + context "Berlin timezone CEST -> CET " do + let(:recurrence_day) { :sunday } + let(:timezone_name) { "Europe/Berlin" } + let(:start_time) { timezone.parse("2023-10-22 02:30:00") } + let(:time) { timezone.parse("2023-10-24 02:30:00") } + + it "realigns the start time to the correct time" do + expect(subject.iso8601).to eq("2023-10-29T02:30:00+02:00") end end end From 2c1567677fb5f6e6a8c5c065c939f7f2dc211cad Mon Sep 17 00:00:00 2001 From: Lars Kuhnt Date: Mon, 13 May 2024 11:39:45 +0200 Subject: [PATCH 7/7] lint updates --- spec/examples/fixed_value_spec.rb | 1 - spec/examples/schedule_spec.rb | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/spec/examples/fixed_value_spec.rb b/spec/examples/fixed_value_spec.rb index ebee6153..8e876f14 100644 --- a/spec/examples/fixed_value_spec.rb +++ b/spec/examples/fixed_value_spec.rb @@ -1,7 +1,6 @@ require "spec_helper" RSpec.describe IceCube::Validations::HourOfDay::Validation do - describe :validate do let(:timezone) { "Africa/Cairo" } let(:time) { "2024-05-03 00:20:00" } diff --git a/spec/examples/schedule_spec.rb b/spec/examples/schedule_spec.rb index 5b00e994..f01e4a2c 100644 --- a/spec/examples/schedule_spec.rb +++ b/spec/examples/schedule_spec.rb @@ -395,7 +395,7 @@ require "active_support/time" let(:schedule) do - IceCube::Schedule.new(ActiveSupport::TimeZone['Africa/Cairo'].parse("2022-05-05 00:20:00")).tap do |schedule| + IceCube::Schedule.new(ActiveSupport::TimeZone["Africa/Cairo"].parse("2022-05-05 00:20:00")).tap do |schedule| schedule.add_recurrence_rule IceCube::Rule.weekly.day(:friday) end end @@ -413,7 +413,7 @@ expect(occurrences.map(&:iso8601)).to eq([ "2024-04-26T01:20:00+03:00", "2024-05-03T00:20:00+03:00", - "2024-05-10T00:20:00+03:00", + "2024-05-10T00:20:00+03:00" ]) end @@ -422,7 +422,7 @@ expect(occurrences.map(&:iso8601)).to eq([ "2024-04-19T00:20:00+02:00", "2024-04-26T01:20:00+03:00", - "2024-05-03T00:20:00+03:00", + "2024-05-03T00:20:00+03:00" ]) end @@ -431,7 +431,7 @@ expect(occurrences.map(&:iso8601).last(3)).to eq([ "2024-10-18T00:20:00+03:00", "2024-10-25T00:20:00+03:00", - "2024-11-01T00:20:00+02:00", + "2024-11-01T00:20:00+02:00" ]) end end