tzinfo 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of tzinfo might be problematic. Click here for more details.

Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.yardopts +6 -0
  5. data/{CHANGES → CHANGES.md} +121 -50
  6. data/{README → README.md} +48 -34
  7. data/Rakefile +45 -22
  8. data/lib/tzinfo.rb +7 -2
  9. data/lib/tzinfo/country.rb +23 -1
  10. data/lib/tzinfo/country_index_definition.rb +6 -1
  11. data/lib/tzinfo/country_timezone.rb +9 -1
  12. data/lib/tzinfo/data_source.rb +26 -5
  13. data/lib/tzinfo/data_timezone.rb +30 -2
  14. data/lib/tzinfo/data_timezone_info.rb +26 -0
  15. data/lib/tzinfo/info_timezone.rb +3 -1
  16. data/lib/tzinfo/linked_timezone.rb +30 -1
  17. data/lib/tzinfo/offset_rationals.rb +5 -3
  18. data/lib/tzinfo/ruby_core_support.rb +2 -0
  19. data/lib/tzinfo/ruby_country_info.rb +14 -0
  20. data/lib/tzinfo/ruby_data_source.rb +5 -0
  21. data/lib/tzinfo/time_or_datetime.rb +16 -1
  22. data/lib/tzinfo/timezone.rb +107 -5
  23. data/lib/tzinfo/timezone_definition.rb +5 -1
  24. data/lib/tzinfo/timezone_index_definition.rb +7 -1
  25. data/lib/tzinfo/{timezone_offset_info.rb → timezone_offset.rb} +12 -10
  26. data/lib/tzinfo/timezone_period.rb +19 -15
  27. data/lib/tzinfo/timezone_proxy.rb +5 -1
  28. data/lib/tzinfo/timezone_transition.rb +136 -0
  29. data/lib/tzinfo/{timezone_transition_info.rb → timezone_transition_definition.rb} +21 -57
  30. data/lib/tzinfo/transition_data_timezone_info.rb +81 -8
  31. data/lib/tzinfo/zoneinfo_country_info.rb +7 -0
  32. data/lib/tzinfo/zoneinfo_data_source.rb +104 -57
  33. data/lib/tzinfo/zoneinfo_timezone_info.rb +18 -10
  34. data/test/tc_country.rb +39 -1
  35. data/test/tc_data_timezone.rb +28 -5
  36. data/test/tc_linked_timezone.rb +24 -3
  37. data/test/tc_ruby_data_source.rb +22 -2
  38. data/test/tc_time_or_datetime.rb +3 -3
  39. data/test/tc_timezone.rb +364 -117
  40. data/test/tc_timezone_london.rb +25 -0
  41. data/test/tc_timezone_melbourne.rb +24 -0
  42. data/test/tc_timezone_new_york.rb +24 -0
  43. data/test/{tc_timezone_offset_info.rb → tc_timezone_offset.rb} +27 -27
  44. data/test/tc_timezone_period.rb +113 -90
  45. data/test/tc_timezone_transition.rb +374 -0
  46. data/test/tc_timezone_transition_definition.rb +306 -0
  47. data/test/tc_transition_data_timezone_info.rb +143 -43
  48. data/test/tc_zoneinfo_data_source.rb +69 -5
  49. data/test/tc_zoneinfo_timezone_info.rb +63 -20
  50. data/test/test_utils.rb +27 -7
  51. data/tzinfo.gemspec +21 -0
  52. metadata +61 -38
  53. metadata.gz.sig +3 -0
  54. data/test/tc_timezone_transition_info.rb +0 -471
  55. data/test/zoneinfo/UTC +0 -0
  56. data/test/zoneinfo/localtime +0 -0
@@ -123,19 +123,19 @@ class TCTransitionDataTimezoneInfo < Test::Unit::TestCase
123
123
  dti.transition 2003, 2, :o2, Time.utc(2003, 2,1,1,0,0).to_i
124
124
  dti.transition 2003, 3, :o3, Time.utc(2003, 3,1,1,0,0).to_i
125
125
 
126
- o1 = TimezoneOffsetInfo.new(-17900, 0, :TESTLMT)
127
- o2 = TimezoneOffsetInfo.new(-18000, 3600, :TESTD)
128
- o3 = TimezoneOffsetInfo.new(-18000, 0, :TESTS)
129
- o4 = TimezoneOffsetInfo.new(-21600, 3600, :TESTD)
130
-
131
- t1 = TimezoneTransitionInfo.new(o2, o1, Time.utc(2000, 4,1,1,0,0).to_i)
132
- t2 = TimezoneTransitionInfo.new(o3, o2, Time.utc(2000,10,1,1,0,0).to_i)
133
- t3 = TimezoneTransitionInfo.new(o2, o3, Time.utc(2001, 3,1,1,0,0).to_i)
134
- t4 = TimezoneTransitionInfo.new(o4, o2, Time.utc(2001, 4,1,1,0,0).to_i)
135
- t5 = TimezoneTransitionInfo.new(o3, o4, Time.utc(2001,10,1,1,0,0).to_i)
136
- t6 = TimezoneTransitionInfo.new(o3, o3, Time.utc(2002,10,1,1,0,0).to_i)
137
- t7 = TimezoneTransitionInfo.new(o2, o3, Time.utc(2003, 2,1,1,0,0).to_i)
138
- t8 = TimezoneTransitionInfo.new(o3, o2, Time.utc(2003, 3,1,1,0,0).to_i)
126
+ o1 = TimezoneOffset.new(-17900, 0, :TESTLMT)
127
+ o2 = TimezoneOffset.new(-18000, 3600, :TESTD)
128
+ o3 = TimezoneOffset.new(-18000, 0, :TESTS)
129
+ o4 = TimezoneOffset.new(-21600, 3600, :TESTD)
130
+
131
+ t1 = TimezoneTransitionDefinition.new(o2, o1, Time.utc(2000, 4,1,1,0,0).to_i)
132
+ t2 = TimezoneTransitionDefinition.new(o3, o2, Time.utc(2000,10,1,1,0,0).to_i)
133
+ t3 = TimezoneTransitionDefinition.new(o2, o3, Time.utc(2001, 3,1,1,0,0).to_i)
134
+ t4 = TimezoneTransitionDefinition.new(o4, o2, Time.utc(2001, 4,1,1,0,0).to_i)
135
+ t5 = TimezoneTransitionDefinition.new(o3, o4, Time.utc(2001,10,1,1,0,0).to_i)
136
+ t6 = TimezoneTransitionDefinition.new(o3, o3, Time.utc(2002,10,1,1,0,0).to_i)
137
+ t7 = TimezoneTransitionDefinition.new(o2, o3, Time.utc(2003, 2,1,1,0,0).to_i)
138
+ t8 = TimezoneTransitionDefinition.new(o3, o2, Time.utc(2003, 3,1,1,0,0).to_i)
139
139
 
140
140
  assert_equal(TimezonePeriod.new(nil, t1), dti.period_for_utc(DateTime.new(1960, 1,1,1, 0, 0)))
141
141
  assert_equal(TimezonePeriod.new(nil, t1), dti.period_for_utc(DateTime.new(1999,12,1,0, 0, 0)))
@@ -165,7 +165,7 @@ class TCTransitionDataTimezoneInfo < Test::Unit::TestCase
165
165
  dti.offset :o1, -17900, 0, :TESTLMT
166
166
  dti.offset :o2, -18000, 0, :TEST
167
167
 
168
- o1 = TimezoneOffsetInfo.new(-17900, 0, :TESTLMT)
168
+ o1 = TimezoneOffset.new(-17900, 0, :TESTLMT)
169
169
 
170
170
  assert_equal(TimezonePeriod.new(nil, nil, o1), dti.period_for_utc(DateTime.new(2005,1,1,0,0,0)))
171
171
  assert_equal(TimezonePeriod.new(nil, nil, o1), dti.period_for_utc(Time.utc(2005,1,1,0,0,0)))
@@ -195,18 +195,18 @@ class TCTransitionDataTimezoneInfo < Test::Unit::TestCase
195
195
  dti.transition 2002, 10, :o3, 58861189, 24 # 2002,10,2,1,0,0
196
196
  dti.transition 2003, 2, :o2, Time.utc(2003, 2,2,1,0,0).to_i
197
197
 
198
- o1 = TimezoneOffsetInfo.new(-17900, 0, :TESTLMT)
199
- o2 = TimezoneOffsetInfo.new(-18000, 3600, :TESTD)
200
- o3 = TimezoneOffsetInfo.new(-18000, 0, :TESTS)
201
- o4 = TimezoneOffsetInfo.new(-21600, 3600, :TESTD)
198
+ o1 = TimezoneOffset.new(-17900, 0, :TESTLMT)
199
+ o2 = TimezoneOffset.new(-18000, 3600, :TESTD)
200
+ o3 = TimezoneOffset.new(-18000, 0, :TESTS)
201
+ o4 = TimezoneOffset.new(-21600, 3600, :TESTD)
202
202
 
203
- t1 = TimezoneTransitionInfo.new(o2, o1, Time.utc(2000, 4,2,1,0,0).to_i)
204
- t2 = TimezoneTransitionInfo.new(o3, o2, Time.utc(2000,10,2,1,0,0).to_i)
205
- t3 = TimezoneTransitionInfo.new(o2, o3, Time.utc(2001, 3,2,1,0,0).to_i)
206
- t4 = TimezoneTransitionInfo.new(o4, o2, Time.utc(2001, 4,2,1,0,0).to_i)
207
- t5 = TimezoneTransitionInfo.new(o3, o4, Time.utc(2001,10,2,1,0,0).to_i)
208
- t6 = TimezoneTransitionInfo.new(o3, o3, Time.utc(2002,10,2,1,0,0).to_i)
209
- t7 = TimezoneTransitionInfo.new(o2, o3, Time.utc(2003, 2,2,1,0,0).to_i)
203
+ t1 = TimezoneTransitionDefinition.new(o2, o1, Time.utc(2000, 4,2,1,0,0).to_i)
204
+ t2 = TimezoneTransitionDefinition.new(o3, o2, Time.utc(2000,10,2,1,0,0).to_i)
205
+ t3 = TimezoneTransitionDefinition.new(o2, o3, Time.utc(2001, 3,2,1,0,0).to_i)
206
+ t4 = TimezoneTransitionDefinition.new(o4, o2, Time.utc(2001, 4,2,1,0,0).to_i)
207
+ t5 = TimezoneTransitionDefinition.new(o3, o4, Time.utc(2001,10,2,1,0,0).to_i)
208
+ t6 = TimezoneTransitionDefinition.new(o3, o3, Time.utc(2002,10,2,1,0,0).to_i)
209
+ t7 = TimezoneTransitionDefinition.new(o2, o3, Time.utc(2003, 2,2,1,0,0).to_i)
210
210
 
211
211
 
212
212
  assert_equal([TimezonePeriod.new(nil, t1)], dti.periods_for_local(DateTime.new(1960, 1, 1, 1, 0, 0)))
@@ -257,14 +257,14 @@ class TCTransitionDataTimezoneInfo < Test::Unit::TestCase
257
257
  dti.transition 1915, 8, :o3, 290485733, 120 # 1915, 8, 4,22,36,0
258
258
  dti.transition 1916, 4, :o4, 29051813, 12 # 1916, 4,30,22, 0,0
259
259
 
260
- o1 = TimezoneOffsetInfo.new(5040, 0, :LMT)
261
- o2 = TimezoneOffsetInfo.new(5040, 0, :WMT)
262
- o3 = TimezoneOffsetInfo.new(3600, 0, :CET)
263
- o4 = TimezoneOffsetInfo.new(3600, 3600, :CEST)
260
+ o1 = TimezoneOffset.new(5040, 0, :LMT)
261
+ o2 = TimezoneOffset.new(5040, 0, :WMT)
262
+ o3 = TimezoneOffset.new(3600, 0, :CET)
263
+ o4 = TimezoneOffset.new(3600, 3600, :CEST)
264
264
 
265
- t1 = TimezoneTransitionInfo.new(o2, o1, 288925853, 120)
266
- t2 = TimezoneTransitionInfo.new(o3, o2, 290485733, 120)
267
- t3 = TimezoneTransitionInfo.new(o4, o3, 29051813, 12)
265
+ t1 = TimezoneTransitionDefinition.new(o2, o1, 288925853, 120)
266
+ t2 = TimezoneTransitionDefinition.new(o3, o2, 290485733, 120)
267
+ t3 = TimezoneTransitionDefinition.new(o4, o3, 29051813, 12)
268
268
 
269
269
  assert_equal([TimezonePeriod.new(t1, t2),
270
270
  TimezonePeriod.new(t2, t3)], dti.periods_for_local(DateTime.new(1915,8,4,23,40,0)))
@@ -277,10 +277,10 @@ class TCTransitionDataTimezoneInfo < Test::Unit::TestCase
277
277
 
278
278
  dti.transition 2000, 7, :o2, Time.utc(2000,7,1,0,0,0).to_i
279
279
 
280
- o1 = TimezoneOffsetInfo.new(-3600, 0, :TESTD)
281
- o2 = TimezoneOffsetInfo.new(-3600, 0, :TESTS)
280
+ o1 = TimezoneOffset.new(-3600, 0, :TESTD)
281
+ o2 = TimezoneOffset.new(-3600, 0, :TESTS)
282
282
 
283
- t1 = TimezoneTransitionInfo.new(o2, o1, Time.utc(2000,7,1,0,0,0).to_i)
283
+ t1 = TimezoneTransitionDefinition.new(o2, o1, Time.utc(2000,7,1,0,0,0).to_i)
284
284
 
285
285
  # 2000-07-01 00:00:00 UTC is 2000-06-30 23:00:00 UTC-1
286
286
  # hence to find periods for local times between 2000-06-30 23:00:00
@@ -297,7 +297,7 @@ class TCTransitionDataTimezoneInfo < Test::Unit::TestCase
297
297
  dti.offset :o1, -17900, 0, :TESTLMT
298
298
  dti.offset :o2, -18000, 0, :TEST
299
299
 
300
- o1 = TimezoneOffsetInfo.new(-17900, 0, :TESTLMT)
300
+ o1 = TimezoneOffset.new(-17900, 0, :TESTLMT)
301
301
 
302
302
  assert_equal([TimezonePeriod.new(nil, nil, o1)], dti.periods_for_local(DateTime.new(2005,1,1,0,0,0)))
303
303
  assert_equal([TimezonePeriod.new(nil, nil, o1)], dti.periods_for_local(Time.utc(2005,1,1,0,0,0)))
@@ -312,6 +312,106 @@ class TCTransitionDataTimezoneInfo < Test::Unit::TestCase
312
312
  assert_raises(NoOffsetsDefined) { dti.periods_for_local(Time.utc(2005,1,1,0,0,0).to_i) }
313
313
  end
314
314
 
315
+ def test_transitions_up_to
316
+ dti = TransitionDataTimezoneInfo.new('Test/Zone')
317
+ dti.offset :o1, -17900, 0, :TESTLMT
318
+ dti.offset :o2, -18000, 3600, :TESTD
319
+ dti.offset :o3, -18000, 0, :TESTS
320
+ dti.offset :o4, -21600, 3600, :TESTD
321
+
322
+ dti.transition 2010, 4, :o2, Time.utc(2010, 4,1,1,0,0).to_i
323
+ dti.transition 2010, 10, :o3, Time.utc(2010,10,1,1,0,0).to_i
324
+ dti.transition 2011, 3, :o2, 58934917, 24 # (2011, 3,1,1,0,0)
325
+ dti.transition 2011, 4, :o4, Time.utc(2011, 4,1,1,0,0).to_i, 58935661, 24
326
+ dti.transition 2011, 10, :o3, Time.utc(2011,10,1,1,0,0).to_i
327
+
328
+ o1 = TimezoneOffset.new(-17900, 0, :TESTLMT)
329
+ o2 = TimezoneOffset.new(-18000, 3600, :TESTD)
330
+ o3 = TimezoneOffset.new(-18000, 0, :TESTS)
331
+ o4 = TimezoneOffset.new(-21600, 3600, :TESTD)
332
+
333
+ t1 = TimezoneTransitionDefinition.new(o2, o1, Time.utc(2010, 4,1,1,0,0).to_i)
334
+ t2 = TimezoneTransitionDefinition.new(o3, o2, Time.utc(2010,10,1,1,0,0).to_i)
335
+ t3 = TimezoneTransitionDefinition.new(o2, o3, Time.utc(2011, 3,1,1,0,0).to_i)
336
+ t4 = TimezoneTransitionDefinition.new(o4, o2, Time.utc(2011, 4,1,1,0,0).to_i)
337
+ t5 = TimezoneTransitionDefinition.new(o3, o4, Time.utc(2011,10,1,1,0,0).to_i)
338
+
339
+ assert_equal([], dti.transitions_up_to(Time.utc(2010,4,1,1,0,0)))
340
+ assert_equal([], dti.transitions_up_to(Time.utc(2010,4,1,1,0,0), Time.utc(2000,1,1,0,0,0)))
341
+ assert_equal([t1], dti.transitions_up_to(Time.utc(2010,4,1,1,0,1)))
342
+ assert_equal([t1], dti.transitions_up_to(Time.utc(2010,4,1,1,0,1), Time.utc(2000,1,1,0,0,0)))
343
+ assert_equal([t2,t3,t4], dti.transitions_up_to(Time.utc(2011,4,1,1,0,1), Time.utc(2010,10,1,1,0,0)))
344
+ assert_equal([t2,t3,t4], dti.transitions_up_to(Time.utc(2011,10,1,1,0,0), Time.utc(2010,4,1,1,0,1)))
345
+ assert_equal([t3], dti.transitions_up_to(Time.utc(2011,4,1,1,0,0), Time.utc(2010,10,1,1,0,1)))
346
+ assert_equal([], dti.transitions_up_to(Time.utc(2011,3,1,1,0,0), Time.utc(2010,10,1,1,0,1)))
347
+ assert_equal([t1,t2,t3,t4], dti.transitions_up_to(Time.utc(2011,10,1,1,0,0)))
348
+ assert_equal([t1,t2,t3,t4,t5], dti.transitions_up_to(Time.utc(2011,10,1,1,0,1)))
349
+ assert_equal([t1,t2,t3,t4,t5], dti.transitions_up_to(Time.utc(2011,10,1,1,0,0,1)))
350
+ assert_equal([t1,t2,t3,t4,t5], dti.transitions_up_to(Time.utc(2011,10,1,1,0,1), Time.utc(2010,4,1,1,0,0)))
351
+ assert_equal([t2,t3,t4,t5], dti.transitions_up_to(Time.utc(2011,10,1,1,0,1), Time.utc(2010,4,1,1,0,1)))
352
+ assert_equal([t2,t3,t4,t5], dti.transitions_up_to(Time.utc(2011,10,1,1,0,1), Time.utc(2010,4,1,1,0,0,1)))
353
+ assert_equal([t5], dti.transitions_up_to(Time.utc(2015,1,1,0,0,0), Time.utc(2011,10,1,1,0,0)))
354
+ assert_equal([], dti.transitions_up_to(Time.utc(2015,1,1,0,0,0), Time.utc(2011,10,1,1,0,1)))
355
+
356
+ assert_equal([], dti.transitions_up_to(Time.utc(2010,4,1,1,0,0).to_i))
357
+ assert_equal([], dti.transitions_up_to(Time.utc(2010,4,1,1,0,0).to_i, Time.utc(2000,1,1,0,0,0).to_i))
358
+ assert_equal([t1], dti.transitions_up_to(Time.utc(2010,4,1,1,0,1).to_i))
359
+ assert_equal([t1], dti.transitions_up_to(Time.utc(2010,4,1,1,0,1).to_i, Time.utc(2000,1,1,0,0,0).to_i))
360
+ assert_equal([t2,t3,t4], dti.transitions_up_to(Time.utc(2011,4,1,1,0,1).to_i, Time.utc(2010,10,1,1,0,0).to_i))
361
+ assert_equal([t2,t3,t4], dti.transitions_up_to(Time.utc(2011,10,1,1,0,0).to_i, Time.utc(2010,4,1,1,0,1).to_i))
362
+ assert_equal([t3], dti.transitions_up_to(Time.utc(2011,4,1,1,0,0).to_i, Time.utc(2010,10,1,1,0,1).to_i))
363
+ assert_equal([], dti.transitions_up_to(Time.utc(2011,3,1,1,0,0).to_i, Time.utc(2010,10,1,1,0,1).to_i))
364
+ assert_equal([t1,t2,t3,t4], dti.transitions_up_to(Time.utc(2011,10,1,1,0,0).to_i))
365
+ assert_equal([t1,t2,t3,t4,t5], dti.transitions_up_to(Time.utc(2011,10,1,1,0,1).to_i))
366
+ assert_equal([t1,t2,t3,t4,t5], dti.transitions_up_to(Time.utc(2011,10,1,1,0,1).to_i, Time.utc(2010,4,1,1,0,0).to_i))
367
+ assert_equal([t2,t3,t4,t5], dti.transitions_up_to(Time.utc(2011,10,1,1,0,1).to_i, Time.utc(2010,4,1,1,0,1).to_i))
368
+ assert_equal([t5], dti.transitions_up_to(Time.utc(2015,1,1,0,0,0).to_i, Time.utc(2011,10,1,1,0,0).to_i))
369
+ assert_equal([], dti.transitions_up_to(Time.utc(2015,1,1,0,0,0).to_i, Time.utc(2011,10,1,1,0,1).to_i))
370
+
371
+ assert_equal([], dti.transitions_up_to(DateTime.new(2010,4,1,1,0,0)))
372
+ assert_equal([], dti.transitions_up_to(DateTime.new(2010,4,1,1,0,0), DateTime.new(2000,1,1,0,0,0)))
373
+ assert_equal([t1], dti.transitions_up_to(DateTime.new(2010,4,1,1,0,1)))
374
+ assert_equal([t1], dti.transitions_up_to(DateTime.new(2010,4,1,1,0,1), DateTime.new(2000,1,1,0,0,0)))
375
+ assert_equal([t2,t3,t4], dti.transitions_up_to(DateTime.new(2011,4,1,1,0,1), DateTime.new(2010,10,1,1,0,0)))
376
+ assert_equal([t2,t3,t4], dti.transitions_up_to(DateTime.new(2011,10,1,1,0,0), DateTime.new(2010,4,1,1,0,1)))
377
+ assert_equal([t3], dti.transitions_up_to(DateTime.new(2011,4,1,1,0,0), DateTime.new(2010,10,1,1,0,1)))
378
+ assert_equal([], dti.transitions_up_to(DateTime.new(2011,3,1,1,0,0), DateTime.new(2010,10,1,1,0,1)))
379
+ assert_equal([t1,t2,t3,t4], dti.transitions_up_to(DateTime.new(2011,10,1,1,0,0)))
380
+ assert_equal([t1,t2,t3,t4,t5], dti.transitions_up_to(DateTime.new(2011,10,1,1,0,1)))
381
+ assert_equal([t1,t2,t3,t4,t5], dti.transitions_up_to(DateTime.new(2011,10,1,1,0,Rational(1,1000000))))
382
+ assert_equal([t1,t2,t3,t4,t5], dti.transitions_up_to(DateTime.new(2011,10,1,1,0,1), DateTime.new(2010,4,1,1,0,0)))
383
+ assert_equal([t2,t3,t4,t5], dti.transitions_up_to(DateTime.new(2011,10,1,1,0,1), DateTime.new(2010,4,1,1,0,1)))
384
+ assert_equal([t2,t3,t4,t5], dti.transitions_up_to(DateTime.new(2011,10,1,1,0,1), DateTime.new(2010,4,1,1,0,Rational(1,1000000))))
385
+ assert_equal([t5], dti.transitions_up_to(DateTime.new(2015,1,1,0,0,0), DateTime.new(2011,10,1,1,0,0)))
386
+ assert_equal([], dti.transitions_up_to(DateTime.new(2015,1,1,0,0,0), DateTime.new(2011,10,1,1,0,1)))
387
+ end
388
+
389
+ def test_transitions_up_to_no_transitions
390
+ dti = TransitionDataTimezoneInfo.new('Test/Zone')
391
+ dti.offset :o1, -17900, 0, :TESTLMT
392
+
393
+ assert_equal([], dti.transitions_up_to(Time.utc(2015,1,1,0,0,0)))
394
+ assert_equal([], dti.transitions_up_to(Time.utc(2015,1,1,0,0,0).to_i))
395
+ assert_equal([], dti.transitions_up_to(DateTime.new(2015,1,1,0,0,0)))
396
+ end
397
+
398
+ def test_transitions_up_to_utc_to_not_greater_than_utc_from
399
+ dti = TransitionDataTimezoneInfo.new('Test/Zone')
400
+ dti.offset :o1, -17900, 0, :TESTLMT
401
+
402
+ assert_raises(ArgumentError) do
403
+ dti.transitions_up_to(Time.utc(2012,8,1,0,0,0), Time.utc(2013,8,1,0,0,0))
404
+ end
405
+
406
+ assert_raises(ArgumentError) do
407
+ dti.transitions_up_to(Time.utc(2012,8,1,0,0,0).to_i, Time.utc(2012,8,1,0,0,0).to_i)
408
+ end
409
+
410
+ assert_raises(ArgumentError) do
411
+ dti.transitions_up_to(DateTime.new(2012,8,1,0,0,0), DateTime.new(2012,8,1,0,0,0))
412
+ end
413
+ end
414
+
315
415
  def test_datetime_and_timestamp_use
316
416
  dti = TransitionDataTimezoneInfo.new('Test/Zone')
317
417
  dti.offset :o1, 0, 0, :TESTS
@@ -323,23 +423,23 @@ class TCTransitionDataTimezoneInfo < Test::Unit::TestCase
323
423
  dti.transition 2038, 1, :o1, 2147483648, 3328347557, 1350
324
424
 
325
425
  if RubyCoreSupport.time_supports_negative && RubyCoreSupport.time_supports_64bit
326
- assert(dti.period_for_utc(DateTime.new(1901,12,13,20,45,51)).send(:start_transition).at.eql?(TimeOrDateTime.new(-2147483649)))
426
+ assert(dti.period_for_utc(DateTime.new(1901,12,13,20,45,51)).start_transition.at.eql?(TimeOrDateTime.new(-2147483649)))
327
427
  else
328
- assert(dti.period_for_utc(DateTime.new(1901,12,13,20,45,51)).send(:start_transition).at.eql?(TimeOrDateTime.new(DateTime.new(1901,12,13,20,45,51))))
428
+ assert(dti.period_for_utc(DateTime.new(1901,12,13,20,45,51)).start_transition.at.eql?(TimeOrDateTime.new(DateTime.new(1901,12,13,20,45,51))))
329
429
  end
330
430
 
331
431
  if RubyCoreSupport.time_supports_negative
332
- assert(dti.period_for_utc(DateTime.new(1969,12,31,23,59,59)).send(:start_transition).at.eql?(TimeOrDateTime.new(-1)))
432
+ assert(dti.period_for_utc(DateTime.new(1969,12,31,23,59,59)).start_transition.at.eql?(TimeOrDateTime.new(-1)))
333
433
  else
334
- assert(dti.period_for_utc(DateTime.new(1969,12,31,23,59,59)).send(:start_transition).at.eql?(TimeOrDateTime.new(DateTime.new(1969,12,31,23,59,59))))
434
+ assert(dti.period_for_utc(DateTime.new(1969,12,31,23,59,59)).start_transition.at.eql?(TimeOrDateTime.new(DateTime.new(1969,12,31,23,59,59))))
335
435
  end
336
436
 
337
- assert(dti.period_for_utc(DateTime.new(2001,9,9,2,46,40)).send(:start_transition).at.eql?(TimeOrDateTime.new(1000000000)))
437
+ assert(dti.period_for_utc(DateTime.new(2001,9,9,2,46,40)).start_transition.at.eql?(TimeOrDateTime.new(1000000000)))
338
438
 
339
439
  if RubyCoreSupport.time_supports_64bit
340
- assert(dti.period_for_utc(DateTime.new(2038,1,19,3,14,8)).send(:start_transition).at.eql?(TimeOrDateTime.new(2147483648)))
440
+ assert(dti.period_for_utc(DateTime.new(2038,1,19,3,14,8)).start_transition.at.eql?(TimeOrDateTime.new(2147483648)))
341
441
  else
342
- assert(dti.period_for_utc(DateTime.new(2038,1,19,3,14,8)).send(:start_transition).at.eql?(TimeOrDateTime.new(DateTime.new(2038,1,19,3,14,8))))
442
+ assert(dti.period_for_utc(DateTime.new(2038,1,19,3,14,8)).start_transition.at.eql?(TimeOrDateTime.new(DateTime.new(2038,1,19,3,14,8))))
343
443
  end
344
444
  end
345
445
  end
@@ -216,6 +216,32 @@ class TCZoneinfoDataSource < Test::Unit::TestCase
216
216
  end
217
217
  end
218
218
 
219
+ def test_load_timezone_info_ignored_file
220
+ assert_raises(InvalidTimezoneIdentifier) do
221
+ @data_source.load_timezone_info('localtime')
222
+ end
223
+ end
224
+
225
+ def test_load_timezone_info_ignored_plus_version_file
226
+ # Mac OS X includes a file named +VERSION containing the tzdata version.
227
+
228
+ Dir.mktmpdir('tzinfo_test') do |dir|
229
+ FileUtils.touch(File.join(dir, 'zone.tab'))
230
+ FileUtils.touch(File.join(dir, 'iso3166.tab'))
231
+
232
+ File.open(File.join(dir, '+VERSION'), 'w') do |f|
233
+ f.binmode
234
+ f.write("2013a\n")
235
+ end
236
+
237
+ data_source = ZoneinfoDataSource.new(dir)
238
+
239
+ assert_raises(InvalidTimezoneIdentifier) do
240
+ data_source.load_timezone_info('+VERSION')
241
+ end
242
+ end
243
+ end
244
+
219
245
  def test_load_timezone_info_nil
220
246
  assert_raises(InvalidTimezoneIdentifier) do
221
247
  @data_source.load_timezone_info(nil)
@@ -416,9 +442,9 @@ class TCZoneinfoDataSource < Test::Unit::TestCase
416
442
  zone = File.join(dir, 'Zone')
417
443
 
418
444
  File.open(File.join(@data_source.zoneinfo_dir, 'EST')) do |src|
419
- # Change format to 3 (which is not a valid format).
445
+ # Change header to TZif1 (which is not a valid header).
420
446
  File.open(zone, 'wb') do |dest|
421
- dest.write('TZif3')
447
+ dest.write('TZif1')
422
448
  src.pos = 5
423
449
  FileUtils.copy_stream(src, dest)
424
450
  end
@@ -434,13 +460,23 @@ class TCZoneinfoDataSource < Test::Unit::TestCase
434
460
 
435
461
  def test_load_timezone_info_tainted
436
462
  safe_test do
437
- info = @data_source.load_timezone_info('Europe/Amsterdam'.taint)
463
+ identifier = 'Europe/Amsterdam'.taint
464
+ assert(identifier.tainted?)
465
+ info = @data_source.load_timezone_info(identifier)
438
466
  assert_equal('Europe/Amsterdam', info.identifier)
467
+ assert(identifier.tainted?)
439
468
  end
440
469
  end
441
470
 
442
- def test_load_timezone_info_tainted_zoneinfo_dir_safe_mode
471
+ def test_load_timezone_info_tainted_and_frozen
443
472
  safe_test do
473
+ info = @data_source.load_timezone_info('Europe/Amsterdam'.taint.freeze)
474
+ assert_equal('Europe/Amsterdam', info.identifier)
475
+ end
476
+ end
477
+
478
+ def test_load_timezone_info_tainted_zoneinfo_dir_safe_mode
479
+ safe_test(:unavailable => :skip) do
444
480
  assert_raises(SecurityError) do
445
481
  ZoneinfoDataSource.new(@data_source.zoneinfo_dir.dup.taint)
446
482
  end
@@ -509,6 +545,24 @@ class TCZoneinfoDataSource < Test::Unit::TestCase
509
545
  end
510
546
  end
511
547
 
548
+ def test_timezone_identifiers_ignored_plus_version_file
549
+ # Mac OS X includes a file named +VERSION containing the tzdata version.
550
+
551
+ Dir.mktmpdir('tzinfo_test') do |dir|
552
+ FileUtils.touch(File.join(dir, 'zone.tab'))
553
+ FileUtils.touch(File.join(dir, 'iso3166.tab'))
554
+ FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST'))
555
+
556
+ File.open(File.join(dir, '+VERSION'), 'w') do |f|
557
+ f.binmode
558
+ f.write("2013a\n")
559
+ end
560
+
561
+ data_source = ZoneinfoDataSource.new(dir)
562
+ assert_array_same_items(['EST'], data_source.timezone_identifiers)
563
+ end
564
+ end
565
+
512
566
  def test_load_country_info
513
567
  info = @data_source.load_country_info('GB')
514
568
  assert_equal('GB', info.code)
@@ -540,7 +594,17 @@ class TCZoneinfoDataSource < Test::Unit::TestCase
540
594
 
541
595
  def test_load_country_info_tainted
542
596
  safe_test do
543
- info = @data_source.load_country_info('NL'.taint)
597
+ code = 'NL'.taint
598
+ assert(code.tainted?)
599
+ info = @data_source.load_country_info(code)
600
+ assert_equal('NL', info.code)
601
+ assert(code.tainted?)
602
+ end
603
+ end
604
+
605
+ def test_load_country_info_tainted_and_frozen
606
+ safe_test do
607
+ info = @data_source.load_country_info('NL'.taint.freeze)
544
608
  assert_equal('NL', info.code)
545
609
  end
546
610
  end
@@ -31,6 +31,14 @@ include TZInfo
31
31
 
32
32
  class TCZoneinfoTimezoneInfo < Test::Unit::TestCase
33
33
 
34
+ begin
35
+ Time.at(-2147483649)
36
+ Time.at(2147483648)
37
+ SUPPORTS_64BIT = true
38
+ rescue RangeError
39
+ SUPPORTS_64BIT = false
40
+ end
41
+
34
42
  def assert_period(abbreviation, utc_offset, std_offset, dst, start_at, end_at, info)
35
43
  if start_at
36
44
  period = info.period_for_utc(start_at)
@@ -89,19 +97,26 @@ class TCZoneinfoTimezoneInfo < Test::Unit::TestCase
89
97
 
90
98
  # Options for testing malformed zoneinfo files.
91
99
  magic = options[:magic]
100
+ section2_magic = options[:section2_magic]
92
101
  abbrev_separator = options[:abbrev_separator] || "\0"
93
102
  abbrev_offset_base = options[:abbrev_offset_base] || 0
94
103
 
95
104
  unless magic
96
105
  if format == 1
97
106
  magic = "TZif\0"
98
- elsif format == 2
99
- magic = 'TZif2'
107
+ elsif format >= 2
108
+ magic = "TZif#{format}"
100
109
  else
101
110
  raise ArgumentError, 'Invalid format specified'
102
111
  end
103
112
  end
104
113
 
114
+ if section2_magic.kind_of?(Proc)
115
+ section2_magic = section2_magic.call(format)
116
+ else
117
+ section2_magic = magic unless section2_magic
118
+ end
119
+
105
120
  convert_times_to_i(transitions)
106
121
  convert_times_to_i(leaps)
107
122
 
@@ -155,9 +170,9 @@ class TCZoneinfoTimezoneInfo < Test::Unit::TestCase
155
170
  file.write("\0" * offsets.length * 2)
156
171
  end
157
172
 
158
- if format == 2
173
+ if format >= 2
159
174
  file.write(
160
- [magic, offsets.length, offsets.length, leaps.length,
175
+ [section2_magic, offsets.length, offsets.length, leaps.length,
161
176
  transitions.length, offsets.length, abbrevs_length].pack('a5 x15 NNNNNN'))
162
177
 
163
178
  unless transitions.empty?
@@ -198,8 +213,11 @@ class TCZoneinfoTimezoneInfo < Test::Unit::TestCase
198
213
  end
199
214
 
200
215
  def tzif_test(offsets, transitions, leaps = [], options = {}, &block)
201
- write_tzif(1, offsets, transitions, leaps, options, &block)
202
- write_tzif(2, offsets, transitions, leaps, options, &block)
216
+ min_format = options[:min_format] || 1
217
+
218
+ min_format.upto(3) do |format|
219
+ write_tzif(format, offsets, transitions, leaps, options, &block)
220
+ end
203
221
  end
204
222
 
205
223
  def test_load
@@ -307,7 +325,7 @@ class TCZoneinfoTimezoneInfo < Test::Unit::TestCase
307
325
  end
308
326
 
309
327
  def test_load_invalid_magic
310
- ['TZif3', 'tzif2', '12345'].each do |magic|
328
+ ['TZif4', 'tzif2', '12345'].each do |magic|
311
329
  offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
312
330
 
313
331
  tzif_test(offsets, [], [], :magic => magic) do |path, format|
@@ -318,6 +336,38 @@ class TCZoneinfoTimezoneInfo < Test::Unit::TestCase
318
336
  end
319
337
  end
320
338
 
339
+ # These tests can only be run if the platform supports 64-bit Times. When
340
+ # 64-bit support is unavailable, the second section will not be read, so no
341
+ # error will be raised.
342
+ if SUPPORTS_64BIT
343
+ def test_load_invalid_section2_magic
344
+ ['TZif4', 'tzif2', '12345'].each do |section2_magic|
345
+ offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
346
+
347
+ tzif_test(offsets, [], [], :min_format => 2, :section2_magic => section2_magic) do |path, format|
348
+ assert_raises(InvalidZoneinfoFile) do
349
+ ZoneinfoTimezoneInfo.new('Zone4', path)
350
+ end
351
+ end
352
+ end
353
+ end
354
+
355
+ def test_load_mismatched_section2_magic
356
+ minus_one = Proc.new {|f| f == 2 ? "TZif\0" : "TZif#{f - 1}" }
357
+ plus_one = Proc.new {|f| "TZif#{f + 1}" }
358
+
359
+ [minus_one, plus_one].each do |section2_magic|
360
+ offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
361
+
362
+ tzif_test(offsets, [], [], :min_format => 2, :section2_magic => section2_magic) do |path, format|
363
+ assert_raises(InvalidZoneinfoFile) do
364
+ ZoneinfoTimezoneInfo.new('Zone5', path)
365
+ end
366
+ end
367
+ end
368
+ end
369
+ end
370
+
321
371
  def test_load_invalid_format
322
372
  Tempfile.open('tzinfo-test-zone') do |file|
323
373
  file.write('Invalid')
@@ -399,21 +449,14 @@ class TCZoneinfoTimezoneInfo < Test::Unit::TestCase
399
449
  assert_period(:XNST, 0, 0, false, Time.utc(2000, 12, 31), nil, info)
400
450
  end
401
451
  end
402
-
452
+
403
453
  def test_load_64bit
404
454
  # Some platforms support 64-bit Times, others only 32-bit. The TZif version
405
- # 2 format contains both 32-bit and 64-bit times.
455
+ # 2 and later format contains both 32-bit and 64-bit times.
406
456
 
407
- # Where 64-bit is supported and a TZif 2 file is provided, the 64-bit times
408
- # should be used, otherwise the 32-bit information should be used.
409
-
410
- begin
411
- Time.at(-2147483649)
412
- Time.at(2147483648)
413
- supports_64bit = true
414
- rescue RangeError
415
- supports_64bit = false
416
- end
457
+ # Where 64-bit is supported and a TZif 2 or later file is provided, the
458
+ # 64-bit times should be used, otherwise the 32-bit information should be
459
+ # used.
417
460
 
418
461
  offsets = [
419
462
  {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
@@ -431,7 +474,7 @@ class TCZoneinfoTimezoneInfo < Test::Unit::TestCase
431
474
  info = ZoneinfoTimezoneInfo.new('Zone/SixtyFour', path)
432
475
  assert_equal('Zone/SixtyFour', info.identifier)
433
476
 
434
- if supports_64bit && format == 2
477
+ if SUPPORTS_64BIT && format >= 2
435
478
  assert_period(:LMT, 3542, 0, false, nil, Time.utc(1850, 1, 2), info)
436
479
  assert_period(:XST, 3600, 0, false, Time.utc(1850, 1, 2), Time.utc(2003, 4, 22), info)
437
480
  assert_period(:XDT, 3600, 3600, true, Time.utc(2003, 4, 22), Time.utc(2003, 10, 21), info)