diff options
Diffstat (limited to 'activesupport')
-rw-r--r-- | activesupport/CHANGELOG | 2 | ||||
-rw-r--r-- | activesupport/lib/active_support/time_with_zone.rb | 23 | ||||
-rw-r--r-- | activesupport/lib/active_support/values/time_zone.rb | 16 | ||||
-rw-r--r-- | activesupport/test/time_zone_test.rb | 40 |
4 files changed, 70 insertions, 11 deletions
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 90ba8b5f04..1b9a30f1b7 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Adding TimeZone#parse [Geoff Buesing] + * Adding TimeZone#at and DateTime#to_f [Geoff Buesing] * TimeWithZone responds to Ruby 1.9 weekday-named query methods [Geoff Buesing] diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index ca82c2e004..984b1e43cb 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -10,12 +10,12 @@ module ActiveSupport @period = @utc ? period : get_period_and_ensure_valid_local_time end - # Returns a Time instance that represents the time in time_zone + # Returns a Time or DateTime instance that represents the time in time_zone def time @time ||= utc_to_local end - # Returns a Time instance that represents the time in UTC + # Returns a Time or DateTime instance that represents the time in UTC def utc @utc ||= local_to_utc end @@ -222,11 +222,20 @@ module ActiveSupport private def get_period_and_ensure_valid_local_time - @time_zone.period_for_local(@time) - rescue ::TZInfo::PeriodNotFound - # time is in the "spring forward" hour gap, so we're moving the time forward one hour and trying again - @time += 1.hour - retry + # we don't want a Time.local instance enforcing its own DST rules as well, + # so transfer time values to a utc constructor if necessary + @time = transfer_time_values_to_utc_constructor(@time) unless @time.utc? + begin + @time_zone.period_for_local(@time) + rescue ::TZInfo::PeriodNotFound + # time is in the "spring forward" hour gap, so we're moving the time forward one hour and trying again + @time += 1.hour + retry + end + end + + def transfer_time_values_to_utc_constructor(time) + ::Time.utc_time(time.year, time.month, time.day, time.hour, time.min, time.sec, time.respond_to?(:usec) ? time.usec : 0) end # Replicating logic from TZInfo::Timezone#utc_to_local because we want to cache the period in an instance variable for reuse diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 391ebc644e..1d33dcbf32 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -197,6 +197,20 @@ class TimeZone utc.in_time_zone(self) end + # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from parsed string. Example: + # + # Time.zone = "Hawaii" # => "Hawaii" + # Time.zone.parse('1999-12-31 14:00:00') # => Fri, 31 Dec 1999 14:00:00 HST -10:00 + # + # If upper components are missing from the string, they are supplied from TimeZone#now: + # + # Time.zone.now # => Fri, 31 Dec 1999 14:00:00 HST -10:00 + # Time.zone.parse('22:30:00') # => Fri, 31 Dec 1999 22:30:00 HST -10:00 + def parse(str, now=now) + time = Time.parse(str, now) rescue DateTime.parse(str) + ActiveSupport::TimeWithZone.new(nil, self, time) + end + # Returns an ActiveSupport::TimeWithZone instance representing the current time # in the time zone represented by +self+. Example: # @@ -244,7 +258,7 @@ class TimeZone rescue LoadError # Tzinfo gem is not available # re-raise LoadError only when a tzinfo-dependent method is called: - %w(local at now today utc_to_local local_to_utc period_for_utc period_for_local tzinfo).each do |method| + %w(local at parse now today utc_to_local local_to_utc period_for_utc period_for_local tzinfo).each do |method| define_method(method) {|*args| raise LoadError, "TZInfo gem is required for TimeZone##{method}. `gem install tzinfo` and try again."} end end diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb index f5e4e5478a..1a97594ccf 100644 --- a/activesupport/test/time_zone_test.rb +++ b/activesupport/test/time_zone_test.rb @@ -156,6 +156,14 @@ class TimeZoneTest < Test::Unit::TestCase assert_equal TimeZone["Hawaii"], time.time_zone end + def test_local_with_old_date + silence_warnings do # silence warnings raised by tzinfo gem + time = TimeZone["Hawaii"].local(1850, 2, 5, 15, 30, 45) + assert_equal [45,30,15,5,2,1850], time.to_a[0,6] + assert_equal TimeZone["Hawaii"], time.time_zone + end + end + def test_local_enforces_spring_dst_rules zone = TimeZone['Eastern Time (US & Canada)'] twz = zone.local(2006,4,2,1,59,59) # 1 second before DST start @@ -197,13 +205,39 @@ class TimeZoneTest < Test::Unit::TestCase end def test_at_with_old_date - zone = TimeZone['UTC'] - secs = -3786825600.0 + zone = TimeZone['Eastern Time (US & Canada)'] + secs = DateTime.civil(1850).to_f twz = zone.at(secs) - assert_equal [0,0,0,1,1,1850], twz.to_a[0,6] + assert_equal [1850, 1, 1, 0], [twz.utc.year, twz.utc.mon, twz.utc.day, twz.utc.hour] assert_equal zone, twz.time_zone assert_equal secs, twz.to_f end + + def test_parse + zone = TimeZone['Eastern Time (US & Canada)'] + twz = zone.parse('1999-12-31 19:00:00') + assert_equal Time.utc(1999,12,31,19), twz.time + assert_equal Time.utc(2000), twz.utc + assert_equal zone, twz.time_zone + end + + def test_parse_with_old_date + silence_warnings do # silence warnings raised by tzinfo gem + zone = TimeZone['Eastern Time (US & Canada)'] + twz = zone.parse('1850-12-31 19:00:00') + assert_equal [0,0,19,31,12,1850], twz.to_a[0,6] + assert_equal zone, twz.time_zone + end + end + + uses_mocha 'TestParseWithIncompleteDate' do + def test_parse_with_incomplete_date + zone = TimeZone['Eastern Time (US & Canada)'] + zone.stubs(:now).returns zone.local(1999,12,31) + twz = zone.parse('19:00:00') + assert_equal Time.utc(1999,12,31,19), twz.time + end + end protected def with_env_tz(new_tz = 'US/Eastern') |