time_zone_test.rb 9.2 KB
Newer Older
1
require 'abstract_unit'
2 3

class TimeZoneTest < Test::Unit::TestCase
4 5 6 7 8 9 10 11 12
  
  uses_tzinfo 'TestTimeZoneCalculations' do
    
    def test_utc_to_local
      silence_warnings do # silence warnings raised by tzinfo gem
        zone = TimeZone['Eastern Time (US & Canada)']
        assert_equal Time.utc(1999, 12, 31, 19), zone.utc_to_local(Time.utc(2000, 1)) # standard offset -0500
        assert_equal Time.utc(2000, 6, 30, 20), zone.utc_to_local(Time.utc(2000, 7)) # dst offset -0400
      end
13
    end
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
  
    def test_local_to_utc
      silence_warnings do # silence warnings raised by tzinfo gem
        zone = TimeZone['Eastern Time (US & Canada)']
        assert_equal Time.utc(2000, 1, 1, 5), zone.local_to_utc(Time.utc(2000, 1)) # standard offset -0500
        assert_equal Time.utc(2000, 7, 1, 4), zone.local_to_utc(Time.utc(2000, 7)) # dst offset -0400
      end
    end
    
    def test_period_for_local
      silence_warnings do # silence warnings raised by tzinfo gem
        zone = TimeZone['Eastern Time (US & Canada)']
        assert_instance_of TZInfo::TimezonePeriod, zone.period_for_local(Time.utc(2000))
      end
    end
    
    TimeZone::MAPPING.keys.each do |name|
      define_method("test_map_#{name.downcase.gsub(/[^a-z]/, '_')}_to_tzinfo") do
        silence_warnings do # silence warnings raised by tzinfo gem
          zone = TimeZone[name]
          assert zone.tzinfo.respond_to?(:period_for_local)
        end
      end
37
    end
38

39 40 41 42 43 44 45 46
    def test_from_integer_to_map
      assert_instance_of TimeZone, TimeZone[-28800] # PST
    end

    def test_from_duration_to_map
      assert_instance_of TimeZone, TimeZone[-480.minutes] # PST
    end

47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
    TimeZone.all.each do |zone|
      name = zone.name.downcase.gsub(/[^a-z]/, '_')
      define_method("test_from_#{name}_to_map") do
        silence_warnings do # silence warnings raised by tzinfo gem
          assert_instance_of TimeZone, TimeZone[zone.name]
        end
      end

      define_method("test_utc_offset_for_#{name}") do
        silence_warnings do # silence warnings raised by tzinfo gem
          period = zone.tzinfo.period_for_utc(Time.utc(2006,1,1,0,0,0))
          assert_equal period.utc_offset, zone.utc_offset
        end
      end
    end
62

63 64
    uses_mocha 'TestTimeZoneNowAndToday' do
      def test_now
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
        with_env_tz 'US/Eastern' do
          Time.stubs(:now).returns(Time.local(2000))
          zone = TimeZone['Eastern Time (US & Canada)']
          assert_instance_of ActiveSupport::TimeWithZone, zone.now
          assert_equal Time.utc(2000,1,1,5), zone.now.utc
          assert_equal Time.utc(2000), zone.now.time
          assert_equal zone, zone.now.time_zone
        end
      end
      
      def test_now_enforces_spring_dst_rules
        with_env_tz 'US/Eastern' do
          Time.stubs(:now).returns(Time.local(2006,4,2,2)) # 2AM springs forward to 3AM
          zone = TimeZone['Eastern Time (US & Canada)']
          assert_equal Time.utc(2006,4,2,3), zone.now.time
          assert_equal true, zone.now.dst?
        end
      end
      
      def test_now_enforces_fall_dst_rules
        with_env_tz 'US/Eastern' do
86
          Time.stubs(:now).returns(Time.at(1162098000)) # equivalent to 1AM DST
87
          zone = TimeZone['Eastern Time (US & Canada)']
88
          assert_equal Time.utc(2006,10,29,1), zone.now.time
89 90
          assert_equal true, zone.now.dst?
        end
91 92 93
      end
    
      def test_today
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
        Time.stubs(:now).returns(Time.utc(2000, 1, 1, 4, 59, 59)) # 1 sec before midnight Jan 1 EST
        assert_equal Date.new(1999, 12, 31), TimeZone['Eastern Time (US & Canada)'].today
        Time.stubs(:now).returns(Time.utc(2000, 1, 1, 5)) # midnight Jan 1 EST
        assert_equal Date.new(2000, 1, 1), TimeZone['Eastern Time (US & Canada)'].today
        Time.stubs(:now).returns(Time.utc(2000, 1, 2, 4, 59, 59)) # 1 sec before midnight Jan 2 EST
        assert_equal Date.new(2000, 1, 1), TimeZone['Eastern Time (US & Canada)'].today
        Time.stubs(:now).returns(Time.utc(2000, 1, 2, 5)) # midnight Jan 2 EST
        assert_equal Date.new(2000, 1, 2), TimeZone['Eastern Time (US & Canada)'].today
      end
    end
    
    def test_local
      silence_warnings do # silence warnings raised by tzinfo gem
        time = TimeZone["Hawaii"].local(2007, 2, 5, 15, 30, 45)
        assert_equal Time.utc(2007, 2, 5, 15, 30, 45), time.time
        assert_equal TimeZone["Hawaii"], time.time_zone
      end
    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
      assert_equal Time.utc(2006,4,2,1,59,59), twz.time
      assert_equal Time.utc(2006,4,2,6,59,59), twz.utc
      assert_equal false, twz.dst?
      assert_equal 'EST', twz.zone
      twz2 = zone.local(2006,4,2,2) # 2AM does not exist because at 2AM, time springs forward to 3AM
      assert_equal Time.utc(2006,4,2,3), twz2.time # twz is created for 3AM
      assert_equal Time.utc(2006,4,2,7), twz2.utc
      assert_equal true, twz2.dst?
      assert_equal 'EDT', twz2.zone
      twz3 = zone.local(2006,4,2,2,30) # 2:30AM does not exist because at 2AM, time springs forward to 3AM
      assert_equal Time.utc(2006,4,2,3,30), twz3.time # twz is created for 3:30AM
      assert_equal Time.utc(2006,4,2,7,30), twz3.utc
      assert_equal true, twz3.dst?
      assert_equal 'EDT', twz3.zone
    end

    def test_local_enforces_fall_dst_rules
      # 1AM during fall DST transition is ambiguous, it could be either DST or non-DST 1AM
      # Mirroring Time.local behavior, this method selects the DST time
      zone = TimeZone['Eastern Time (US & Canada)']
      twz = zone.local(2006,10,29,1)
      assert_equal Time.utc(2006,10,29,1), twz.time
      assert_equal Time.utc(2006,10,29,5), twz.utc
      assert_equal true, twz.dst? 
      assert_equal 'EDT', twz.zone
    end

    def test_at
      zone = TimeZone['Eastern Time (US & Canada)']
      secs = 946684800.0
      twz = zone.at(secs)
      assert_equal Time.utc(1999,12,31,19), twz.time
      assert_equal Time.utc(2000), twz.utc
      assert_equal zone, twz.time_zone
      assert_equal secs, twz.to_f
    end

    def test_at_with_old_date
      zone = TimeZone['Eastern Time (US & Canada)']
      secs = DateTime.civil(1850).to_f
      twz = zone.at(secs)
      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
193 194 195 196
      end
    end
  end
  
197
  def test_formatted_offset_positive
198 199 200
    zone = TimeZone['Moscow']
    assert_equal "+03:00", zone.formatted_offset
    assert_equal "+0300", zone.formatted_offset(false)
201
  end
202
  
203
  def test_formatted_offset_negative
204 205 206
    zone = TimeZone['Eastern Time (US & Canada)']
    assert_equal "-05:00", zone.formatted_offset
    assert_equal "-0500", zone.formatted_offset(false)
207
  end
208
  
209 210 211 212 213 214
  def test_formatted_offset_zero
    zone = TimeZone['London']
    assert_equal "+00:00", zone.formatted_offset
    assert_equal "UTC", zone.formatted_offset(true, 'UTC')
  end
  
215
  def test_zone_compare
216 217
    zone1 = TimeZone['Central Time (US & Canada)'] # offset -0600
    zone2 = TimeZone['Eastern Time (US & Canada)'] # offset -0500
218 219 220 221
    assert zone1 < zone2
    assert zone2 > zone1
    assert zone1 == zone1
  end
222
  
223
  def test_to_s
224
    assert_equal "(UTC+03:00) Moscow", TimeZone['Moscow'].to_s
225
  end
226
  
227 228 229 230 231 232
  def test_all_sorted
    all = TimeZone.all
    1.upto( all.length-1 ) do |i|
      assert all[i-1] < all[i]
    end
  end
233
  
234 235
  def test_index
    assert_nil TimeZone["bogus"]
236 237
    assert_instance_of TimeZone, TimeZone["Central Time (US & Canada)"]
    assert_instance_of TimeZone, TimeZone[8]
238
    assert_raises(ArgumentError) { TimeZone[false] }
239
  end
240
  
241
  def test_new
242
    assert_equal TimeZone["Central Time (US & Canada)"], TimeZone.new("Central Time (US & Canada)")
243
  end
244 245 246 247 248
  
  def test_us_zones
    assert TimeZone.us_zones.include?(TimeZone["Hawaii"])
    assert !TimeZone.us_zones.include?(TimeZone["Kuala Lumpur"])
  end 
249
  
250 251 252 253 254 255 256 257
  protected
    def with_env_tz(new_tz = 'US/Eastern')
      old_tz, ENV['TZ'] = ENV['TZ'], new_tz
      yield
    ensure
      old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
    end  
end