From 8db090e9709b85601044b0efbabed403c4b2d8ba Mon Sep 17 00:00:00 2001 From: Sean Devine Date: Mon, 29 Jun 2015 10:59:20 -0400 Subject: [PATCH 1/3] Parse time zones when creating schedules from ICAL; fix DST test bug #295 --- lib/ice_cube/parsers/ical_parser.rb | 16 +++++++++++++--- spec/examples/from_ical_spec.rb | 28 ++++++++++++++++++++++++---- spec/examples/hourly_rule_spec.rb | 13 +++++++------ 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/lib/ice_cube/parsers/ical_parser.rb b/lib/ice_cube/parsers/ical_parser.rb index 6729fca8..09a44e2d 100644 --- a/lib/ice_cube/parsers/ical_parser.rb +++ b/lib/ice_cube/parsers/ical_parser.rb @@ -7,12 +7,14 @@ def self.schedule_from_ical(ical_string, options = {}) (property, tzid) = property.split(';') case property when 'DTSTART' - data[:start_time] = Time.parse(value) + data[:start_time] = _parse_in_tzid(value, tzid) when 'DTEND' - data[:end_time] = Time.parse(value) + data[:end_time] = _parse_in_tzid(value, tzid) when 'EXDATE' data[:extimes] ||= [] - data[:extimes] += value.split(',').map{|v| Time.parse(v)} + data[:extimes] += value.split(',').map do |v| + _parse_in_tzid(v, tzid) + end when 'DURATION' data[:duration] # FIXME when 'RRULE' @@ -22,6 +24,14 @@ def self.schedule_from_ical(ical_string, options = {}) Schedule.from_hash data end + def self._parse_in_tzid(value, tzid) + t = Time.parse(value) + if tzid + t = t.in_time_zone(ActiveSupport::TimeZone[tzid.split("=")[1]]) + end + t + end + def self.rule_from_ical(ical) params = { validations: { } } diff --git a/spec/examples/from_ical_spec.rb b/spec/examples/from_ical_spec.rb index 68d218ea..31064166 100644 --- a/spec/examples/from_ical_spec.rb +++ b/spec/examples/from_ical_spec.rb @@ -94,7 +94,7 @@ module IceCube end - describe Schedule, 'from_ical' do + describe Schedule, 'from_ical', system_time_zone: "America/Chicago" do ical_string = <<-ICAL.gsub(/^\s*/, '') DTSTART:20130314T201500Z @@ -102,7 +102,14 @@ module IceCube RRULE:FREQ=WEEKLY;BYDAY=TH;UNTIL=20130531T100000Z ICAL - ical_string_woth_multiple_exdates = <<-ICAL.gsub(/^\s*/, '') + ical_string_with_time_zones = <<-ICAL.gsub(/^\s*/,'') + DTSTART;TZID=America/Denver:20130731T143000 + DTEND:20130731T153000 + RRULE:FREQ=WEEKLY + EXDATE;TZID=America/Chicago:20130823T143000 + ICAL + + ical_string_with_multiple_exdates = <<-ICAL.gsub(/^\s*/, '') DTSTART;TZID=America/Denver:20130731T143000 DTEND;TZID=America/Denver:20130731T153000 RRULE:FREQ=WEEKLY;UNTIL=20140730T203000Z;BYDAY=MO,WE,FR @@ -125,6 +132,20 @@ def sorted_ical(ical) it "loads an ICAL string" do expect(IceCube::Schedule.from_ical(ical_string)).to be_a(IceCube::Schedule) end + describe "parsing time zones" do + it "sets the time zone of the start time" do + schedule = IceCube::Schedule.from_ical(ical_string_with_time_zones) + expect(schedule.start_time.time_zone).to eq ActiveSupport::TimeZone.new("America/Denver") + end + it "uses the system time if a time zone is not explicity provided" do + schedule = IceCube::Schedule.from_ical(ical_string_with_time_zones) + expect(schedule.end_time).not_to respond_to :time_zone + end + it "sets the time zone of the exception times" do + schedule = IceCube::Schedule.from_ical(ical_string_with_time_zones) + expect(schedule.exception_times[0].time_zone).to eq ActiveSupport::TimeZone.new("America/Chicago") + end + end end describe "daily frequency" do @@ -235,7 +256,6 @@ def sorted_ical(ical) describe 'monthly frequency' do it 'matches simple monthly' do start_time = Time.now - schedule = IceCube::Schedule.new(start_time) schedule.add_recurrence_rule(IceCube::Rule.monthly) @@ -359,7 +379,7 @@ def sorted_ical(ical) end it 'handles multiple EXDATE lines' do - schedule = IceCube::Schedule.from_ical ical_string_woth_multiple_exdates + schedule = IceCube::Schedule.from_ical ical_string_with_multiple_exdates schedule.exception_times.count.should == 3 end end diff --git a/spec/examples/hourly_rule_spec.rb b/spec/examples/hourly_rule_spec.rb index d0685585..77cd10be 100644 --- a/spec/examples/hourly_rule_spec.rb +++ b/spec/examples/hourly_rule_spec.rb @@ -39,13 +39,14 @@ module IceCube end it 'should not skip times in DST end hour' do - schedule = Schedule.new(t0 = Time.local(2013, 11, 3, 0, 0, 0)) + tz = ActiveSupport::TimeZone["America/Vancouver"] + schedule = Schedule.new(t0 = tz.local(2013, 11, 3, 0, 0, 0)) schedule.add_recurrence_rule Rule.hourly - schedule.first(4).should == [ - Time.local(2013, 11, 3, 0, 0, 0), # -0700 - Time.local(2013, 11, 3, 1, 0, 0) - ONE_HOUR, # -0700 - Time.local(2013, 11, 3, 1, 0, 0), # -0800 - Time.local(2013, 11, 3, 2, 0, 0), # -0800 + expect(schedule.first(4)).to eq [ + tz.local(2013, 11, 3, 0, 0, 0), # -0700 + tz.local(2013, 11, 3, 1, 0, 0), # -0700 + tz.local(2013, 11, 3, 2, 0, 0) - ONE_HOUR, # -0800 + tz.local(2013, 11, 3, 2, 0, 0), # -0800 ] end From f754169289194399d75d4189e841bb736dee81b0 Mon Sep 17 00:00:00 2001 From: John Hamelink Date: Sat, 3 Oct 2015 16:17:51 +0100 Subject: [PATCH 2/3] Add correct offset without changing time --- lib/ice_cube/parsers/ical_parser.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ice_cube/parsers/ical_parser.rb b/lib/ice_cube/parsers/ical_parser.rb index 09a44e2d..6f795131 100644 --- a/lib/ice_cube/parsers/ical_parser.rb +++ b/lib/ice_cube/parsers/ical_parser.rb @@ -25,11 +25,11 @@ def self.schedule_from_ical(ical_string, options = {}) end def self._parse_in_tzid(value, tzid) - t = Time.parse(value) + time_parser = Time if tzid - t = t.in_time_zone(ActiveSupport::TimeZone[tzid.split("=")[1]]) + time_parser = ActiveSupport::TimeZone.new(tzid.split('=')[1]) || Time end - t + time_parser.parse(value) end def self.rule_from_ical(ical) From f03e439b279650035941a596d661f864f1332673 Mon Sep 17 00:00:00 2001 From: John Hamelink Date: Sat, 3 Oct 2015 16:29:16 +0100 Subject: [PATCH 3/3] Add spec which proves hour doesn't change when timezone is set --- spec/examples/from_ical_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/examples/from_ical_spec.rb b/spec/examples/from_ical_spec.rb index 31064166..f1fec335 100644 --- a/spec/examples/from_ical_spec.rb +++ b/spec/examples/from_ical_spec.rb @@ -145,6 +145,10 @@ def sorted_ical(ical) schedule = IceCube::Schedule.from_ical(ical_string_with_time_zones) expect(schedule.exception_times[0].time_zone).to eq ActiveSupport::TimeZone.new("America/Chicago") end + it "adding the offset doesnt also change the time" do + schedule = IceCube::Schedule.from_ical(ical_string_with_time_zones) + expect(schedule.exception_times[0].hour).to eq 14 + end end end