tzinfo 1.2.7 → 1.2.8

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 (54) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CHANGES.md +11 -0
  5. data/README.md +1 -1
  6. data/lib/tzinfo.rb +3 -0
  7. data/lib/tzinfo/annual_rules.rb +51 -0
  8. data/lib/tzinfo/posix_time_zone_parser.rb +136 -0
  9. data/lib/tzinfo/time_or_datetime.rb +11 -0
  10. data/lib/tzinfo/transition_rule.rb +325 -0
  11. data/lib/tzinfo/zoneinfo_data_source.rb +2 -1
  12. data/lib/tzinfo/zoneinfo_timezone_info.rb +255 -40
  13. data/test/tc_annual_rules.rb +95 -0
  14. data/test/tc_posix_time_zone_parser.rb +261 -0
  15. data/test/tc_time_or_datetime.rb +14 -0
  16. data/test/tc_transition_rule.rb +663 -0
  17. data/test/tc_zoneinfo_timezone_info.rb +952 -113
  18. data/test/tzinfo-data/tzinfo/data/definitions/America/Argentina/Buenos_Aires.rb +5 -5
  19. data/test/tzinfo-data/tzinfo/data/definitions/America/New_York.rb +13 -1
  20. data/test/tzinfo-data/tzinfo/data/definitions/Australia/Melbourne.rb +13 -1
  21. data/test/tzinfo-data/tzinfo/data/definitions/EST.rb +1 -1
  22. data/test/tzinfo-data/tzinfo/data/definitions/Etc/GMT__m__1.rb +2 -2
  23. data/test/tzinfo-data/tzinfo/data/definitions/Etc/GMT__p__1.rb +2 -2
  24. data/test/tzinfo-data/tzinfo/data/definitions/Etc/UTC.rb +1 -1
  25. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Amsterdam.rb +15 -3
  26. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Andorra.rb +13 -1
  27. data/test/tzinfo-data/tzinfo/data/definitions/Europe/London.rb +13 -1
  28. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Paris.rb +15 -3
  29. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Prague.rb +19 -4
  30. data/test/tzinfo-data/tzinfo/data/definitions/UTC.rb +1 -1
  31. data/test/tzinfo-data/tzinfo/data/indexes/countries.rb +197 -184
  32. data/test/tzinfo-data/tzinfo/data/indexes/timezones.rb +60 -47
  33. data/test/tzinfo-data/tzinfo/data/version.rb +9 -3
  34. data/test/zoneinfo/America/Argentina/Buenos_Aires +0 -0
  35. data/test/zoneinfo/America/New_York +0 -0
  36. data/test/zoneinfo/Australia/Melbourne +0 -0
  37. data/test/zoneinfo/EST +0 -0
  38. data/test/zoneinfo/Etc/UTC +0 -0
  39. data/test/zoneinfo/Europe/Amsterdam +0 -0
  40. data/test/zoneinfo/Europe/Andorra +0 -0
  41. data/test/zoneinfo/Europe/London +0 -0
  42. data/test/zoneinfo/Europe/Paris +0 -0
  43. data/test/zoneinfo/Europe/Prague +0 -0
  44. data/test/zoneinfo/Factory +0 -0
  45. data/test/zoneinfo/iso3166.tab +13 -14
  46. data/test/zoneinfo/leapseconds +38 -21
  47. data/test/zoneinfo/posix/Europe/London +0 -0
  48. data/test/zoneinfo/posixrules +0 -0
  49. data/test/zoneinfo/right/Europe/London +0 -0
  50. data/test/zoneinfo/zone.tab +172 -159
  51. data/test/zoneinfo/zone1970.tab +185 -170
  52. data/tzinfo.gemspec +1 -1
  53. metadata +9 -3
  54. metadata.gz.sig +0 -0
@@ -10,6 +10,15 @@ include TZInfo
10
10
  send(:using, RubyCoreSupport::UntaintExt) if RubyCoreSupport.const_defined?(:UntaintExt)
11
11
 
12
12
  class TCZoneinfoTimezoneInfo < Minitest::Test
13
+ class FakePosixTimeZoneParser
14
+ def initialize(&block)
15
+ @on_parse = block
16
+ end
17
+
18
+ def parse(tz_string)
19
+ @on_parse.call(tz_string)
20
+ end
21
+ end
13
22
 
14
23
  begin
15
24
  Time.at(-2147483649)
@@ -27,6 +36,16 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
27
36
  SUPPORTS_NEGATIVE = false
28
37
  end
29
38
 
39
+ def setup
40
+ @expect_tz_string = nil
41
+ @tz_parse_result = nil
42
+ @posix_tz_parser = FakePosixTimeZoneParser.new do |tz_string|
43
+ raise "Unexpected tz_string passed to PosixTimeZoneParser: #{tz_string}" unless tz_string == @expect_tz_string
44
+ raise InvalidPosixTimeZone, 'FakePosixTimeZoneParser Failure.' if @tz_parse_result == :fail
45
+ @tz_parse_result
46
+ end
47
+ end
48
+
30
49
  def assert_period(abbreviation, utc_offset, std_offset, dst, start_at, end_at, info)
31
50
  if start_at
32
51
  period = info.period_for_utc(start_at)
@@ -36,24 +55,24 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
36
55
  # no transitions, pick the epoch
37
56
  period = info.period_for_utc(Time.utc(1970, 1, 1))
38
57
  end
39
-
40
- assert_equal(abbreviation, period.abbreviation)
41
- assert_equal(utc_offset, period.utc_offset)
42
- assert_equal(std_offset, period.std_offset)
43
- assert_equal(dst, period.dst?)
44
-
58
+
59
+ assert_equal(abbreviation, period.abbreviation, 'abbreviation')
60
+ assert_equal(utc_offset, period.utc_offset, 'utc_offset')
61
+ assert_equal(std_offset, period.std_offset, 'std_offset')
62
+ assert_equal(dst, period.dst?, 'dst')
63
+
45
64
  if start_at
46
- refute_nil(period.utc_start_time)
47
- assert_equal(start_at, period.utc_start_time)
65
+ refute_nil(period.utc_start_time, 'utc_start_time')
66
+ assert_equal(start_at, period.utc_start_time, 'utc_start_time')
48
67
  else
49
- assert_nil(period.utc_start_time)
68
+ assert_nil(period.utc_start_time, 'utc_start_time')
50
69
  end
51
70
 
52
71
  if end_at
53
- refute_nil(period.utc_end_time)
54
- assert_equal(end_at, period.utc_end_time)
72
+ refute_nil(period.utc_end_time, 'utc_end_time')
73
+ assert_equal(end_at, period.utc_end_time, 'utc_end_time')
55
74
  else
56
- assert_nil(period.utc_end_time)
75
+ assert_nil(period.utc_end_time, 'utc_end_time')
57
76
  end
58
77
  end
59
78
 
@@ -81,13 +100,15 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
81
100
  pack_int64_network_order(values.collect {|value| value < 0 ? value + 0x10000000000000000 : value})
82
101
  end
83
102
 
84
- def write_tzif(format, offsets, transitions, leaps = [], options = {})
103
+ def write_tzif(format, offsets, transitions, tz_string, leaps, options = {})
85
104
 
86
105
  # Options for testing malformed zoneinfo files.
87
106
  magic = options[:magic]
88
107
  section2_magic = options[:section2_magic]
89
108
  abbrev_separator = options[:abbrev_separator] || "\0"
90
109
  abbrev_offset_base = options[:abbrev_offset_base] || 0
110
+ omit_tz_string_start_new_line = options[:omit_tz_string_start_new_line]
111
+ omit_tz_string_end_new_line = options[:omit_tz_string_end_new_line]
91
112
 
92
113
  unless magic
93
114
  if format == 1
@@ -191,20 +212,37 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
191
212
  end
192
213
 
193
214
  # Empty POSIX timezone string
194
- file.write("\n\n")
215
+ file.write("\n") unless omit_tz_string_start_new_line
216
+ tz_string = tz_string.encode(Encoding::UTF_8) if tz_string.respond_to?(:encode)
217
+ file.write(tz_string)
218
+ file.write("\n") unless omit_tz_string_end_new_line
195
219
  end
196
220
 
197
221
  file.flush
198
222
 
199
- yield file.path, format
223
+ yield file.path
200
224
  end
201
225
  end
202
226
 
203
- def tzif_test(offsets, transitions, leaps = [], options = {}, &block)
204
- min_format = options[:min_format] || 1
227
+ def tzif_test(offsets, transitions, options = {}, &block)
228
+ rules = options[:rules]
229
+ tz_string = options[:tz_string] || (rules ? "TEST_TZ_STRING_#{rand(1000000)}" : '')
230
+ leaps = options[:leaps] || []
231
+ min_format = options[:min_format] || (tz_string.empty? ? 1 : 2)
205
232
 
206
233
  min_format.upto(3) do |format|
207
- write_tzif(format, offsets, transitions, leaps, options, &block)
234
+ write_tzif(format, offsets, transitions, tz_string, leaps, options) do |path|
235
+ if format >= 2
236
+ @tz_parse_result = rules
237
+ @expect_tz_string = tz_string
238
+ end
239
+ begin
240
+ yield path, format
241
+ ensure
242
+ @tz_parse_result = nil
243
+ @expect_tz_string = nil
244
+ end
245
+ end
208
246
  end
209
247
  end
210
248
 
@@ -222,7 +260,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
222
260
  {:at => Time.utc(2000, 12, 31), :offset_index => 3}]
223
261
 
224
262
  tzif_test(offsets, transitions) do |path, format|
225
- info = ZoneinfoTimezoneInfo.new('Zone/One', path)
263
+ info = ZoneinfoTimezoneInfo.new('Zone/One', path, @posix_tz_parser)
226
264
  assert_equal('Zone/One', info.identifier)
227
265
 
228
266
  assert_period(:LMT, 3542, 0, false, nil, Time.utc(1971, 1, 2), info)
@@ -247,7 +285,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
247
285
  {:at => Time.utc(1992, 4, 1, 4, 30, 0), :offset_index => 3}]
248
286
 
249
287
  tzif_test(offsets, transitions) do |path, format|
250
- info = ZoneinfoTimezoneInfo.new('Zone/One', path)
288
+ info = ZoneinfoTimezoneInfo.new('Zone/One', path, @posix_tz_parser)
251
289
  assert_equal('Zone/One', info.identifier)
252
290
 
253
291
  assert_period(:LMT, -12492, 0, false, nil, Time.utc(1971, 7, 9, 3, 0, 0), info)
@@ -272,7 +310,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
272
310
  {:at => Time.utc(2000, 12, 31), :offset_index => 3}]
273
311
 
274
312
  tzif_test(offsets, transitions) do |path, format|
275
- info = ZoneinfoTimezoneInfo.new('Zone/Two', path)
313
+ info = ZoneinfoTimezoneInfo.new('Zone/Two', path, @posix_tz_parser)
276
314
  assert_equal('Zone/Two', info.identifier)
277
315
 
278
316
  assert_period(:LMT, 3542, 0, false, nil, Time.utc(1979, 1, 2), info)
@@ -283,7 +321,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
283
321
  offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
284
322
 
285
323
  tzif_test(offsets, []) do |path, format|
286
- info = ZoneinfoTimezoneInfo.new('Zone/three', path)
324
+ info = ZoneinfoTimezoneInfo.new('Zone/three', path, @posix_tz_parser)
287
325
  assert_equal('Zone/three', info.identifier)
288
326
 
289
327
  assert_period(:LT, -12094, 0, false, nil, nil, info)
@@ -296,7 +334,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
296
334
 
297
335
  tzif_test(offsets, transitions) do |path, format|
298
336
  assert_raises(InvalidZoneinfoFile) do
299
- ZoneinfoTimezoneInfo.new('Zone', path)
337
+ ZoneinfoTimezoneInfo.new('Zone', path, @posix_tz_parser)
300
338
  end
301
339
  end
302
340
  end
@@ -307,7 +345,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
307
345
 
308
346
  tzif_test(offsets, transitions) do |path, format|
309
347
  assert_raises(InvalidZoneinfoFile) do
310
- ZoneinfoTimezoneInfo.new('Zone', path)
348
+ ZoneinfoTimezoneInfo.new('Zone', path, @posix_tz_parser)
311
349
  end
312
350
  end
313
351
  end
@@ -316,9 +354,9 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
316
354
  offsets = [{:gmtoff => -0, :isdst => false, :abbrev => 'LMT'}]
317
355
  leaps = [{:at => Time.utc(1972,6,30,23,59,60), :seconds => 1}]
318
356
 
319
- tzif_test(offsets, [], leaps) do |path, format|
357
+ tzif_test(offsets, [], :leaps => leaps) do |path, format|
320
358
  assert_raises(InvalidZoneinfoFile) do
321
- ZoneinfoTimezoneInfo.new('Zone', path)
359
+ ZoneinfoTimezoneInfo.new('Zone', path, @posix_tz_parser)
322
360
  end
323
361
  end
324
362
  end
@@ -327,41 +365,36 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
327
365
  ['TZif4', 'tzif2', '12345'].each do |magic|
328
366
  offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
329
367
 
330
- tzif_test(offsets, [], [], :magic => magic) do |path, format|
368
+ tzif_test(offsets, [], :magic => magic) do |path, format|
331
369
  assert_raises(InvalidZoneinfoFile) do
332
- ZoneinfoTimezoneInfo.new('Zone2', path)
370
+ ZoneinfoTimezoneInfo.new('Zone2', path, @posix_tz_parser)
333
371
  end
334
372
  end
335
373
  end
336
374
  end
337
375
 
338
- # These tests can only be run if the platform supports 64-bit Times. When
339
- # 64-bit support is unavailable, the second section will not be read, so no
340
- # error will be raised.
341
- if SUPPORTS_64BIT
342
- def test_load_invalid_section2_magic
343
- ['TZif4', 'tzif2', '12345'].each do |section2_magic|
344
- offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
345
-
346
- tzif_test(offsets, [], [], :min_format => 2, :section2_magic => section2_magic) do |path, format|
347
- assert_raises(InvalidZoneinfoFile) do
348
- ZoneinfoTimezoneInfo.new('Zone4', path)
349
- end
376
+ def test_load_invalid_section2_magic
377
+ ['TZif4', 'tzif2', '12345'].each do |section2_magic|
378
+ offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
379
+
380
+ tzif_test(offsets, [], :min_format => 2, :section2_magic => section2_magic) do |path, format|
381
+ assert_raises(InvalidZoneinfoFile) do
382
+ ZoneinfoTimezoneInfo.new('Zone4', path, @posix_tz_parser)
350
383
  end
351
384
  end
352
385
  end
386
+ end
387
+
388
+ def test_load_mismatched_section2_magic
389
+ minus_one = Proc.new {|f| f == 2 ? "TZif\0" : "TZif#{f - 1}" }
390
+ plus_one = Proc.new {|f| "TZif#{f + 1}" }
353
391
 
354
- def test_load_mismatched_section2_magic
355
- minus_one = Proc.new {|f| f == 2 ? "TZif\0" : "TZif#{f - 1}" }
356
- plus_one = Proc.new {|f| "TZif#{f + 1}" }
357
-
358
- [minus_one, plus_one].each do |section2_magic|
359
- offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
360
-
361
- tzif_test(offsets, [], [], :min_format => 2, :section2_magic => section2_magic) do |path, format|
362
- assert_raises(InvalidZoneinfoFile) do
363
- ZoneinfoTimezoneInfo.new('Zone5', path)
364
- end
392
+ [minus_one, plus_one].each do |section2_magic|
393
+ offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
394
+
395
+ tzif_test(offsets, [], :min_format => 2, :section2_magic => section2_magic) do |path, format|
396
+ assert_raises(InvalidZoneinfoFile) do
397
+ ZoneinfoTimezoneInfo.new('Zone5', path, @posix_tz_parser)
365
398
  end
366
399
  end
367
400
  end
@@ -373,7 +406,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
373
406
  file.flush
374
407
 
375
408
  assert_raises(InvalidZoneinfoFile) do
376
- ZoneinfoTimezoneInfo.new('Zone3', file.path)
409
+ ZoneinfoTimezoneInfo.new('Zone3', file.path, @posix_tz_parser)
377
410
  end
378
411
  end
379
412
  end
@@ -386,9 +419,9 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
386
419
  transitions = [
387
420
  {:at => Time.utc(2000, 1, 1), :offset_index => 1}]
388
421
 
389
- tzif_test(offsets, transitions, [], :abbrev_separator => '^') do |path, format|
422
+ tzif_test(offsets, transitions, :abbrev_separator => '^') do |path, format|
390
423
  assert_raises(InvalidZoneinfoFile) do
391
- ZoneinfoTimezoneInfo.new('Zone', path)
424
+ ZoneinfoTimezoneInfo.new('Zone', path, @posix_tz_parser)
392
425
  end
393
426
  end
394
427
  end
@@ -401,9 +434,9 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
401
434
  transitions = [
402
435
  {:at => Time.utc(2000, 1, 1), :offset_index => 1}]
403
436
 
404
- tzif_test(offsets, transitions, [], :abbrev_offset_base => 8) do |path, format|
437
+ tzif_test(offsets, transitions, :abbrev_offset_base => 8) do |path, format|
405
438
  assert_raises(InvalidZoneinfoFile) do
406
- ZoneinfoTimezoneInfo.new('Zone', path)
439
+ ZoneinfoTimezoneInfo.new('Zone', path, @posix_tz_parser)
407
440
  end
408
441
  end
409
442
  end
@@ -428,7 +461,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
428
461
  {:at => Time.utc(2000, 12, 31), :offset_index => 3}]
429
462
 
430
463
  tzif_test(offsets, transitions) do |path, format|
431
- info = ZoneinfoTimezoneInfo.new('Zone/Negative', path)
464
+ info = ZoneinfoTimezoneInfo.new('Zone/Negative', path, @posix_tz_parser)
432
465
  assert_equal('Zone/Negative', info.identifier)
433
466
 
434
467
  if SUPPORTS_NEGATIVE
@@ -459,7 +492,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
459
492
  {:at => Time.utc(2000, 12, 31), :offset_index => 3}]
460
493
 
461
494
  tzif_test(offsets, transitions) do |path, format|
462
- info = ZoneinfoTimezoneInfo.new('Zone/Negative', path)
495
+ info = ZoneinfoTimezoneInfo.new('Zone/Negative', path, @posix_tz_parser)
463
496
  assert_equal('Zone/Negative', info.identifier)
464
497
 
465
498
  if SUPPORTS_NEGATIVE
@@ -476,13 +509,15 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
476
509
  end
477
510
 
478
511
  def test_load_64bit
479
- # Some platforms support 64-bit Times, others only 32-bit. The TZif version
480
- # 2 and later format contains both 32-bit and 64-bit times.
512
+ # The TZif version2 and later format contains both 32-bit and 64-bit
513
+ # sections. The 64-bit section is always used.
514
+ #
515
+ # Negative transitions before the supported range are moved to the start of
516
+ # the supported range.
517
+ #
518
+ # Transitions after 2**31 - 1 are discarded if 64-bit times aren't
519
+ # supported.
481
520
 
482
- # Where 64-bit is supported and a TZif 2 or later file is provided, the
483
- # 64-bit times should be used, otherwise the 32-bit information should be
484
- # used.
485
-
486
521
  offsets = [
487
522
  {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
488
523
  {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
@@ -496,27 +531,35 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
496
531
  {:at => 2240524800, :offset_index => 3}] # Time.utc(2040, 12, 31)
497
532
 
498
533
  tzif_test(offsets, transitions) do |path, format|
499
- info = ZoneinfoTimezoneInfo.new('Zone/SixtyFour', path)
534
+ info = ZoneinfoTimezoneInfo.new('Zone/SixtyFour', path, @posix_tz_parser)
500
535
  assert_equal('Zone/SixtyFour', info.identifier)
501
536
 
502
- if SUPPORTS_64BIT && format >= 2
503
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(1850, 1, 2), info)
537
+ if SUPPORTS_64BIT && SUPPORTS_NEGATIVE && format >= 2
538
+ assert_period(:LMT, 3542, 0, false, nil, Time.utc(1850, 1, 2), info)
504
539
  assert_period(:XST, 3600, 0, false, Time.utc(1850, 1, 2), Time.utc(2003, 4, 22), info)
505
540
  assert_period(:XDT, 3600, 3600, true, Time.utc(2003, 4, 22), Time.utc(2003, 10, 21), info)
506
541
  assert_period(:XST, 3600, 0, false, Time.utc(2003, 10, 21), Time.utc(2040, 12, 31), info)
507
- assert_period(:XNST, 0, 0, false, Time.utc(2040, 12, 31), nil, info)
508
- else
509
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(2003, 4, 22), info)
542
+ assert_period(:XNST, 0, 0, false, Time.utc(2040, 12, 31), nil, info)
543
+ elsif format < 2
544
+ assert_period(:LMT, 3542, 0, false, nil, Time.utc(2003, 4, 22), info)
510
545
  assert_period(:XDT, 3600, 3600, true, Time.utc(2003, 4, 22), Time.utc(2003, 10, 21), info)
511
- assert_period(:XST, 3600, 0, false, Time.utc(2003, 10, 21), nil, info)
546
+ assert_period(:XST, 3600, 0, false, Time.utc(2003, 10, 21), nil, info)
547
+ else
548
+ min_supported = SUPPORTS_NEGATIVE ? -2**31 : 0
549
+ assert_period(:LMT, 3542, 0, false, nil, Time.at(min_supported).utc, info)
550
+ assert_period(:XST, 3600, 0, false, Time.at(min_supported).utc, Time.utc(2003, 4, 22), info)
551
+ assert_period(:XDT, 3600, 3600, true, Time.utc(2003, 4, 22), Time.utc(2003, 10, 21), info)
552
+ assert_period(:XST, 3600, 0, false, Time.utc(2003, 10, 21), nil, info)
512
553
  end
513
554
  end
514
555
  end
515
556
 
516
557
  def test_load_64bit_range
517
558
  # The full range of 64 bit timestamps is not currently supported because of
518
- # the way transitions are indexed. Transitions outside the supported range
519
- # will be ignored.
559
+ # the way transitions are indexed. The last transition before the earliest
560
+ # supported time will be moved to that time if there isn't already a
561
+ # transition at that time. Transitions after the latest supported time are
562
+ # ignored.
520
563
 
521
564
  offsets = [
522
565
  {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
@@ -529,7 +572,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
529
572
  {:at => 2**63 - 1, :offset_index => 0}]
530
573
 
531
574
  tzif_test(offsets, transitions) do |path, format|
532
- info = ZoneinfoTimezoneInfo.new('Zone/SixtyFourRange', path)
575
+ info = ZoneinfoTimezoneInfo.new('Zone/SixtyFourRange', path, @posix_tz_parser)
533
576
  assert_equal('Zone/SixtyFourRange', info.identifier)
534
577
 
535
578
  if SUPPORTS_64BIT && format >= 2
@@ -540,19 +583,73 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
540
583
  #assert_period(:LMT, 3542, 0, false, Time.at(2**63 - 1).utc, nil, info)
541
584
 
542
585
  # Without full range support, the following periods will be defined:
586
+ assert_period(:LMT, 3542, 0, false, nil, Time.utc(1700, 1, 1), info)
587
+ assert_period(:XST, 3600, 0, false, Time.utc(1700, 1, 1), Time.utc(2014, 5, 27), info)
588
+ assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
589
+ elsif format < 2
543
590
  assert_period(:LMT, 3542, 0, false, nil, Time.utc(2014, 5, 27), info)
544
591
  assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
545
592
  else
593
+ min_supported = SUPPORTS_NEGATIVE ? -2**31 : 0
594
+ assert_period(:LMT, 3542, 0, false, nil, Time.at(min_supported).utc, info)
595
+ assert_period(:XST, 3600, 0, false, Time.at(min_supported).utc, Time.utc(2014, 5, 27), info)
596
+ assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
597
+ end
598
+ end
599
+ end
600
+
601
+ def test_load_64bit_range_transition_at_earliest_supported
602
+ # The full range of 64 bit timestamps is not currently supported because of
603
+ # the way transitions are indexed. The last transition before the earliest
604
+ # supported time will be moved to that time if there isn't already a
605
+ # transition at that time. Transitions after the latest supported time are
606
+ # ignored.
607
+
608
+ offsets = [
609
+ {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
610
+ {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
611
+ {:gmtoff => 3600, :isdst => false, :abbrev => 'XST2'},
612
+ {:gmtoff => 7200, :isdst => false, :abbrev => 'XNST'}]
613
+
614
+ transitions = [
615
+ {:at => -2**63, :offset_index => 1},
616
+ {:at => -8520336000, :offset_index => 2}, # Time.utc(1700, 1, 1).to_i
617
+ {:at => Time.utc(2014, 5, 27), :offset_index => 3},
618
+ {:at => 2**63 - 1, :offset_index => 0}]
619
+
620
+ tzif_test(offsets, transitions) do |path, format|
621
+ info = ZoneinfoTimezoneInfo.new('Zone/SixtyFourRange', path, @posix_tz_parser)
622
+ assert_equal('Zone/SixtyFourRange', info.identifier)
623
+
624
+ if SUPPORTS_64BIT && format >= 2
625
+ # When the full range is supported, the following periods will be defined:
626
+ #assert_period(:LMT, 3542, 0, false, nil, Time.at(-2**63).utc, info)
627
+ #assert_period(:XST, 3600, 0, false, Time.at(-2**63).utc, Time.utc(2014, 5, 27), info)
628
+ #assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), Time.at(2**63 - 1).utc, info)
629
+ #assert_period(:LMT, 3542, 0, false, Time.at(2**63 - 1).utc, nil, info)
630
+
631
+ # Without full range support, the following periods will be defined:
632
+ assert_period(:LMT, 3542, 0, false, nil, Time.utc(1700, 1, 1), info)
633
+ assert_period(:XST2, 3600, 0, false, Time.utc(1700, 1, 1), Time.utc(2014, 5, 27), info)
634
+ assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
635
+ elsif format < 2
546
636
  assert_period(:LMT, 3542, 0, false, nil, Time.utc(2014, 5, 27), info)
547
637
  assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
638
+ elsif SUPPORTS_NEGATIVE
639
+ assert_period(:LMT, 3542, 0, false, nil, Time.at(-2**31).utc, info)
640
+ assert_period(:XST, 3600, 0, false, Time.at(-2**31).utc, Time.utc(2014, 5, 27), info)
641
+ assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
642
+ else
643
+ assert_period(:LMT, 3542, 0, false, nil, Time.utc(1970, 1, 1), info)
644
+ assert_period(:XST2, 3600, 0, false, Time.utc(1970, 1, 1), Time.utc(2014, 5, 27), info)
645
+ assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
548
646
  end
549
647
  end
550
648
  end
551
649
 
552
650
  def test_load_supported_64bit_range
553
651
  # The full range of 64 bit timestamps is not currently supported because of
554
- # the way transitions are indexed. Transitions outside the supported range
555
- # will be ignored.
652
+ # the way transitions are indexed.
556
653
 
557
654
  min_timestamp = -8520336000 # Time.utc(1700, 1, 1).to_i
558
655
  max_timestamp = 16725225600 # Time.utc(2500, 1, 1).to_i
@@ -568,7 +665,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
568
665
  {:at => max_timestamp - 1, :offset_index => 0}]
569
666
 
570
667
  tzif_test(offsets, transitions) do |path, format|
571
- info = ZoneinfoTimezoneInfo.new('Zone/SupportedSixtyFourRange', path)
668
+ info = ZoneinfoTimezoneInfo.new('Zone/SupportedSixtyFourRange', path, @posix_tz_parser)
572
669
  assert_equal('Zone/SupportedSixtyFourRange', info.identifier)
573
670
 
574
671
  if SUPPORTS_64BIT && format >= 2
@@ -576,9 +673,14 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
576
673
  assert_period(:XST, 3600, 0, false, Time.at(min_timestamp).utc, Time.utc(2014, 5, 27), info)
577
674
  assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), Time.at(max_timestamp - 1).utc, info)
578
675
  assert_period(:LMT, 3542, 0, false, Time.at(max_timestamp - 1).utc, nil, info)
579
- else
676
+ elsif format < 2
580
677
  assert_period(:LMT, 3542, 0, false, nil, Time.utc(2014, 5, 27), info)
581
678
  assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
679
+ else
680
+ min_supported = SUPPORTS_NEGATIVE ? -2**31 : 0
681
+ assert_period(:LMT, 3542, 0, false, nil, Time.at(min_supported).utc, info)
682
+ assert_period(:XST, 3600, 0, false, Time.at(min_supported).utc, Time.utc(2014, 5, 27), info)
683
+ assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
582
684
  end
583
685
  end
584
686
  end
@@ -595,19 +697,14 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
595
697
  {:at => 2**31 - 1, :offset_index => 0}]
596
698
 
597
699
  tzif_test(offsets, transitions) do |path, format|
598
- info = ZoneinfoTimezoneInfo.new('Zone/ThirtyTwoRange', path)
700
+ info = ZoneinfoTimezoneInfo.new('Zone/ThirtyTwoRange', path, @posix_tz_parser)
599
701
  assert_equal('Zone/ThirtyTwoRange', info.identifier)
600
702
 
601
- if SUPPORTS_NEGATIVE
602
- assert_period(:LMT, 3542, 0, false, nil, Time.at(-2**31).utc, info)
603
- assert_period(:XST, 3600, 0, false, Time.at(-2**31).utc, Time.utc(2014, 5, 27), info)
604
- assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), Time.at(2**31 - 1).utc, info)
605
- assert_period(:LMT, 3542, 0, false, Time.at(2**31 - 1).utc, nil, info)
606
- else
607
- assert_period(:XST, 3600, 0, false, Time.utc(1970, 1, 1), Time.utc(2014, 5, 27), info)
608
- assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), Time.at(2**31 - 1).utc, info)
609
- assert_period(:LMT, 3542, 0, false, Time.at(2**31 - 1).utc, nil, info)
610
- end
703
+ min_supported = SUPPORTS_NEGATIVE ? -2**31 : 0
704
+ assert_period(:LMT, 3542, 0, false, nil, Time.at(min_supported).utc, info)
705
+ assert_period(:XST, 3600, 0, false, Time.at(min_supported).utc, Time.utc(2014, 5, 27), info)
706
+ assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), Time.at(2**31 - 1), info)
707
+ assert_period(:LMT, 3542, 0, false, Time.at(2**31 - 1).utc, nil, info)
611
708
  end
612
709
  end
613
710
 
@@ -628,7 +725,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
628
725
  {:at => Time.utc(2000, 4, 1), :offset_index => 1}]
629
726
 
630
727
  tzif_test(offsets, transitions) do |path, format|
631
- info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path)
728
+ info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path, @posix_tz_parser)
632
729
  assert_equal('Zone/DoubleDaylight', info.identifier)
633
730
 
634
731
  assert_period(:LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
@@ -645,7 +742,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
645
742
 
646
743
  offsets = [
647
744
  {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
648
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
745
+ {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
649
746
  {:gmtoff => 10800, :isdst => true, :abbrev => 'XDDT'}]
650
747
 
651
748
  transitions = [
@@ -654,7 +751,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
654
751
  {:at => Time.utc(2000, 6, 1), :offset_index => 1}]
655
752
 
656
753
  tzif_test(offsets, transitions) do |path, format|
657
- info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path)
754
+ info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path, @posix_tz_parser)
658
755
  assert_equal('Zone/DoubleDaylight', info.identifier)
659
756
 
660
757
  assert_period(:LMT, 3542, 0, false, nil, Time.utc(2000, 4, 1), info)
@@ -683,7 +780,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
683
780
  {:at => Time.utc(2000, 6, 1), :offset_index => 1}]
684
781
 
685
782
  tzif_test(offsets, transitions) do |path, format|
686
- info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path)
783
+ info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path, @posix_tz_parser)
687
784
  assert_equal('Zone/DoubleDaylight', info.identifier)
688
785
 
689
786
  assert_period(:LMT, -10821, 0, false, nil, Time.utc(2000, 1, 1), info)
@@ -712,7 +809,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
712
809
  {:at => Time.utc(2000, 3, 1), :offset_index => 1}]
713
810
 
714
811
  tzif_test(offsets, transitions) do |path, format|
715
- info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path)
812
+ info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path, @posix_tz_parser)
716
813
  assert_equal('Zone/DoubleDaylight', info.identifier)
717
814
 
718
815
  assert_period(:LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
@@ -733,7 +830,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
733
830
  transitions = [{:at => Time.utc(2000, 1, 1), :offset_index => 1}]
734
831
 
735
832
  tzif_test(offsets, transitions) do |path, format|
736
- info = ZoneinfoTimezoneInfo.new('Zone/OnlyDST', path)
833
+ info = ZoneinfoTimezoneInfo.new('Zone/OnlyDST', path, @posix_tz_parser)
737
834
  assert_equal('Zone/OnlyDST', info.identifier)
738
835
 
739
836
  assert_period(:LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
@@ -750,7 +847,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
750
847
  transitions = [{:at => Time.utc(2000, 1, 1), :offset_index => 0}]
751
848
 
752
849
  tzif_test(offsets, transitions) do |path, format|
753
- info = ZoneinfoTimezoneInfo.new('Zone/OnlyDST', path)
850
+ info = ZoneinfoTimezoneInfo.new('Zone/OnlyDST', path, @posix_tz_parser)
754
851
  assert_equal('Zone/OnlyDST', info.identifier)
755
852
 
756
853
  assert_period(:XDT, 3600, 3600, true, nil, Time.utc(2000, 1, 1), info)
@@ -775,7 +872,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
775
872
  {:at => Time.utc(2000, 2, 1), :offset_index => 2}]
776
873
 
777
874
  tzif_test(offsets, transitions) do |path, format|
778
- info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path)
875
+ info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path, @posix_tz_parser)
779
876
  assert_equal('Zone/DoubleDaylight', info.identifier)
780
877
 
781
878
  assert_period(:LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
@@ -805,7 +902,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
805
902
  {:at => Time.utc(2012, 3, 31, 14, 0, 0), :offset_index => 4}]
806
903
 
807
904
  tzif_test(offsets, transitions) do |path, format|
808
- info = ZoneinfoTimezoneInfo.new('Test/Pacific/Apia', path)
905
+ info = ZoneinfoTimezoneInfo.new('Test/Pacific/Apia', path, @posix_tz_parser)
809
906
  assert_equal('Test/Pacific/Apia', info.identifier)
810
907
 
811
908
  assert_period( :LMT, 45184, 0, false, nil, Time.utc(2011, 4, 2, 14, 0, 0), info)
@@ -844,7 +941,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
844
941
  # offsets.
845
942
 
846
943
  tzif_test(offsets, transitions) do |path, format|
847
- info = ZoneinfoTimezoneInfo.new('Zone/SplitUtcOffset', path)
944
+ info = ZoneinfoTimezoneInfo.new('Zone/SplitUtcOffset', path, @posix_tz_parser)
848
945
  assert_equal('Zone/SplitUtcOffset', info.identifier)
849
946
 
850
947
  assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
@@ -886,7 +983,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
886
983
  # utc_offset of 3600 and std_offset of 7200).
887
984
 
888
985
  tzif_test(offsets, transitions) do |path, format|
889
- info = ZoneinfoTimezoneInfo.new('Zone/MinimumUtcOffset', path)
986
+ info = ZoneinfoTimezoneInfo.new('Zone/MinimumUtcOffset', path, @posix_tz_parser)
890
987
  assert_equal('Zone/MinimumUtcOffset', info.identifier)
891
988
 
892
989
  assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
@@ -915,7 +1012,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
915
1012
  # utc_offset of 3600 and std_offset of 7200).
916
1013
 
917
1014
  tzif_test(offsets, transitions) do |path, format|
918
- info = ZoneinfoTimezoneInfo.new('Zone/MinimumUtcOffset', path)
1015
+ info = ZoneinfoTimezoneInfo.new('Zone/MinimumUtcOffset', path, @posix_tz_parser)
919
1016
  assert_equal('Zone/MinimumUtcOffset', info.identifier)
920
1017
 
921
1018
  assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
@@ -944,7 +1041,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
944
1041
  # equivalent (or greater) utc_total_offset.
945
1042
 
946
1043
  tzif_test(offsets, transitions) do |path, format|
947
- info = ZoneinfoTimezoneInfo.new('Zone/UtcOffsetEqual', path)
1044
+ info = ZoneinfoTimezoneInfo.new('Zone/UtcOffsetEqual', path, @posix_tz_parser)
948
1045
  assert_equal('Zone/UtcOffsetEqual', info.identifier)
949
1046
 
950
1047
  assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
@@ -973,7 +1070,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
973
1070
  # equivalent (or greater) utc_total_offset.
974
1071
 
975
1072
  tzif_test(offsets, transitions) do |path, format|
976
- info = ZoneinfoTimezoneInfo.new('Zone/UtcOffsetEqual', path)
1073
+ info = ZoneinfoTimezoneInfo.new('Zone/UtcOffsetEqual', path, @posix_tz_parser)
977
1074
  assert_equal('Zone/UtcOffsetEqual', info.identifier)
978
1075
 
979
1076
  assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
@@ -1001,7 +1098,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
1001
1098
  # from utc_total_offset - std_offset.
1002
1099
 
1003
1100
  tzif_test(offsets, transitions) do |path, format|
1004
- info = ZoneinfoTimezoneInfo.new('Zone/AdjacentEqual', path)
1101
+ info = ZoneinfoTimezoneInfo.new('Zone/AdjacentEqual', path, @posix_tz_parser)
1005
1102
  assert_equal('Zone/AdjacentEqual', info.identifier)
1006
1103
 
1007
1104
  assert_period(:LMT, 7142, 0, false, nil, Time.utc(2000, 1, 1), info)
@@ -1032,7 +1129,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
1032
1129
  # an equivalent utc_offset of 3600 and std_offset of 7200).
1033
1130
 
1034
1131
  tzif_test(offsets, transitions) do |path, format|
1035
- info = ZoneinfoTimezoneInfo.new('Zone/UtcOffsetPreserved', path)
1132
+ info = ZoneinfoTimezoneInfo.new('Zone/UtcOffsetPreserved', path, @posix_tz_parser)
1036
1133
  assert_equal('Zone/UtcOffsetPreserved', info.identifier)
1037
1134
 
1038
1135
  assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
@@ -1064,7 +1161,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
1064
1161
  # an equivalent utc_offset of 3600 and std_offset of 7200).
1065
1162
 
1066
1163
  tzif_test(offsets, transitions) do |path, format|
1067
- info = ZoneinfoTimezoneInfo.new('Zone/UtcOffsetPreserved', path)
1164
+ info = ZoneinfoTimezoneInfo.new('Zone/UtcOffsetPreserved', path, @posix_tz_parser)
1068
1165
  assert_equal('Zone/UtcOffsetPreserved', info.identifier)
1069
1166
 
1070
1167
  assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
@@ -1092,7 +1189,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
1092
1189
  {:at => Time.utc(2000, 5, 1), :offset_index => 1}]
1093
1190
 
1094
1191
  tzif_test(offsets, transitions) do |path, format|
1095
- info = ZoneinfoTimezoneInfo.new('Zone/NegativeStdOffsetDst', path)
1192
+ info = ZoneinfoTimezoneInfo.new('Zone/NegativeStdOffsetDst', path, @posix_tz_parser)
1096
1193
  assert_equal('Zone/NegativeStdOffsetDst', info.identifier)
1097
1194
 
1098
1195
  assert_period(:LMT, -100, 0, false, nil, Time.utc(2000, 1, 1), info)
@@ -1121,7 +1218,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
1121
1218
  {:at => Time.utc(2000, 5, 1), :offset_index => 1}]
1122
1219
 
1123
1220
  tzif_test(offsets, transitions) do |path, format|
1124
- info = ZoneinfoTimezoneInfo.new('Zone/NegativeStdOffsetDstInitialDst', path)
1221
+ info = ZoneinfoTimezoneInfo.new('Zone/NegativeStdOffsetDstInitialDst', path, @posix_tz_parser)
1125
1222
  assert_equal('Zone/NegativeStdOffsetDstInitialDst', info.identifier)
1126
1223
 
1127
1224
  assert_period(:LMT, -100, 0, false, nil, Time.utc(2000, 1, 1), info)
@@ -1146,7 +1243,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
1146
1243
  {:at => Time.utc(2000, 3, 1), :offset_index => 3}]
1147
1244
 
1148
1245
  tzif_test(offsets, transitions) do |path, format|
1149
- info = ZoneinfoTimezoneInfo.new('Zone/BaseOffsetMovesToDstNotHour', path)
1246
+ info = ZoneinfoTimezoneInfo.new('Zone/BaseOffsetMovesToDstNotHour', path, @posix_tz_parser)
1150
1247
  assert_equal('Zone/BaseOffsetMovesToDstNotHour', info.identifier)
1151
1248
 
1152
1249
  assert_period(:LMT, -100, 0, false, nil, Time.utc(2000, 1, 1), info)
@@ -1169,7 +1266,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
1169
1266
  {:at => Time.utc(2000, 3, 1), :offset_index => 3}]
1170
1267
 
1171
1268
  tzif_test(offsets, transitions) do |path, format|
1172
- info = ZoneinfoTimezoneInfo.new('Zone/BaseOffsetMovesFromDstNotHour', path)
1269
+ info = ZoneinfoTimezoneInfo.new('Zone/BaseOffsetMovesFromDstNotHour', path, @posix_tz_parser)
1173
1270
  assert_equal('Zone/BaseOffsetMovesFromDstNotHour', info.identifier)
1174
1271
 
1175
1272
  assert_period(:LMT, -100, 0, false, nil, Time.utc(2000, 1, 1), info)
@@ -1187,7 +1284,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
1187
1284
  path.untaint
1188
1285
 
1189
1286
  safe_test do
1190
- info = ZoneinfoTimezoneInfo.new('Zone/three', path)
1287
+ info = ZoneinfoTimezoneInfo.new('Zone/three', path, @posix_tz_parser)
1191
1288
  assert_equal('Zone/three', info.identifier)
1192
1289
 
1193
1290
  assert_period(:LT, -12094, 0, false, nil, nil, info)
@@ -1207,7 +1304,7 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
1207
1304
  {:at => Time.utc(1971, 1, 2), :offset_index => 1}]
1208
1305
 
1209
1306
  tzif_test(offsets, transitions) do |path, format|
1210
- info = ZoneinfoTimezoneInfo.new('Zone/One', path)
1307
+ info = ZoneinfoTimezoneInfo.new('Zone/One', path, @posix_tz_parser)
1211
1308
  assert_equal('Zone/One', info.identifier)
1212
1309
 
1213
1310
  assert_period(:LMT, 3542, 0, false, nil, Time.utc(1971, 1, 2), info)
@@ -1226,11 +1323,753 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
1226
1323
  {:at => Time.utc(2011, 12, 31, 13, 24, 26), :offset_index => 1}]
1227
1324
 
1228
1325
  tzif_test(offsets, transitions) do |path, format|
1229
- info = ZoneinfoTimezoneInfo.new('Zone/One', path)
1326
+ info = ZoneinfoTimezoneInfo.new('Zone/One', path, @posix_tz_parser)
1230
1327
  assert_equal('Zone/One', info.identifier)
1231
1328
 
1232
1329
  assert_period(:LMT, 3542, 0, false, nil, Time.utc(2011, 12, 31, 13, 24, 26), info)
1233
1330
  assert_period(:XST, 3600, 0, false, Time.utc(2011, 12, 31, 13, 24, 26), nil, info)
1234
1331
  end
1235
1332
  end
1333
+
1334
+ def test_load_invalid_tz_string
1335
+ offsets = [{:gmtoff => 0, :isdst => false, :abbrev => 'UTC'}]
1336
+
1337
+ tzif_test(offsets, [], :rules => :fail) do |path, format|
1338
+ error = assert_raises(InvalidZoneinfoFile) { ZoneinfoTimezoneInfo.new('Invalid/String', path, @posix_tz_parser) }
1339
+ assert_equal("Failed to parse POSIX-style TZ string in file '#{path}': FakePosixTimeZoneParser Failure.", error.message)
1340
+ end
1341
+ end
1342
+
1343
+ def test_load_tz_string_missing_start_newline
1344
+ offsets = [{:gmtoff => 0, :isdst => false, :abbrev => 'UTC'}]
1345
+ rules = TimezoneOffset.new(0, 0, 'UTC')
1346
+
1347
+ tzif_test(offsets, [], :rules => rules, :omit_tz_string_start_new_line => true) do |path, format|
1348
+ error = assert_raises(InvalidZoneinfoFile) { ZoneinfoTimezoneInfo.new('Missing/Start', path, @posix_tz_parser) }
1349
+ assert_equal("Expected newline starting POSIX-style TZ string in file '#{path}'.", error.message)
1350
+ end
1351
+ end
1352
+
1353
+ def test_load_tz_string_missing_end_newline
1354
+ offsets = [{:gmtoff => 0, :isdst => false, :abbrev => 'UTC'}]
1355
+ rules = TimezoneOffset.new(0, 0, 'UTC')
1356
+
1357
+ tzif_test(offsets, [], :rules => rules, :omit_tz_string_end_new_line => true) do |path, format|
1358
+ error = assert_raises(InvalidZoneinfoFile) { ZoneinfoTimezoneInfo.new('Missing/End', path, @posix_tz_parser) }
1359
+ assert_equal("Expected newline ending POSIX-style TZ string in file '#{path}'.", error.message)
1360
+ end
1361
+ end
1362
+
1363
+ [
1364
+ [false, 1, 0, 'TEST'],
1365
+ [false, 0, 1, 'TEST'],
1366
+ [false, 0, 0, 'TEST2'],
1367
+ [false, -1, 1, 'TEST'],
1368
+ [true, 0, 0, 'TEST']
1369
+ ].each do |(isdst, base_utc_offset, std_offset, abbreviation)|
1370
+ define_method "test_load_tz_string_does_not_match_#{isdst ? 'dst' : 'std'}_constant_offset_#{base_utc_offset}_#{std_offset}_#{abbreviation}" do
1371
+ offsets = [{:gmtoff => 0, :isdst => isdst, :abbrev => 'TEST'}]
1372
+ rules = TimezoneOffset.new(base_utc_offset, std_offset, abbreviation)
1373
+
1374
+ tzif_test(offsets, [], :rules => rules) do |path, format|
1375
+ error = assert_raises(InvalidZoneinfoFile) { ZoneinfoTimezoneInfo.new('Offset/Mismatch', path, @posix_tz_parser) }
1376
+ assert_equal("Constant offset POSIX-style TZ string does not match constant offset in file '#{path}'.", error.message)
1377
+ end
1378
+ end
1379
+ end
1380
+
1381
+ [
1382
+ [3601, 'XST'],
1383
+ [3600, 'YST']
1384
+ ].each do |(base_utc_offset, abbreviation)|
1385
+ define_method "test_load_tz_string_does_not_match_final_std_transition_offset_#{base_utc_offset}_#{abbreviation}" do
1386
+ offsets = [
1387
+ {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
1388
+ {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
1389
+ {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'}
1390
+ ]
1391
+
1392
+ transitions = [
1393
+ {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 3542, :offset_index => 1},
1394
+ {:at => Time.utc(1981, 4, 10, 2, 0, 0) - 3600, :offset_index => 2},
1395
+ {:at => Time.utc(1981, 10, 27, 2, 0, 0) - 7200, :offset_index => 1}
1396
+ ]
1397
+
1398
+ rules = AnnualRules.new(
1399
+ TimezoneOffset.new(base_utc_offset, 0, abbreviation),
1400
+ TimezoneOffset.new(3600, 3600, 'XDT'),
1401
+ JulianDayOfYearTransitionRule.new(100, 7200),
1402
+ JulianDayOfYearTransitionRule.new(300, 7200)
1403
+ )
1404
+
1405
+ tzif_test(offsets, transitions, :rules => rules) do |path, format|
1406
+ error = assert_raises(InvalidZoneinfoFile) { ZoneinfoTimezoneInfo.new('Offset/Mismatch', path, @posix_tz_parser) }
1407
+ assert_equal("The first offset indicated by the POSIX-style TZ string did not match the final defined offset in file '#{path}'.", error.message)
1408
+ end
1409
+ end
1410
+ end
1411
+
1412
+ [
1413
+ [3601, 0, 'XST'],
1414
+ [3600, 1, 'XST'],
1415
+ [3600, 0, 'YST']
1416
+ ].each do |(base_utc_offset, std_offset, abbreviation)|
1417
+ define_method "test_load_tz_string_does_not_match_final_dst_transition_offset_#{base_utc_offset}_#{std_offset}_#{abbreviation}" do
1418
+ offsets = [
1419
+ {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
1420
+ {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
1421
+ {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'}
1422
+ ]
1423
+
1424
+ transitions = [
1425
+ {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 3542, :offset_index => 1},
1426
+ {:at => Time.utc(1981, 4, 10, 2, 0, 0) - 3600, :offset_index => 2}
1427
+ ]
1428
+
1429
+ rules = AnnualRules.new(
1430
+ TimezoneOffset.new(3600, 0, 'XST'),
1431
+ TimezoneOffset.new(base_utc_offset, std_offset, abbreviation),
1432
+ JulianDayOfYearTransitionRule.new(100, 7200),
1433
+ JulianDayOfYearTransitionRule.new(300, 7200)
1434
+ )
1435
+
1436
+ tzif_test(offsets, transitions, :rules => rules) do |path, format|
1437
+ error = assert_raises(InvalidZoneinfoFile) { ZoneinfoTimezoneInfo.new('Offset/Mismatch', path, @posix_tz_parser) }
1438
+ assert_equal("The first offset indicated by the POSIX-style TZ string did not match the final defined offset in file '#{path}'.", error.message)
1439
+ end
1440
+ end
1441
+ end
1442
+
1443
+ [
1444
+ [3600, 0],
1445
+ [3600, 3600],
1446
+ [10800, -3600]
1447
+ ].each do |(base_utc_offset, std_offset)|
1448
+ rules = TimezoneOffset.new(base_utc_offset, std_offset, 'TEST')
1449
+
1450
+ define_method "test_load_tz_string_uses_constant_offset_with_no_transitions_#{base_utc_offset}_#{std_offset}" do
1451
+ offsets = [{:gmtoff => base_utc_offset + std_offset, :isdst => std_offset != 0, :abbrev => 'TEST'}]
1452
+
1453
+ tzif_test(offsets, [], :rules => rules) do |path, format|
1454
+ info = ZoneinfoTimezoneInfo.new('Constant/Offset', path, @posix_tz_parser)
1455
+ assert_equal('Constant/Offset', info.identifier)
1456
+ assert_period(:TEST, base_utc_offset, std_offset, std_offset != 0, nil, nil, info)
1457
+ end
1458
+ end
1459
+
1460
+ define_method "test_load_tz_string_uses_constant_offset_after_last_transition_#{base_utc_offset}_#{std_offset}" do
1461
+ offsets = [
1462
+ {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
1463
+ {:gmtoff => base_utc_offset + std_offset, :isdst => std_offset != 0, :abbrev => 'TEST'}
1464
+ ]
1465
+
1466
+ transitions = [
1467
+ {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 3542, :offset_index => 1}
1468
+ ]
1469
+
1470
+ t0 = Time.utc(1971, 1, 2, 2, 0, 0) - 3542
1471
+
1472
+ tzif_test(offsets, transitions, :rules => rules) do |path, format|
1473
+ info = ZoneinfoTimezoneInfo.new('Constant/After', path, @posix_tz_parser)
1474
+ assert_equal('Constant/After', info.identifier)
1475
+ assert_period(:LMT, 3542, 0, false, nil, t0, info)
1476
+ assert_period(:TEST, base_utc_offset, std_offset, std_offset != 0, t0, nil, info)
1477
+ end
1478
+ end
1479
+ end
1480
+
1481
+ def test_load_tz_string_uses_rules_to_generate_all_transitions_when_none_defined
1482
+ offsets = [{:gmtoff => 7200, :isdst => false, :abbrev => 'XST'}]
1483
+
1484
+ rules = AnnualRules.new(
1485
+ TimezoneOffset.new(7200, 0, 'XST'),
1486
+ TimezoneOffset.new(7200, 3600, 'XDT'),
1487
+ JulianDayOfYearTransitionRule.new(100, 3600),
1488
+ JulianDayOfYearTransitionRule.new(300, 7200)
1489
+ )
1490
+
1491
+ generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1492
+
1493
+ tzif_test(offsets, [], :rules => rules) do |path, format|
1494
+ info = ZoneinfoTimezoneInfo.new('All/Rules', path, @posix_tz_parser)
1495
+ assert_equal('All/Rules', info.identifier)
1496
+
1497
+ assert_period(:XST, 7200, 0, false, nil, Time.utc(1970, 4, 10, 1, 0, 0) - 7200, info)
1498
+
1499
+ 1970.upto(generate_up_to - 1).each do |year|
1500
+ assert_period(:XDT, 7200, 3600, true, Time.utc(year, 4, 10, 1, 0, 0) - 7200, Time.utc(year, 10, 27, 2, 0, 0) - 10800, info)
1501
+ assert_period(:XST, 7200, 0, false, Time.utc(year, 10, 27, 2, 0, 0) - 10800, Time.utc(year + 1, 4, 10, 1, 0, 0) - 7200, info)
1502
+ end
1503
+
1504
+ assert_period(:XDT, 7200, 3600, true, Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 7200, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, info)
1505
+ assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1506
+ end
1507
+ end
1508
+
1509
+ def test_load_tz_string_uses_rules_to_generate_all_transitions_when_none_defined_omitting_first_if_matches_first_offset
1510
+ offsets = [{:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}]
1511
+
1512
+ rules = AnnualRules.new(
1513
+ TimezoneOffset.new(7200, 0, 'XST'),
1514
+ TimezoneOffset.new(7200, 3600, 'XDT'),
1515
+ JulianDayOfYearTransitionRule.new(100, 3600),
1516
+ JulianDayOfYearTransitionRule.new(300, 7200)
1517
+ )
1518
+
1519
+ generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1520
+
1521
+ tzif_test(offsets, [], :rules => rules) do |path, format|
1522
+ info = ZoneinfoTimezoneInfo.new('All/Rules', path, @posix_tz_parser)
1523
+ assert_equal('All/Rules', info.identifier)
1524
+
1525
+ assert_period(:XDT, 7200, 3600, true, nil, Time.utc(1970, 10, 27, 2, 0, 0) - 10800, info)
1526
+ assert_period(:XST, 7200, 0, false, Time.utc(1970, 10, 27, 2, 0, 0) - 10800, Time.utc(1971, 4, 10, 1, 0, 0) - 7200, info)
1527
+
1528
+ 1971.upto(generate_up_to - 1).each do |year|
1529
+ assert_period(:XDT, 7200, 3600, true, Time.utc(year, 4, 10, 1, 0, 0) - 7200, Time.utc(year, 10, 27, 2, 0, 0) - 10800, info)
1530
+ assert_period(:XST, 7200, 0, false, Time.utc(year, 10, 27, 2, 0, 0) - 10800, Time.utc(year + 1, 4, 10, 1, 0, 0) - 7200, info)
1531
+ end
1532
+
1533
+ assert_period(:XDT, 7200, 3600, true, Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 7200, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, info)
1534
+ assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1535
+ end
1536
+ end
1537
+
1538
+ def test_load_tz_string_uses_rules_to_generate_all_transitions_when_none_defined_with_previous_offset_of_first_matching_first_offset
1539
+ offsets = [{:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'}]
1540
+
1541
+ rules = AnnualRules.new(
1542
+ TimezoneOffset.new(7200, 0, 'XST'),
1543
+ TimezoneOffset.new(7200, 3600, 'XDT'),
1544
+ JulianDayOfYearTransitionRule.new(100, 3600),
1545
+ JulianDayOfYearTransitionRule.new(300, 7200)
1546
+ )
1547
+
1548
+ generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1549
+
1550
+ tzif_test(offsets, [], :rules => rules) do |path, format|
1551
+ info = ZoneinfoTimezoneInfo.new('All/Rules', path, @posix_tz_parser)
1552
+ assert_equal('All/Rules', info.identifier)
1553
+
1554
+ assert_period(:LMT, 7142, 0, false, nil, Time.utc(1970, 4, 10, 1, 0, 0) - 7200, info)
1555
+
1556
+ 1970.upto(generate_up_to - 1).each do |year|
1557
+ assert_period(:XDT, 7200, 3600, true, Time.utc(year, 4, 10, 1, 0, 0) - 7200, Time.utc(year, 10, 27, 2, 0, 0) - 10800, info)
1558
+ assert_period(:XST, 7200, 0, false, Time.utc(year, 10, 27, 2, 0, 0) - 10800, Time.utc(year + 1, 4, 10, 1, 0, 0) - 7200, info)
1559
+ end
1560
+
1561
+ assert_period(:XDT, 7200, 3600, true, Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 7200, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, info)
1562
+ assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1563
+ end
1564
+ end
1565
+
1566
+ def test_load_tz_string_uses_rules_to_generate_all_transitions_when_none_defined_correcting_initial_offset
1567
+ offsets = [{:gmtoff => 10800, :isdst => true, :abbrev => 'XDDT'}]
1568
+
1569
+ rules = AnnualRules.new(
1570
+ TimezoneOffset.new(3600, 0, 'XST'),
1571
+ TimezoneOffset.new(3600, 7200, 'XDDT'),
1572
+ JulianDayOfYearTransitionRule.new(100, 3600),
1573
+ JulianDayOfYearTransitionRule.new(300, 7200)
1574
+ )
1575
+
1576
+ generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1577
+
1578
+ tzif_test(offsets, [], :rules => rules) do |path, format|
1579
+ info = ZoneinfoTimezoneInfo.new('All/Rules', path, @posix_tz_parser)
1580
+ assert_equal('All/Rules', info.identifier)
1581
+
1582
+ assert_period(:XDDT, 3600, 7200, true, nil, Time.utc(1970, 10, 27, 2, 0, 0) - 10800, info) # would be :XDT, 7200, 3600 otherwise
1583
+ assert_period(:XST, 3600, 0, false, Time.utc(1970, 10, 27, 2, 0, 0) - 10800, Time.utc(1971, 4, 10, 1, 0, 0) - 3600, info)
1584
+
1585
+ 1971.upto(generate_up_to - 1).each do |year|
1586
+ assert_period(:XDDT, 3600, 7200, true, Time.utc(year, 4, 10, 1, 0, 0) - 3600, Time.utc(year, 10, 27, 2, 0, 0) - 10800, info)
1587
+ assert_period(:XST, 3600, 0, false, Time.utc(year, 10, 27, 2, 0, 0) - 10800, Time.utc(year + 1, 4, 10, 1, 0, 0) - 3600, info)
1588
+ end
1589
+
1590
+ assert_period(:XDDT, 3600, 7200, true, Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 3600, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, info)
1591
+ assert_period(:XST, 3600, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1592
+ end
1593
+ end
1594
+
1595
+ def test_load_tz_string_extends_transitions_starting_from_std_to_dst_following_year
1596
+ offsets = [
1597
+ {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1598
+ {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1599
+ {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
1600
+ ]
1601
+
1602
+ transitions = [
1603
+ {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
1604
+ {:at => Time.utc(1981, 4, 10, 1, 0, 0) - 7200, :offset_index => 2},
1605
+ {:at => Time.utc(1981, 10, 27, 2, 0, 0) - 10800, :offset_index => 1}
1606
+ ]
1607
+
1608
+ rules = AnnualRules.new(
1609
+ TimezoneOffset.new(7200, 0, 'XST'),
1610
+ TimezoneOffset.new(7200, 3600, 'XDT'),
1611
+ JulianDayOfYearTransitionRule.new(100, 3600),
1612
+ JulianDayOfYearTransitionRule.new(300, 7200)
1613
+ )
1614
+
1615
+ generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1616
+
1617
+ tzif_test(offsets, transitions, :rules => rules) do |path, format|
1618
+ info = ZoneinfoTimezoneInfo.new('From/Rules', path, @posix_tz_parser)
1619
+ assert_equal('From/Rules', info.identifier)
1620
+
1621
+ assert_period(:LMT, 7142, 0, false, nil, Time.utc(1971, 1, 2, 2, 0, 0) - 7142, info)
1622
+ assert_period(:XST, 7200, 0, false, Time.utc(1971, 1, 2, 2, 0, 0) - 7142, Time.utc(1981, 4, 10, 1, 0, 0) - 7200, info)
1623
+
1624
+ 1981.upto(generate_up_to - 1).each do |year|
1625
+ assert_period(:XDT, 7200, 3600, true, Time.utc(year, 4, 10, 1, 0, 0) - 7200, Time.utc(year, 10, 27, 2, 0, 0) - 10800, info)
1626
+ assert_period(:XST, 7200, 0, false, Time.utc(year, 10, 27, 2, 0, 0) - 10800, Time.utc(year + 1, 4, 10, 1, 0, 0) - 7200, info)
1627
+ end
1628
+
1629
+ assert_period(:XDT, 7200, 3600, true, Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 7200, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, info)
1630
+ assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1631
+ end
1632
+ end
1633
+
1634
+ def test_load_tz_string_extends_transitions_starting_from_dst_to_std_same_year
1635
+ offsets = [
1636
+ {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1637
+ {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1638
+ {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
1639
+ ]
1640
+
1641
+ transitions = [
1642
+ {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
1643
+ {:at => Time.utc(1981, 4, 10, 1, 0, 0) - 7200, :offset_index => 2},
1644
+ {:at => Time.utc(1981, 10, 27, 2, 0, 0) - 10800, :offset_index => 1},
1645
+ {:at => Time.utc(1982, 4, 10, 1, 0, 0) - 7200, :offset_index => 2}
1646
+ ]
1647
+
1648
+ rules = AnnualRules.new(
1649
+ TimezoneOffset.new(7200, 0, 'XST'),
1650
+ TimezoneOffset.new(7200, 3600, 'XDT'),
1651
+ JulianDayOfYearTransitionRule.new(100, 3600),
1652
+ JulianDayOfYearTransitionRule.new(300, 7200)
1653
+ )
1654
+
1655
+ generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1656
+
1657
+ tzif_test(offsets, transitions, :rules => rules) do |path, format|
1658
+ info = ZoneinfoTimezoneInfo.new('From/Rules', path, @posix_tz_parser)
1659
+ assert_equal('From/Rules', info.identifier)
1660
+
1661
+ assert_period(:LMT, 7142, 0, false, nil, Time.utc(1971, 1, 2, 2, 0, 0) - 7142, info)
1662
+ assert_period(:XST, 7200, 0, false, Time.utc(1971, 1, 2, 2, 0, 0) - 7142, Time.utc(1981, 4, 10, 1, 0, 0) - 7200, info)
1663
+
1664
+ 1981.upto(generate_up_to - 1).each do |year|
1665
+ assert_period(:XDT, 7200, 3600, true, Time.utc(year, 4, 10, 1, 0, 0) - 7200, Time.utc(year, 10, 27, 2, 0, 0) - 10800, info)
1666
+ assert_period(:XST, 7200, 0, false, Time.utc(year, 10, 27, 2, 0, 0) - 10800, Time.utc(year + 1, 4, 10, 1, 0, 0) - 7200, info)
1667
+ end
1668
+
1669
+ assert_period(:XDT, 7200, 3600, true, Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 7200, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, info)
1670
+ assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1671
+ end
1672
+ end
1673
+
1674
+ def test_load_tz_string_extends_transitions_starting_from_dst_to_std_following_year
1675
+ offsets = [
1676
+ {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1677
+ {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1678
+ {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
1679
+ ]
1680
+
1681
+ transitions = [
1682
+ {:at => Time.utc(1971, 1, 2, 1, 0, 0) - 7142, :offset_index => 1},
1683
+ {:at => Time.utc(1981, 10, 27, 1, 0, 0) - 7200, :offset_index => 2},
1684
+ {:at => Time.utc(1982, 4, 10, 2, 0, 0) - 10800, :offset_index => 1},
1685
+ {:at => Time.utc(1982, 10, 27, 1, 0, 0) - 7200, :offset_index => 2}
1686
+ ]
1687
+
1688
+ rules = AnnualRules.new(
1689
+ TimezoneOffset.new(7200, 0, 'XST'),
1690
+ TimezoneOffset.new(7200, 3600, 'XDT'),
1691
+ JulianDayOfYearTransitionRule.new(300, 3600),
1692
+ JulianDayOfYearTransitionRule.new(100, 7200)
1693
+ )
1694
+
1695
+ generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1696
+
1697
+ tzif_test(offsets, transitions, :rules => rules) do |path, format|
1698
+ info = ZoneinfoTimezoneInfo.new('From/Rules', path, @posix_tz_parser)
1699
+ assert_equal('From/Rules', info.identifier)
1700
+
1701
+ assert_period(:LMT, 7142, 0, false, nil, Time.utc(1971, 1, 2, 1, 0, 0) - 7142, info)
1702
+ assert_period(:XST, 7200, 0, false, Time.utc(1971, 1, 2, 1, 0, 0) - 7142, Time.utc(1981, 10, 27, 1, 0, 0) - 7200, info)
1703
+ assert_period(:XDT, 7200, 3600, true, Time.utc(1981, 10, 27, 1, 0, 0) - 7200, Time.utc(1982, 4, 10, 2, 0, 0) - 10800, info)
1704
+
1705
+ 1982.upto(generate_up_to - 1).each do |year|
1706
+ assert_period(:XST, 7200, 0, false, Time.utc(year, 4, 10, 1, 0, 0) - 7200, Time.utc(year, 10, 27, 2, 0, 0) - 10800, info)
1707
+ assert_period(:XDT, 7200, 3600, true, Time.utc(year, 10, 27, 2, 0, 0) - 10800, Time.utc(year + 1, 4, 10, 1, 0, 0) - 7200, info)
1708
+ end
1709
+
1710
+ assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 7200, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, info)
1711
+ assert_period(:XDT, 7200, 3600, true, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1712
+ end
1713
+ end
1714
+
1715
+ def test_load_tz_string_extends_transitions_starting_from_std_to_dst_same_year
1716
+ offsets = [
1717
+ {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1718
+ {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1719
+ {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
1720
+ ]
1721
+
1722
+ transitions = [
1723
+ {:at => Time.utc(1971, 1, 2, 1, 0, 0) - 7142, :offset_index => 1},
1724
+ {:at => Time.utc(1981, 10, 27, 1, 0, 0) - 7200, :offset_index => 2},
1725
+ {:at => Time.utc(1982, 4, 10, 2, 0, 0) - 10800, :offset_index => 1},
1726
+ {:at => Time.utc(1982, 10, 27, 1, 0, 0) - 7200, :offset_index => 2},
1727
+ {:at => Time.utc(1983, 4, 10, 2, 0, 0) - 10800, :offset_index => 1}
1728
+ ]
1729
+
1730
+ rules = AnnualRules.new(
1731
+ TimezoneOffset.new(7200, 0, 'XST'),
1732
+ TimezoneOffset.new(7200, 3600, 'XDT'),
1733
+ JulianDayOfYearTransitionRule.new(300, 3600),
1734
+ JulianDayOfYearTransitionRule.new(100, 7200)
1735
+ )
1736
+
1737
+ generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1738
+
1739
+ tzif_test(offsets, transitions, :rules => rules) do |path, format|
1740
+ info = ZoneinfoTimezoneInfo.new('From/Rules', path, @posix_tz_parser)
1741
+ assert_equal('From/Rules', info.identifier)
1742
+
1743
+ assert_period(:LMT, 7142, 0, false, nil, Time.utc(1971, 1, 2, 1, 0, 0) - 7142, info)
1744
+ assert_period(:XST, 7200, 0, false, Time.utc(1971, 1, 2, 1, 0, 0) - 7142, Time.utc(1981, 10, 27, 1, 0, 0) - 7200, info)
1745
+ assert_period(:XDT, 7200, 3600, true, Time.utc(1981, 10, 27, 1, 0, 0) - 7200, Time.utc(1982, 4, 10, 2, 0, 0) - 10800, info)
1746
+
1747
+ 1982.upto(generate_up_to - 1).each do |year|
1748
+ assert_period(:XST, 7200, 0, false, Time.utc(year, 4, 10, 1, 0, 0) - 7200, Time.utc(year, 10, 27, 2, 0, 0) - 10800, info)
1749
+ assert_period(:XDT, 7200, 3600, true, Time.utc(year, 10, 27, 2, 0, 0) - 10800, Time.utc(year + 1, 4, 10, 1, 0, 0) - 7200, info)
1750
+ end
1751
+
1752
+ assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 7200, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, info)
1753
+ assert_period(:XDT, 7200, 3600, true, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1754
+ end
1755
+ end
1756
+
1757
+ def test_load_tz_string_extends_transitions_negative_dst
1758
+ offsets = [
1759
+ {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1760
+ {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'},
1761
+ {:gmtoff => 10800, :isdst => false, :abbrev => 'XST'}
1762
+ ]
1763
+
1764
+ transitions = [
1765
+ {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
1766
+ {:at => Time.utc(1981, 4, 10, 1, 0, 0) - 7200, :offset_index => 2},
1767
+ {:at => Time.utc(1981, 10, 27, 2, 0, 0) - 10800, :offset_index => 1}
1768
+ ]
1769
+
1770
+ rules = AnnualRules.new(
1771
+ TimezoneOffset.new(10800, 0, 'XST'),
1772
+ TimezoneOffset.new(10800, -3600, 'XDT'),
1773
+ JulianDayOfYearTransitionRule.new(300, 7200),
1774
+ JulianDayOfYearTransitionRule.new(100, 3600)
1775
+ )
1776
+
1777
+ generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1778
+
1779
+ tzif_test(offsets, transitions, :rules => rules) do |path, format|
1780
+ info = ZoneinfoTimezoneInfo.new('From/Rules', path, @posix_tz_parser)
1781
+ assert_equal('From/Rules', info.identifier)
1782
+
1783
+ assert_period(:LMT, 7142, 0, false, nil, Time.utc(1971, 1, 2, 2, 0, 0) - 7142, info)
1784
+ assert_period(:XDT, 10800, -3600, true, Time.utc(1971, 1, 2, 2, 0, 0) - 7142, Time.utc(1981, 4, 10, 1, 0, 0) - 7200, info)
1785
+
1786
+ 1981.upto(generate_up_to - 1).each do |year|
1787
+ assert_period(:XST, 10800, 0, false, Time.utc(year, 4, 10, 1, 0, 0) - 7200, Time.utc(year, 10, 27, 2, 0, 0) - 10800, info)
1788
+ assert_period(:XDT, 10800, -3600, true, Time.utc(year, 10, 27, 2, 0, 0) - 10800, Time.utc(year + 1, 4, 10, 1, 0, 0) - 7200, info)
1789
+ end
1790
+
1791
+ assert_period(:XST, 10800, 0, false, Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 7200, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, info)
1792
+ assert_period(:XDT, 10800, -3600, true, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1793
+ end
1794
+ end
1795
+
1796
+ def test_load_tz_string_extends_single_transition_in_final_year
1797
+ offsets = [
1798
+ {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1799
+ {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1800
+ {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
1801
+ ]
1802
+
1803
+ generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1804
+
1805
+ transitions = [
1806
+ {:at => Time.utc( 1971, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
1807
+ {:at => Time.utc(generate_up_to - 1, 4, 10, 1, 0, 0) - 7200, :offset_index => 2},
1808
+ {:at => Time.utc(generate_up_to - 1, 10, 27, 2, 0, 0) - 10800, :offset_index => 1},
1809
+ {:at => Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 7200, :offset_index => 2}
1810
+ ]
1811
+
1812
+ rules = AnnualRules.new(
1813
+ TimezoneOffset.new(7200, 0, 'XST'),
1814
+ TimezoneOffset.new(7200, 3600, 'XDT'),
1815
+ JulianDayOfYearTransitionRule.new(100, 3600),
1816
+ JulianDayOfYearTransitionRule.new(300, 7200)
1817
+ )
1818
+
1819
+ tzif_test(offsets, transitions, :rules => rules) do |path, format|
1820
+ info = ZoneinfoTimezoneInfo.new('Final/Year', path, @posix_tz_parser)
1821
+ assert_equal('Final/Year', info.identifier)
1822
+
1823
+ assert_period(:LMT, 7142, 0, false, nil, Time.utc( 1971, 1, 2, 2, 0, 0) - 7142, info)
1824
+ assert_period(:XST, 7200, 0, false, Time.utc( 1971, 1, 2, 2, 0, 0) - 7142, Time.utc(generate_up_to - 1, 4, 10, 1, 0, 0) - 7200, info)
1825
+ assert_period(:XDT, 7200, 3600, true, Time.utc(generate_up_to - 1, 4, 10, 1, 0, 0) - 7200, Time.utc(generate_up_to - 1, 10, 27, 2, 0, 0) - 10800, info)
1826
+ assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to - 1, 10, 27, 2, 0, 0) - 10800, Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 7200, info)
1827
+ assert_period(:XDT, 7200, 3600, true, Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 7200, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, info)
1828
+ assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1829
+ end
1830
+ end
1831
+
1832
+ def test_load_tz_string_adds_nothing_if_transitions_up_to_final_year
1833
+ offsets = [
1834
+ {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1835
+ {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1836
+ {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
1837
+ ]
1838
+
1839
+ generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1840
+
1841
+ transitions = [
1842
+ {:at => Time.utc( 1971, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
1843
+ {:at => Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 7200, :offset_index => 2},
1844
+ {:at => Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, :offset_index => 1},
1845
+ ]
1846
+
1847
+ rules = AnnualRules.new(
1848
+ TimezoneOffset.new(7200, 0, 'XST'),
1849
+ TimezoneOffset.new(7200, 3600, 'XDT'),
1850
+ JulianDayOfYearTransitionRule.new(100, 3600),
1851
+ JulianDayOfYearTransitionRule.new(300, 7200)
1852
+ )
1853
+
1854
+ tzif_test(offsets, transitions, :rules => rules) do |path, format|
1855
+ info = ZoneinfoTimezoneInfo.new('Final/Year', path, @posix_tz_parser)
1856
+ assert_equal('Final/Year', info.identifier)
1857
+
1858
+ assert_period(:LMT, 7142, 0, false, nil, Time.utc( 1971, 1, 2, 2, 0, 0) - 7142, info)
1859
+ assert_period(:XDT, 7200, 3600, true, Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 7200, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, info)
1860
+ assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1861
+ end
1862
+ end
1863
+
1864
+ def test_load_tz_string_corrects_offset_of_final_transition
1865
+ offsets = [
1866
+ {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
1867
+ {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'}]
1868
+
1869
+ transitions = [{:at => Time.utc(2000, 4, 10, 1, 0, 0) - 3542, :offset_index => 1}]
1870
+
1871
+ rules = AnnualRules.new(
1872
+ TimezoneOffset.new(3600, 0, 'XST'),
1873
+ TimezoneOffset.new(3600, 3600, 'XDT'),
1874
+ JulianDayOfYearTransitionRule.new(100, 3600),
1875
+ JulianDayOfYearTransitionRule.new(300, 7200)
1876
+ )
1877
+
1878
+ generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1879
+
1880
+ tzif_test(offsets, transitions, :rules => rules) do |path, format|
1881
+ info = ZoneinfoTimezoneInfo.new('Correct/Final', path, @posix_tz_parser)
1882
+ assert_equal('Correct/Final', info.identifier)
1883
+
1884
+ assert_period(:LMT, 3542, 0, false, nil, Time.utc(2000, 4, 10, 1, 0, 0) - 3542, info)
1885
+ assert_period(:XDT, 3600, 3600, true, Time.utc(2000, 4, 10, 1, 0, 0) - 3542, Time.utc(2000, 10, 27, 2, 0, 0) - 7200, info) # would be :XDT, 3542, 3658 without tz_string
1886
+ assert_period(:XST, 3600, 0, false, Time.utc(2000, 10, 27, 2, 0, 0) - 7200, Time.utc(2001, 4, 10, 1, 0, 0) - 3600, info)
1887
+
1888
+ 2001.upto(generate_up_to - 1).each do |year|
1889
+ assert_period(:XDT, 3600, 3600, true, Time.utc(year, 4, 10, 1, 0, 0) - 3600, Time.utc(year, 10, 27, 2, 0, 0) - 7200, info)
1890
+ assert_period(:XST, 3600, 0, false, Time.utc(year, 10, 27, 2, 0, 0) - 7200, Time.utc(year + 1, 4, 10, 1, 0, 0) - 3600, info)
1891
+ end
1892
+
1893
+ assert_period(:XDT, 3600, 3600, true, Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 3600, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 7200, info)
1894
+ assert_period(:XST, 3600, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 7200, nil, info)
1895
+ end
1896
+ end
1897
+
1898
+ def test_load_tz_string_specifies_transition_to_offset_of_final_transition_same_year
1899
+ offsets = [
1900
+ {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1901
+ {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1902
+ {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
1903
+ ]
1904
+
1905
+ transitions = [
1906
+ {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
1907
+ {:at => Time.utc(1981, 4, 10, 1, 0, 0) - 7200, :offset_index => 2},
1908
+ {:at => Time.utc(1981, 10, 27, 2, 0, 0) - 10800, :offset_index => 1},
1909
+ {:at => Time.utc(1982, 4, 10, 1, 0, 0) - 7200, :offset_index => 2}
1910
+ ]
1911
+
1912
+ rules = AnnualRules.new(
1913
+ TimezoneOffset.new(7200, 0, 'XST'),
1914
+ TimezoneOffset.new(7200, 3600, 'XDT'),
1915
+ JulianDayOfYearTransitionRule.new(101, 3600),
1916
+ JulianDayOfYearTransitionRule.new(300, 7200)
1917
+ )
1918
+
1919
+ tzif_test(offsets, transitions, :rules => rules) do |path, format|
1920
+ error = assert_raises(InvalidZoneinfoFile) { ZoneinfoTimezoneInfo.new('Invalid/Offset', path, @posix_tz_parser) }
1921
+ assert_equal("The first offset indicated by the POSIX-style TZ string did not match the final defined offset in file '#{path}'.", error.message)
1922
+ end
1923
+ end
1924
+
1925
+ def test_load_tz_string_specifies_transition_to_offset_of_final_transition_following_year
1926
+ offsets = [
1927
+ {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1928
+ {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1929
+ {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
1930
+ ]
1931
+
1932
+ transitions = [
1933
+ {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
1934
+ {:at => Time.utc(1981, 10, 27, 2, 0, 0) - 7200, :offset_index => 2}
1935
+ ]
1936
+
1937
+ rules = AnnualRules.new(
1938
+ TimezoneOffset.new(7200, 0, 'XST'),
1939
+ TimezoneOffset.new(7200, 3600, 'XDT'),
1940
+ JulianDayOfYearTransitionRule.new(100, 3600),
1941
+ JulianDayOfYearTransitionRule.new(299, 7200)
1942
+ )
1943
+
1944
+ tzif_test(offsets, transitions, :rules => rules) do |path, format|
1945
+ error = assert_raises(InvalidZoneinfoFile) { ZoneinfoTimezoneInfo.new('Invalid/Offset', path, @posix_tz_parser) }
1946
+ assert_equal("The first offset indicated by the POSIX-style TZ string did not match the final defined offset in file '#{path}'.", error.message)
1947
+ end
1948
+ end
1949
+
1950
+ unless SUPPORTS_64BIT
1951
+ def test_generate_up_to_limited_to_2037_with_no_64_bit_support
1952
+ assert_equal(2037, ZoneinfoTimezoneInfo::GENERATE_UP_TO)
1953
+ end
1954
+
1955
+ def test_load_tz_string_does_not_generate_if_transition_after_32_bit_range_with_no_64_bit_support
1956
+ offsets = [
1957
+ {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1958
+ {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1959
+ {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
1960
+ ]
1961
+
1962
+ transitions = [
1963
+ {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
1964
+ {:at => 2154474000 - 7200, :offset_index => 2}, # Time.utc(2038, 4, 10, 1, 0, 0).to_i
1965
+ {:at => 2171757600 - 10800, :offset_index => 1} # Time.utc(2038, 10, 27, 2, 0, 0).to_i
1966
+ ]
1967
+
1968
+ rules = AnnualRules.new(
1969
+ TimezoneOffset.new(7200, 0, 'XST'),
1970
+ TimezoneOffset.new(7200, 3600, 'XDT'),
1971
+ JulianDayOfYearTransitionRule.new(100, 3600),
1972
+ JulianDayOfYearTransitionRule.new(300, 7200)
1973
+ )
1974
+
1975
+ tzif_test(offsets, transitions, :rules => rules) do |path, format|
1976
+ info = ZoneinfoTimezoneInfo.new('From/Rules', path, @posix_tz_parser)
1977
+ assert_equal('From/Rules', info.identifier)
1978
+
1979
+ assert_period(:LMT, 7142, 0, false, nil, Time.utc(1971, 1, 2, 2, 0, 0) - 7142, info)
1980
+ assert_period(:XST, 7200, 0, false, Time.utc(1971, 1, 2, 2, 0, 0) - 7142, nil, info)
1981
+ end
1982
+ end
1983
+ end
1984
+
1985
+ if SUPPORTS_NEGATIVE
1986
+ def test_load_tz_string_generates_from_last_transition_if_before_1970_and_supports_negative
1987
+ offsets = [
1988
+ {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1989
+ {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1990
+ {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
1991
+ ]
1992
+
1993
+ transitions = [
1994
+ {:at => Time.utc(1961, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
1995
+ {:at => Time.utc(1962, 4, 10, 1, 0, 0) - 7200, :offset_index => 2},
1996
+ {:at => Time.utc(1962, 10, 27, 2, 0, 0) - 10800, :offset_index => 1}
1997
+ ]
1998
+
1999
+ rules = AnnualRules.new(
2000
+ TimezoneOffset.new(7200, 0, 'XST'),
2001
+ TimezoneOffset.new(7200, 3600, 'XDT'),
2002
+ JulianDayOfYearTransitionRule.new(100, 3600),
2003
+ JulianDayOfYearTransitionRule.new(300, 7200)
2004
+ )
2005
+
2006
+ generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
2007
+
2008
+ tzif_test(offsets, transitions, :rules => rules) do |path, format|
2009
+ info = ZoneinfoTimezoneInfo.new('Pre/1970', path, @posix_tz_parser)
2010
+ assert_equal('Pre/1970', info.identifier)
2011
+
2012
+ assert_period(:LMT, 7142, 0, false, nil, Time.utc(1961, 1, 2, 2, 0, 0) - 7142, info)
2013
+ assert_period(:XST, 7200, 0, false, Time.utc(1961, 1, 2, 2, 0, 0) - 7142, Time.utc(1962, 4, 10, 1, 0, 0) - 7200, info)
2014
+
2015
+ 1962.upto(generate_up_to - 1).each do |year|
2016
+ assert_period(:XDT, 7200, 3600, true, Time.utc(year, 4, 10, 1, 0, 0) - 7200, Time.utc(year, 10, 27, 2, 0, 0) - 10800, info)
2017
+ assert_period(:XST, 7200, 0, false, Time.utc(year, 10, 27, 2, 0, 0) - 10800, Time.utc(year + 1, 4, 10, 1, 0, 0) - 7200, info)
2018
+ end
2019
+
2020
+ assert_period(:XDT, 7200, 3600, true, Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 7200, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, info)
2021
+ assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
2022
+ end
2023
+ end
2024
+ else
2025
+ def test_load_tz_string_generates_from_1970_if_last_transition_before_1970_and_does_not_support_negative
2026
+ offsets = [
2027
+ {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
2028
+ {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
2029
+ {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
2030
+ ]
2031
+
2032
+ transitions = [
2033
+ {:at => -283903200 - 7142, :offset_index => 1}, # Time.utc(1961, 1, 2, 2, 0, 0)
2034
+ {:at => -243903600 - 7200, :offset_index => 2}, # Time.utc(1962, 4, 10, 1, 0, 0)
2035
+ {:at => -226620000 - 10800, :offset_index => 1} # Time.utc(1962, 10, 27, 2, 0, 0)
2036
+ ]
2037
+
2038
+ rules = AnnualRules.new(
2039
+ TimezoneOffset.new(7200, 0, 'XST'),
2040
+ TimezoneOffset.new(7200, 3600, 'XDT'),
2041
+ JulianDayOfYearTransitionRule.new(100, 3600),
2042
+ JulianDayOfYearTransitionRule.new(300, 7200)
2043
+ )
2044
+
2045
+ generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
2046
+
2047
+ tzif_test(offsets, transitions, :rules => rules) do |path, format|
2048
+ info = ZoneinfoTimezoneInfo.new('Pre/1970', path, @posix_tz_parser)
2049
+ assert_equal('Pre/1970', info.identifier)
2050
+
2051
+ assert_period(:LMT, 7142, 0, false, nil, Time.utc(1970, 1, 1), info)
2052
+ assert_period(:XST, 7200, 0, false, Time.utc(1970, 1, 1), Time.utc(1970, 4, 10, 1, 0, 0) - 7200, info)
2053
+
2054
+ 1970.upto(generate_up_to - 1).each do |year|
2055
+ assert_period(:XDT, 7200, 3600, true, Time.utc(year, 4, 10, 1, 0, 0) - 7200, Time.utc(year, 10, 27, 2, 0, 0) - 10800, info)
2056
+ assert_period(:XST, 7200, 0, false, Time.utc(year, 10, 27, 2, 0, 0) - 10800, Time.utc(year + 1, 4, 10, 1, 0, 0) - 7200, info)
2057
+ end
2058
+
2059
+ assert_period(:XDT, 7200, 3600, true, Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 7200, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, info)
2060
+ assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
2061
+ end
2062
+ end
2063
+ end
2064
+
2065
+ def test_load_tz_string_as_utf8
2066
+ offsets = [{:gmtoff => 3600, :isdst => false, :abbrev => 'áccént'}]
2067
+ rules = TimezoneOffset.new(3600, 0, 'áccént')
2068
+
2069
+ tzif_test(offsets, [], :tz_string => '<áccént>1', :rules => rules) do |path, format|
2070
+ # FakePosixTimeZoneParser will test that the tz_string matches.
2071
+ info = ZoneinfoTimezoneInfo.new('Test/Utf8', path, @posix_tz_parser)
2072
+ assert_period(:'áccént', 3600, 0, false, nil, nil, info)
2073
+ end
2074
+ end
1236
2075
  end