Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

weekly rule DST issue #551

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion lib/ice_cube/rules/weekly_rule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions lib/ice_cube/time_util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 17 additions & 0 deletions spec/examples/fixed_value_spec.rb
Original file line number Diff line number Diff line change
@@ -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
pacso marked this conversation as resolved.
Show resolved Hide resolved
29 changes: 29 additions & 0 deletions spec/examples/schedule_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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-26T00: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
pacso marked this conversation as resolved.
Show resolved Hide resolved
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
Expand Down
16 changes: 16 additions & 0 deletions spec/examples/time_util_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
35 changes: 35 additions & 0 deletions spec/examples/weekly_rule_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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-26T00: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") }
pacso marked this conversation as resolved.
Show resolved Hide resolved
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") }
pacso marked this conversation as resolved.
Show resolved Hide resolved

it "realigns the start time to the correct time" do
expect(subject.iso8601).to eq("2024-04-26T00:20:00+03:00")
end
end
end
end
Loading