Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 9007

Show
Ignore:
Timestamp:
03/11/08 05:39:13 (6 months ago)
Author:
gbuesing
Message:

TimeZone #local and #now correctly enforce DST rules

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/activesupport/CHANGELOG

    r9006 r9007  
    11*SVN* 
     2 
     3* TimeZone #local and #now correctly enforce DST rules [Geoff Buesing] 
    24 
    35* TimeWithZone instances correctly enforce DST rules. Adding TimeZone#period_for_utc [Geoff Buesing] 
  • trunk/activesupport/lib/active_support/values/time_zone.rb

    r9006 r9007  
    175175    "(UTC#{formatted_offset}) #{name}" 
    176176  end 
    177    
    178   # Method for creating new ActiveSupport::TimeWithZone instance in time zone of self. Example: 
    179   # 
    180   #   Time.zone = "Hawaii"                      # => "Hawaii" 
    181   #   Time.zone.local(2007, 2, 1, 15, 30, 45)   # => Thu, 01 Feb 2007 15:30:45 HST -10:00 
    182   def local(*args) 
    183     Time.utc_time(*args).change_time_zone(self) 
    184   end 
    185177 
    186178  begin # the following methods depend on the tzinfo gem 
    187179    require_library_or_gem "tzinfo" unless Object.const_defined?(:TZInfo) 
     180     
     181    # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+. Example: 
     182    # 
     183    #   Time.zone = "Hawaii"                      # => "Hawaii" 
     184    #   Time.zone.local(2007, 2, 1, 15, 30, 45)   # => Thu, 01 Feb 2007 15:30:45 HST -10:00 
     185    def local(*args) 
     186      t = Time.utc_time(*args) 
     187      begin 
     188        result = local_to_utc(t) 
     189      rescue TZInfo::PeriodNotFound 
     190        t += 1.hour 
     191        retry 
     192      end 
     193      result.in_time_zone(self) 
     194    end 
    188195     
    189196    # Returns an ActiveSupport::TimeWithZone instance representing the current time 
     
    193200    #   Time.zone.now         # => Wed, 23 Jan 2008 20:24:27 HST -10:00 
    194201    def now 
    195       tzinfo.now.change_time_zone(self) 
     202      Time.now.utc.in_time_zone(self) 
    196203    end 
    197204 
     
    234241  rescue LoadError # Tzinfo gem is not available 
    235242    # re-raise LoadError only when a tzinfo-dependent method is called: 
    236     %w(now today utc_to_local local_to_utc period_for_local tzinfo).each do |method| 
     243    %w(local now today utc_to_local local_to_utc period_for_utc period_for_local tzinfo).each do |method| 
    237244      define_method(method) {|*args| raise LoadError, "TZInfo gem is required for TimeZone##{method}. `gem install tzinfo` and try again."} 
    238245    end 
  • trunk/activesupport/test/time_zone_test.rb

    r8847 r9007  
    6363    uses_mocha 'TestTimeZoneNowAndToday' do 
    6464      def test_now 
    65         TZInfo::DataTimezone.any_instance.stubs(:now).returns(Time.utc(2000)) 
    66         zone = TimeZone['Eastern Time (US & Canada)'] 
    67         assert_instance_of ActiveSupport::TimeWithZone, zone.now 
    68         assert_equal Time.utc(2000), zone.now.time 
    69         assert_equal zone, zone.now.time_zone 
     65        with_env_tz 'US/Eastern' do 
     66          Time.stubs(:now).returns(Time.local(2000)) 
     67          zone = TimeZone['Eastern Time (US & Canada)'] 
     68          assert_instance_of ActiveSupport::TimeWithZone, zone.now 
     69          assert_equal Time.utc(2000,1,1,5), zone.now.utc 
     70          assert_equal Time.utc(2000), zone.now.time 
     71          assert_equal zone, zone.now.time_zone 
     72        end 
     73      end 
     74       
     75      def test_now_enforces_spring_dst_rules 
     76        with_env_tz 'US/Eastern' do 
     77          Time.stubs(:now).returns(Time.local(2006,4,2,2)) # 2AM springs forward to 3AM 
     78          zone = TimeZone['Eastern Time (US & Canada)'] 
     79          assert_equal Time.utc(2006,4,2,3), zone.now.time 
     80          assert_equal true, zone.now.dst? 
     81        end 
     82      end 
     83       
     84      def test_now_enforces_fall_dst_rules 
     85        with_env_tz 'US/Eastern' do 
     86          Time.stubs(:now).returns(Time.local(2006,10,29,1)) # 1AM is ambiguous; could be DST or non-DST 1AM 
     87          zone = TimeZone['Eastern Time (US & Canada)'] 
     88          assert_equal Time.utc(2006,10,29,1), zone.now.time # selects DST 1AM 
     89          assert_equal true, zone.now.dst? 
     90        end 
    7091      end 
    7192     
     
    135156    assert_equal TimeZone["Hawaii"], time.time_zone 
    136157  end 
     158   
     159  def test_local_enforces_spring_dst_rules 
     160    zone = TimeZone['Eastern Time (US & Canada)'] 
     161    twz = zone.local(2006,4,2,1,59,59) # 1 second before DST start 
     162    assert_equal Time.utc(2006,4,2,1,59,59), twz.time 
     163    assert_equal Time.utc(2006,4,2,6,59,59), twz.utc 
     164    assert_equal false, twz.dst? 
     165    assert_equal 'EST', twz.zone 
     166    twz2 = zone.local(2006,4,2,2) # 2AM does not exist because at 2AM, time springs forward to 3AM 
     167    assert_equal Time.utc(2006,4,2,3), twz2.time # twz is created for 3AM 
     168    assert_equal Time.utc(2006,4,2,7), twz2.utc 
     169    assert_equal true, twz2.dst? 
     170    assert_equal 'EDT', twz2.zone 
     171    twz3 = zone.local(2006,4,2,2,30) # 2:30AM does not exist because at 2AM, time springs forward to 3AM 
     172    assert_equal Time.utc(2006,4,2,3,30), twz3.time # twz is created for 3:30AM 
     173    assert_equal Time.utc(2006,4,2,7,30), twz3.utc 
     174    assert_equal true, twz3.dst? 
     175    assert_equal 'EDT', twz3.zone 
     176  end 
     177   
     178  def test_local_enforces_fall_dst_rules 
     179    # 1AM during fall DST transition is ambiguous, it could be either DST or non-DST 1AM 
     180    # Mirroring Time.local behavior, this method selects the DST time 
     181    zone = TimeZone['Eastern Time (US & Canada)'] 
     182    twz = zone.local(2006,10,29,1) 
     183    assert_equal Time.utc(2006,10,29,1), twz.time 
     184    assert_equal Time.utc(2006,10,29,5), twz.utc 
     185    assert_equal true, twz.dst?  
     186    assert_equal 'EDT', twz.zone 
     187  end 
     188 
     189  protected 
     190    def with_env_tz(new_tz = 'US/Eastern') 
     191      old_tz, ENV['TZ'] = ENV['TZ'], new_tz 
     192      yield 
     193    ensure 
     194      old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') 
     195    end   
    137196end 
    138