tzinfo 1.2.11 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.yardopts +3 -0
  4. data/CHANGES.md +469 -431
  5. data/LICENSE +13 -13
  6. data/README.md +368 -114
  7. data/lib/tzinfo/country.rb +131 -129
  8. data/lib/tzinfo/country_timezone.rb +70 -112
  9. data/lib/tzinfo/data_source.rb +389 -144
  10. data/lib/tzinfo/data_sources/constant_offset_data_timezone_info.rb +56 -0
  11. data/lib/tzinfo/data_sources/country_info.rb +42 -0
  12. data/lib/tzinfo/data_sources/data_timezone_info.rb +91 -0
  13. data/lib/tzinfo/data_sources/linked_timezone_info.rb +33 -0
  14. data/lib/tzinfo/data_sources/ruby_data_source.rb +141 -0
  15. data/lib/tzinfo/data_sources/timezone_info.rb +47 -0
  16. data/lib/tzinfo/data_sources/transitions_data_timezone_info.rb +214 -0
  17. data/lib/tzinfo/data_sources/zoneinfo_data_source.rb +573 -0
  18. data/lib/tzinfo/data_sources/zoneinfo_reader.rb +284 -0
  19. data/lib/tzinfo/data_sources.rb +8 -0
  20. data/lib/tzinfo/data_timezone.rb +33 -47
  21. data/lib/tzinfo/datetime_with_offset.rb +153 -0
  22. data/lib/tzinfo/format1/country_definer.rb +17 -0
  23. data/lib/tzinfo/format1/country_index_definition.rb +64 -0
  24. data/lib/tzinfo/format1/timezone_definer.rb +64 -0
  25. data/lib/tzinfo/format1/timezone_definition.rb +39 -0
  26. data/lib/tzinfo/format1/timezone_index_definition.rb +77 -0
  27. data/lib/tzinfo/format1.rb +10 -0
  28. data/lib/tzinfo/format2/country_definer.rb +68 -0
  29. data/lib/tzinfo/format2/country_index_definer.rb +68 -0
  30. data/lib/tzinfo/format2/country_index_definition.rb +46 -0
  31. data/lib/tzinfo/format2/timezone_definer.rb +94 -0
  32. data/lib/tzinfo/format2/timezone_definition.rb +73 -0
  33. data/lib/tzinfo/format2/timezone_index_definer.rb +45 -0
  34. data/lib/tzinfo/format2/timezone_index_definition.rb +55 -0
  35. data/lib/tzinfo/format2.rb +10 -0
  36. data/lib/tzinfo/info_timezone.rb +26 -21
  37. data/lib/tzinfo/linked_timezone.rb +33 -52
  38. data/lib/tzinfo/offset_timezone_period.rb +42 -0
  39. data/lib/tzinfo/string_deduper.rb +118 -0
  40. data/lib/tzinfo/time_with_offset.rb +128 -0
  41. data/lib/tzinfo/timestamp.rb +548 -0
  42. data/lib/tzinfo/timestamp_with_offset.rb +85 -0
  43. data/lib/tzinfo/timezone.rb +979 -502
  44. data/lib/tzinfo/timezone_offset.rb +84 -74
  45. data/lib/tzinfo/timezone_period.rb +151 -217
  46. data/lib/tzinfo/timezone_proxy.rb +70 -79
  47. data/lib/tzinfo/timezone_transition.rb +77 -109
  48. data/lib/tzinfo/transitions_timezone_period.rb +63 -0
  49. data/lib/tzinfo/version.rb +7 -0
  50. data/lib/tzinfo/with_offset.rb +61 -0
  51. data/lib/tzinfo.rb +60 -40
  52. data.tar.gz.sig +0 -0
  53. metadata +51 -115
  54. metadata.gz.sig +2 -3
  55. data/Rakefile +0 -107
  56. data/lib/tzinfo/annual_rules.rb +0 -51
  57. data/lib/tzinfo/country_index_definition.rb +0 -31
  58. data/lib/tzinfo/country_info.rb +0 -42
  59. data/lib/tzinfo/data_timezone_info.rb +0 -55
  60. data/lib/tzinfo/linked_timezone_info.rb +0 -26
  61. data/lib/tzinfo/offset_rationals.rb +0 -77
  62. data/lib/tzinfo/posix_time_zone_parser.rb +0 -136
  63. data/lib/tzinfo/ruby_core_support.rb +0 -176
  64. data/lib/tzinfo/ruby_country_info.rb +0 -74
  65. data/lib/tzinfo/ruby_data_source.rb +0 -136
  66. data/lib/tzinfo/time_or_datetime.rb +0 -351
  67. data/lib/tzinfo/timezone_definition.rb +0 -36
  68. data/lib/tzinfo/timezone_index_definition.rb +0 -54
  69. data/lib/tzinfo/timezone_info.rb +0 -30
  70. data/lib/tzinfo/timezone_transition_definition.rb +0 -104
  71. data/lib/tzinfo/transition_data_timezone_info.rb +0 -274
  72. data/lib/tzinfo/transition_rule.rb +0 -325
  73. data/lib/tzinfo/zoneinfo_country_info.rb +0 -37
  74. data/lib/tzinfo/zoneinfo_data_source.rb +0 -504
  75. data/lib/tzinfo/zoneinfo_timezone_info.rb +0 -516
  76. data/test/assets/payload.rb +0 -1
  77. data/test/tc_annual_rules.rb +0 -95
  78. data/test/tc_country.rb +0 -240
  79. data/test/tc_country_index_definition.rb +0 -69
  80. data/test/tc_country_info.rb +0 -16
  81. data/test/tc_country_timezone.rb +0 -173
  82. data/test/tc_data_source.rb +0 -218
  83. data/test/tc_data_timezone.rb +0 -99
  84. data/test/tc_data_timezone_info.rb +0 -18
  85. data/test/tc_info_timezone.rb +0 -34
  86. data/test/tc_linked_timezone.rb +0 -155
  87. data/test/tc_linked_timezone_info.rb +0 -23
  88. data/test/tc_offset_rationals.rb +0 -23
  89. data/test/tc_posix_time_zone_parser.rb +0 -261
  90. data/test/tc_ruby_core_support.rb +0 -168
  91. data/test/tc_ruby_country_info.rb +0 -110
  92. data/test/tc_ruby_data_source.rb +0 -175
  93. data/test/tc_time_or_datetime.rb +0 -674
  94. data/test/tc_timezone.rb +0 -1361
  95. data/test/tc_timezone_definition.rb +0 -113
  96. data/test/tc_timezone_index_definition.rb +0 -73
  97. data/test/tc_timezone_info.rb +0 -11
  98. data/test/tc_timezone_london.rb +0 -143
  99. data/test/tc_timezone_melbourne.rb +0 -142
  100. data/test/tc_timezone_new_york.rb +0 -142
  101. data/test/tc_timezone_offset.rb +0 -126
  102. data/test/tc_timezone_period.rb +0 -555
  103. data/test/tc_timezone_proxy.rb +0 -136
  104. data/test/tc_timezone_transition.rb +0 -366
  105. data/test/tc_timezone_transition_definition.rb +0 -295
  106. data/test/tc_timezone_utc.rb +0 -27
  107. data/test/tc_transition_data_timezone_info.rb +0 -433
  108. data/test/tc_transition_rule.rb +0 -663
  109. data/test/tc_zoneinfo_country_info.rb +0 -78
  110. data/test/tc_zoneinfo_data_source.rb +0 -1226
  111. data/test/tc_zoneinfo_timezone_info.rb +0 -2149
  112. data/test/test_utils.rb +0 -214
  113. data/test/ts_all.rb +0 -7
  114. data/test/ts_all_ruby.rb +0 -5
  115. data/test/ts_all_zoneinfo.rb +0 -9
  116. data/test/tzinfo-data/tzinfo/data/definitions/America/Argentina/Buenos_Aires.rb +0 -89
  117. data/test/tzinfo-data/tzinfo/data/definitions/America/New_York.rb +0 -327
  118. data/test/tzinfo-data/tzinfo/data/definitions/Australia/Melbourne.rb +0 -230
  119. data/test/tzinfo-data/tzinfo/data/definitions/EST.rb +0 -19
  120. data/test/tzinfo-data/tzinfo/data/definitions/Etc/GMT__m__1.rb +0 -21
  121. data/test/tzinfo-data/tzinfo/data/definitions/Etc/GMT__p__1.rb +0 -21
  122. data/test/tzinfo-data/tzinfo/data/definitions/Etc/UTC.rb +0 -21
  123. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Amsterdam.rb +0 -273
  124. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Andorra.rb +0 -198
  125. data/test/tzinfo-data/tzinfo/data/definitions/Europe/London.rb +0 -333
  126. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Paris.rb +0 -277
  127. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Prague.rb +0 -235
  128. data/test/tzinfo-data/tzinfo/data/definitions/UTC.rb +0 -16
  129. data/test/tzinfo-data/tzinfo/data/indexes/countries.rb +0 -940
  130. data/test/tzinfo-data/tzinfo/data/indexes/timezones.rb +0 -609
  131. data/test/tzinfo-data/tzinfo/data/version.rb +0 -20
  132. data/test/tzinfo-data/tzinfo/data.rb +0 -8
  133. data/test/zoneinfo/America/Argentina/Buenos_Aires +0 -0
  134. data/test/zoneinfo/America/New_York +0 -0
  135. data/test/zoneinfo/Australia/Melbourne +0 -0
  136. data/test/zoneinfo/EST +0 -0
  137. data/test/zoneinfo/Etc/UTC +0 -0
  138. data/test/zoneinfo/Europe/Amsterdam +0 -0
  139. data/test/zoneinfo/Europe/Andorra +0 -0
  140. data/test/zoneinfo/Europe/London +0 -0
  141. data/test/zoneinfo/Europe/Paris +0 -0
  142. data/test/zoneinfo/Europe/Prague +0 -0
  143. data/test/zoneinfo/Factory +0 -0
  144. data/test/zoneinfo/iso3166.tab +0 -274
  145. data/test/zoneinfo/leapseconds +0 -78
  146. data/test/zoneinfo/posix/Europe/London +0 -0
  147. data/test/zoneinfo/posixrules +0 -0
  148. data/test/zoneinfo/right/Europe/London +0 -0
  149. data/test/zoneinfo/zone.tab +0 -452
  150. data/test/zoneinfo/zone1970.tab +0 -384
  151. data/tzinfo.gemspec +0 -21
@@ -1,2149 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require File.join(File.expand_path(File.dirname(__FILE__)), 'test_utils')
4
- require 'tempfile'
5
-
6
- include TZInfo
7
-
8
- class TCZoneinfoTimezoneInfo < Minitest::Test
9
- class FakePosixTimeZoneParser
10
- def initialize(&block)
11
- @on_parse = block
12
- end
13
-
14
- def parse(tz_string)
15
- @on_parse.call(tz_string)
16
- end
17
- end
18
-
19
- begin
20
- Time.at(-2147483649)
21
- Time.at(2147483648)
22
- SUPPORTS_64BIT = true
23
- rescue RangeError
24
- SUPPORTS_64BIT = false
25
- end
26
-
27
- begin
28
- Time.at(-1)
29
- Time.at(-2147483648)
30
- SUPPORTS_NEGATIVE = true
31
- rescue ArgumentError
32
- SUPPORTS_NEGATIVE = false
33
- end
34
-
35
- def setup
36
- @expect_tz_string = nil
37
- @tz_parse_result = nil
38
- @posix_tz_parser = FakePosixTimeZoneParser.new do |tz_string|
39
- raise "Unexpected tz_string passed to PosixTimeZoneParser: #{tz_string}" unless tz_string == @expect_tz_string
40
- raise InvalidPosixTimeZone, 'FakePosixTimeZoneParser Failure.' if @tz_parse_result == :fail
41
- @tz_parse_result
42
- end
43
- end
44
-
45
- def assert_period(abbreviation, utc_offset, std_offset, dst, start_at, end_at, info)
46
- if start_at
47
- period = info.period_for_utc(start_at)
48
- elsif end_at
49
- period = info.period_for_utc(TimeOrDateTime.wrap(end_at).add_with_convert(-1).to_orig)
50
- else
51
- # no transitions, pick the epoch
52
- period = info.period_for_utc(Time.utc(1970, 1, 1))
53
- end
54
-
55
- assert_equal(abbreviation, period.abbreviation, 'abbreviation')
56
- assert_equal(utc_offset, period.utc_offset, 'utc_offset')
57
- assert_equal(std_offset, period.std_offset, 'std_offset')
58
- assert_equal(dst, period.dst?, 'dst')
59
-
60
- if start_at
61
- refute_nil(period.utc_start_time, 'utc_start_time')
62
- assert_equal(start_at, period.utc_start_time, 'utc_start_time')
63
- else
64
- assert_nil(period.utc_start_time, 'utc_start_time')
65
- end
66
-
67
- if end_at
68
- refute_nil(period.utc_end_time, 'utc_end_time')
69
- assert_equal(end_at, period.utc_end_time, 'utc_end_time')
70
- else
71
- assert_nil(period.utc_end_time, 'utc_end_time')
72
- end
73
- end
74
-
75
- def convert_times_to_i(items, key = :at)
76
- items.each do |item|
77
- if item[key].kind_of?(Time)
78
- item[key] = item[key].utc.to_i
79
- end
80
- end
81
- end
82
-
83
- def select_with_32bit_values(items, key = :at)
84
- items.select do |item|
85
- i = item[key]
86
- i >= -2147483648 && i <= 2147483647
87
- end
88
- end
89
-
90
- def pack_int64_network_order(values)
91
- values.collect {|value| [value >> 32, value & 0xFFFFFFFF]}.flatten.pack('NN' * values.length)
92
- end
93
-
94
- def pack_int64_signed_network_order(values)
95
- # Convert to the equivalent 64-bit unsigned integer with the same bit representation
96
- pack_int64_network_order(values.collect {|value| value < 0 ? value + 0x10000000000000000 : value})
97
- end
98
-
99
- def write_tzif(format, offsets, transitions, tz_string, leaps, options = {})
100
-
101
- # Options for testing malformed zoneinfo files.
102
- magic = options[:magic]
103
- section2_magic = options[:section2_magic]
104
- abbrev_separator = options[:abbrev_separator] || "\0"
105
- abbrev_offset_base = options[:abbrev_offset_base] || 0
106
- omit_tz_string_start_new_line = options[:omit_tz_string_start_new_line]
107
- omit_tz_string_end_new_line = options[:omit_tz_string_end_new_line]
108
-
109
- unless magic
110
- if format == 1
111
- magic = "TZif\0"
112
- elsif format >= 2
113
- magic = "TZif#{format}"
114
- else
115
- raise ArgumentError, 'Invalid format specified'
116
- end
117
- end
118
-
119
- if section2_magic.kind_of?(Proc)
120
- section2_magic = section2_magic.call(format)
121
- else
122
- section2_magic = magic unless section2_magic
123
- end
124
-
125
- convert_times_to_i(transitions)
126
- convert_times_to_i(leaps)
127
-
128
- abbrevs = offsets.collect {|o| o[:abbrev]}.uniq
129
-
130
- if abbrevs.length > 0
131
- abbrevs = abbrevs.collect {|a| a.encode('UTF-8')} if abbrevs.first.respond_to?(:encode)
132
-
133
- if abbrevs.first.respond_to?(:bytesize)
134
- abbrevs_length = abbrevs.inject(0) {|sum, a| sum + a.bytesize + abbrev_separator.bytesize}
135
- else
136
- abbrevs_length = abbrevs.inject(0) {|sum, a| sum + a.length + abbrev_separator.length}
137
- end
138
- else
139
- abbrevs_length = 0
140
- end
141
-
142
- b32_transitions = select_with_32bit_values(transitions)
143
- b32_leaps = select_with_32bit_values(leaps)
144
-
145
- Tempfile.open('tzinfo-test-zone') do |file|
146
- file.binmode
147
-
148
- file.write(
149
- [magic, offsets.length, offsets.length, leaps.length,
150
- b32_transitions.length, offsets.length, abbrevs_length].pack('a5 x15 NNNNNN'))
151
-
152
- unless b32_transitions.empty?
153
- file.write(b32_transitions.collect {|t| t[:at]}.pack('N' * b32_transitions.length))
154
- file.write(b32_transitions.collect {|t| t[:offset_index]}.pack('C' * b32_transitions.length))
155
- end
156
-
157
- offsets.each do |offset|
158
- index = abbrevs.index(offset[:abbrev])
159
- abbrev_offset = abbrev_offset_base
160
- 0.upto(index - 1) {|i| abbrev_offset += abbrevs[i].length + 1}
161
-
162
- file.write([offset[:gmtoff], offset[:isdst] ? 1 : 0, abbrev_offset].pack('NCC'))
163
- end
164
-
165
- abbrevs.each do |a|
166
- file.write(a)
167
- file.write(abbrev_separator)
168
- end
169
-
170
- b32_leaps.each do |leap|
171
- file.write([leap[:at], leap[:seconds]].pack('NN'))
172
- end
173
-
174
- unless offsets.empty?
175
- file.write("\0" * offsets.length * 2)
176
- end
177
-
178
- if format >= 2
179
- file.write(
180
- [section2_magic, offsets.length, offsets.length, leaps.length,
181
- transitions.length, offsets.length, abbrevs_length].pack('a5 x15 NNNNNN'))
182
-
183
- unless transitions.empty?
184
- file.write(pack_int64_signed_network_order(transitions.collect {|t| t[:at]}))
185
- file.write(transitions.collect {|t| t[:offset_index]}.pack('C' * transitions.length))
186
- end
187
-
188
- offsets.each do |offset|
189
- index = abbrevs.index(offset[:abbrev])
190
- abbrev_offset = abbrev_offset_base
191
- 0.upto(index - 1) {|i| abbrev_offset += abbrevs[i].length + 1}
192
-
193
- file.write([offset[:gmtoff], offset[:isdst] ? 1 : 0, abbrev_offset].pack('NCC'))
194
- end
195
-
196
- abbrevs.each do |a|
197
- file.write(a)
198
- file.write(abbrev_separator)
199
- end
200
-
201
- leaps.each do |leap|
202
- file.write(pack_int64_signed_network_order([leap[:at]]))
203
- file.write([leap[:seconds]].pack('N'))
204
- end
205
-
206
- unless offsets.empty?
207
- file.write("\0" * offsets.length * 2)
208
- end
209
-
210
- # Empty POSIX timezone string
211
- file.write("\n") unless omit_tz_string_start_new_line
212
- tz_string = tz_string.encode(Encoding::UTF_8) if tz_string.respond_to?(:encode)
213
- file.write(tz_string)
214
- file.write("\n") unless omit_tz_string_end_new_line
215
- end
216
-
217
- file.flush
218
-
219
- yield file.path
220
- end
221
- end
222
-
223
- def tzif_test(offsets, transitions, options = {}, &block)
224
- rules = options[:rules]
225
- tz_string = options[:tz_string] || (rules ? "TEST_TZ_STRING_#{rand(1000000)}" : '')
226
- leaps = options[:leaps] || []
227
- min_format = options[:min_format] || (tz_string.empty? ? 1 : 2)
228
-
229
- min_format.upto(3) do |format|
230
- write_tzif(format, offsets, transitions, tz_string, leaps, options) do |path|
231
- if format >= 2
232
- @tz_parse_result = rules
233
- @expect_tz_string = tz_string
234
- end
235
- begin
236
- yield path, format
237
- ensure
238
- @tz_parse_result = nil
239
- @expect_tz_string = nil
240
- end
241
- end
242
- end
243
- end
244
-
245
- def test_load
246
- offsets = [
247
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
248
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
249
- {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'},
250
- {:gmtoff => 0, :isdst => false, :abbrev => 'XNST'}]
251
-
252
- transitions = [
253
- {:at => Time.utc(1971, 1, 2), :offset_index => 1},
254
- {:at => Time.utc(1980, 4, 22), :offset_index => 2},
255
- {:at => Time.utc(1980, 10, 21), :offset_index => 1},
256
- {:at => Time.utc(2000, 12, 31), :offset_index => 3}]
257
-
258
- tzif_test(offsets, transitions) do |path, format|
259
- info = ZoneinfoTimezoneInfo.new('Zone/One', path, @posix_tz_parser)
260
- assert_equal('Zone/One', info.identifier)
261
-
262
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(1971, 1, 2), info)
263
- assert_period(:XST, 3600, 0, false, Time.utc(1971, 1, 2), Time.utc(1980, 4, 22), info)
264
- assert_period(:XDT, 3600, 3600, true, Time.utc(1980, 4, 22), Time.utc(1980, 10, 21), info)
265
- assert_period(:XST, 3600, 0, false, Time.utc(1980, 10, 21), Time.utc(2000, 12, 31), info)
266
- assert_period(:XNST, 0, 0, false, Time.utc(2000, 12, 31), nil, info)
267
- end
268
- end
269
-
270
- def test_load_negative_utc_offset
271
- offsets = [
272
- {:gmtoff => -12492, :isdst => false, :abbrev => 'LMT'},
273
- {:gmtoff => -12000, :isdst => false, :abbrev => 'XST'},
274
- {:gmtoff => -8400, :isdst => true, :abbrev => 'XDT'},
275
- {:gmtoff => -8400, :isdst => false, :abbrev => 'XNST'}]
276
-
277
- transitions = [
278
- {:at => Time.utc(1971, 7, 9, 3, 0, 0), :offset_index => 1},
279
- {:at => Time.utc(1972, 10, 12, 3, 0, 0), :offset_index => 2},
280
- {:at => Time.utc(1973, 4, 29, 3, 0, 0), :offset_index => 1},
281
- {:at => Time.utc(1992, 4, 1, 4, 30, 0), :offset_index => 3}]
282
-
283
- tzif_test(offsets, transitions) do |path, format|
284
- info = ZoneinfoTimezoneInfo.new('Zone/One', path, @posix_tz_parser)
285
- assert_equal('Zone/One', info.identifier)
286
-
287
- assert_period(:LMT, -12492, 0, false, nil, Time.utc(1971, 7, 9, 3, 0, 0), info)
288
- assert_period(:XST, -12000, 0, false, Time.utc(1971, 7, 9, 3, 0, 0), Time.utc(1972, 10, 12, 3, 0, 0), info)
289
- assert_period(:XDT, -12000, 3600, true, Time.utc(1972, 10, 12, 3, 0, 0), Time.utc(1973, 4, 29, 3, 0, 0), info)
290
- assert_period(:XST, -12000, 0, false, Time.utc(1973, 4, 29, 3, 0, 0), Time.utc(1992, 4, 1, 4, 30, 0), info)
291
- assert_period(:XNST, -8400, 0, false, Time.utc(1992, 4, 1, 4, 30, 0), nil, info)
292
- end
293
- end
294
-
295
- def test_load_dst_first
296
- offsets = [
297
- {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'},
298
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
299
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
300
- {:gmtoff => 0, :isdst => false, :abbrev => 'XNST'}]
301
-
302
- transitions = [
303
- {:at => Time.utc(1979, 1, 2), :offset_index => 2},
304
- {:at => Time.utc(1980, 4, 22), :offset_index => 0},
305
- {:at => Time.utc(1980, 10, 21), :offset_index => 2},
306
- {:at => Time.utc(2000, 12, 31), :offset_index => 3}]
307
-
308
- tzif_test(offsets, transitions) do |path, format|
309
- info = ZoneinfoTimezoneInfo.new('Zone/Two', path, @posix_tz_parser)
310
- assert_equal('Zone/Two', info.identifier)
311
-
312
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(1979, 1, 2), info)
313
- end
314
- end
315
-
316
- def test_load_no_transitions
317
- offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
318
-
319
- tzif_test(offsets, []) do |path, format|
320
- info = ZoneinfoTimezoneInfo.new('Zone/three', path, @posix_tz_parser)
321
- assert_equal('Zone/three', info.identifier)
322
-
323
- assert_period(:LT, -12094, 0, false, nil, nil, info)
324
- end
325
- end
326
-
327
- def test_load_no_offsets
328
- offsets = []
329
- transitions = [{:at => Time.utc(2000, 12, 31), :offset_index => 0}]
330
-
331
- tzif_test(offsets, transitions) do |path, format|
332
- assert_raises(InvalidZoneinfoFile) do
333
- ZoneinfoTimezoneInfo.new('Zone', path, @posix_tz_parser)
334
- end
335
- end
336
- end
337
-
338
- def test_load_invalid_offset_index
339
- offsets = [{:gmtoff => -0, :isdst => false, :abbrev => 'LMT'}]
340
- transitions = [{:at => Time.utc(2000, 12, 31), :offset_index => 2}]
341
-
342
- tzif_test(offsets, transitions) do |path, format|
343
- assert_raises(InvalidZoneinfoFile) do
344
- ZoneinfoTimezoneInfo.new('Zone', path, @posix_tz_parser)
345
- end
346
- end
347
- end
348
-
349
- def test_load_with_leap_seconds
350
- offsets = [{:gmtoff => -0, :isdst => false, :abbrev => 'LMT'}]
351
- leaps = [{:at => Time.utc(1972,6,30,23,59,60), :seconds => 1}]
352
-
353
- tzif_test(offsets, [], :leaps => leaps) do |path, format|
354
- assert_raises(InvalidZoneinfoFile) do
355
- ZoneinfoTimezoneInfo.new('Zone', path, @posix_tz_parser)
356
- end
357
- end
358
- end
359
-
360
- def test_load_invalid_magic
361
- ['TZif4', 'tzif2', '12345'].each do |magic|
362
- offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
363
-
364
- tzif_test(offsets, [], :magic => magic) do |path, format|
365
- assert_raises(InvalidZoneinfoFile) do
366
- ZoneinfoTimezoneInfo.new('Zone2', path, @posix_tz_parser)
367
- end
368
- end
369
- end
370
- end
371
-
372
- def test_load_invalid_section2_magic
373
- ['TZif4', 'tzif2', '12345'].each do |section2_magic|
374
- offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
375
-
376
- tzif_test(offsets, [], :min_format => 2, :section2_magic => section2_magic) do |path, format|
377
- assert_raises(InvalidZoneinfoFile) do
378
- ZoneinfoTimezoneInfo.new('Zone4', path, @posix_tz_parser)
379
- end
380
- end
381
- end
382
- end
383
-
384
- def test_load_mismatched_section2_magic
385
- minus_one = Proc.new {|f| f == 2 ? "TZif\0" : "TZif#{f - 1}" }
386
- plus_one = Proc.new {|f| "TZif#{f + 1}" }
387
-
388
- [minus_one, plus_one].each do |section2_magic|
389
- offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
390
-
391
- tzif_test(offsets, [], :min_format => 2, :section2_magic => section2_magic) do |path, format|
392
- assert_raises(InvalidZoneinfoFile) do
393
- ZoneinfoTimezoneInfo.new('Zone5', path, @posix_tz_parser)
394
- end
395
- end
396
- end
397
- end
398
-
399
- def test_load_invalid_format
400
- Tempfile.open('tzinfo-test-zone') do |file|
401
- file.write('Invalid')
402
- file.flush
403
-
404
- assert_raises(InvalidZoneinfoFile) do
405
- ZoneinfoTimezoneInfo.new('Zone3', file.path, @posix_tz_parser)
406
- end
407
- end
408
- end
409
-
410
- def test_load_missing_abbrev_null_termination
411
- offsets = [
412
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
413
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'}]
414
-
415
- transitions = [
416
- {:at => Time.utc(2000, 1, 1), :offset_index => 1}]
417
-
418
- tzif_test(offsets, transitions, :abbrev_separator => '^') do |path, format|
419
- assert_raises(InvalidZoneinfoFile) do
420
- ZoneinfoTimezoneInfo.new('Zone', path, @posix_tz_parser)
421
- end
422
- end
423
- end
424
-
425
- def test_load_out_of_range_abbrev_offsets
426
- offsets = [
427
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
428
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'}]
429
-
430
- transitions = [
431
- {:at => Time.utc(2000, 1, 1), :offset_index => 1}]
432
-
433
- tzif_test(offsets, transitions, :abbrev_offset_base => 8) do |path, format|
434
- assert_raises(InvalidZoneinfoFile) do
435
- ZoneinfoTimezoneInfo.new('Zone', path, @posix_tz_parser)
436
- end
437
- end
438
- end
439
-
440
- def test_load_before_epoch
441
- # Some platforms don't support negative timestamps for times before the
442
- # epoch. Check that they are returned when supported and skipped when not.
443
-
444
- # Note the last transition before the epoch (and within the 32-bit range) is
445
- # moved to the epoch on platforms that do not support negative timestamps.
446
-
447
- offsets = [
448
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
449
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
450
- {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'},
451
- {:gmtoff => 0, :isdst => false, :abbrev => 'XNST'}]
452
-
453
- transitions = [
454
- {:at => -694224000, :offset_index => 1}, # Time.utc(1948, 1, 2)
455
- {:at => -21945600, :offset_index => 2}, # Time.utc(1969, 4, 22)
456
- {:at => Time.utc(1970, 10, 21), :offset_index => 1},
457
- {:at => Time.utc(2000, 12, 31), :offset_index => 3}]
458
-
459
- tzif_test(offsets, transitions) do |path, format|
460
- info = ZoneinfoTimezoneInfo.new('Zone/Negative', path, @posix_tz_parser)
461
- assert_equal('Zone/Negative', info.identifier)
462
-
463
- if SUPPORTS_NEGATIVE
464
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(1948, 1, 2), info)
465
- assert_period(:XST, 3600, 0, false, Time.utc(1948, 1, 2), Time.utc(1969, 4, 22), info)
466
- assert_period(:XDT, 3600, 3600, true, Time.utc(1969, 4, 22), Time.utc(1970, 10, 21), info)
467
- else
468
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(1970, 1, 1), info)
469
- assert_period(:XDT, 3600, 3600, true, Time.utc(1970, 1, 1), Time.utc(1970, 10, 21), info)
470
- end
471
-
472
- assert_period(:XST, 3600, 0, false, Time.utc(1970, 10, 21), Time.utc(2000, 12, 31), info)
473
- assert_period(:XNST, 0, 0, false, Time.utc(2000, 12, 31), nil, info)
474
- end
475
- end
476
-
477
- def test_load_on_epoch
478
- offsets = [
479
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
480
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
481
- {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'},
482
- {:gmtoff => 0, :isdst => false, :abbrev => 'XNST'}]
483
-
484
- transitions = [
485
- {:at => -694224000, :offset_index => 1}, # Time.utc(1948, 1, 2)
486
- {:at => -21945600, :offset_index => 2}, # Time.utc(1969, 4, 22)
487
- {:at => Time.utc(1970, 1, 1), :offset_index => 1},
488
- {:at => Time.utc(2000, 12, 31), :offset_index => 3}]
489
-
490
- tzif_test(offsets, transitions) do |path, format|
491
- info = ZoneinfoTimezoneInfo.new('Zone/Negative', path, @posix_tz_parser)
492
- assert_equal('Zone/Negative', info.identifier)
493
-
494
- if SUPPORTS_NEGATIVE
495
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(1948, 1, 2), info)
496
- assert_period(:XST, 3600, 0, false, Time.utc(1948, 1, 2), Time.utc(1969, 4, 22), info)
497
- assert_period(:XDT, 3600, 3600, true, Time.utc(1969, 4, 22), Time.utc(1970, 1, 1), info)
498
- else
499
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(1970, 1, 1), info)
500
- end
501
-
502
- assert_period(:XST, 3600, 0, false, Time.utc(1970, 1, 1), Time.utc(2000, 12, 31), info)
503
- assert_period(:XNST, 0, 0, false, Time.utc(2000, 12, 31), nil, info)
504
- end
505
- end
506
-
507
- def test_load_64bit
508
- # The TZif version2 and later format contains both 32-bit and 64-bit
509
- # sections. The 64-bit section is always used.
510
- #
511
- # Negative transitions before the supported range are moved to the start of
512
- # the supported range.
513
- #
514
- # Transitions after 2**31 - 1 are discarded if 64-bit times aren't
515
- # supported.
516
-
517
- offsets = [
518
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
519
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
520
- {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'},
521
- {:gmtoff => 0, :isdst => false, :abbrev => 'XNST'}]
522
-
523
- transitions = [
524
- {:at => -3786739200, :offset_index => 1}, # Time.utc(1850, 1, 2)
525
- {:at => Time.utc(2003, 4, 22), :offset_index => 2},
526
- {:at => Time.utc(2003, 10, 21), :offset_index => 1},
527
- {:at => 2240524800, :offset_index => 3}] # Time.utc(2040, 12, 31)
528
-
529
- tzif_test(offsets, transitions) do |path, format|
530
- info = ZoneinfoTimezoneInfo.new('Zone/SixtyFour', path, @posix_tz_parser)
531
- assert_equal('Zone/SixtyFour', info.identifier)
532
-
533
- if SUPPORTS_64BIT && SUPPORTS_NEGATIVE && format >= 2
534
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(1850, 1, 2), info)
535
- assert_period(:XST, 3600, 0, false, Time.utc(1850, 1, 2), Time.utc(2003, 4, 22), info)
536
- assert_period(:XDT, 3600, 3600, true, Time.utc(2003, 4, 22), Time.utc(2003, 10, 21), info)
537
- assert_period(:XST, 3600, 0, false, Time.utc(2003, 10, 21), Time.utc(2040, 12, 31), info)
538
- assert_period(:XNST, 0, 0, false, Time.utc(2040, 12, 31), nil, info)
539
- elsif format < 2
540
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(2003, 4, 22), info)
541
- assert_period(:XDT, 3600, 3600, true, Time.utc(2003, 4, 22), Time.utc(2003, 10, 21), info)
542
- assert_period(:XST, 3600, 0, false, Time.utc(2003, 10, 21), nil, info)
543
- else
544
- min_supported = SUPPORTS_NEGATIVE ? -2**31 : 0
545
- assert_period(:LMT, 3542, 0, false, nil, Time.at(min_supported).utc, info)
546
- assert_period(:XST, 3600, 0, false, Time.at(min_supported).utc, Time.utc(2003, 4, 22), info)
547
- assert_period(:XDT, 3600, 3600, true, Time.utc(2003, 4, 22), Time.utc(2003, 10, 21), info)
548
- assert_period(:XST, 3600, 0, false, Time.utc(2003, 10, 21), nil, info)
549
- end
550
- end
551
- end
552
-
553
- def test_load_64bit_range
554
- # The full range of 64 bit timestamps is not currently supported because of
555
- # the way transitions are indexed. The last transition before the earliest
556
- # supported time will be moved to that time if there isn't already a
557
- # transition at that time. Transitions after the latest supported time are
558
- # ignored.
559
-
560
- offsets = [
561
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
562
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
563
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XNST'}]
564
-
565
- transitions = [
566
- {:at => -2**63, :offset_index => 1},
567
- {:at => Time.utc(2014, 5, 27), :offset_index => 2},
568
- {:at => 2**63 - 1, :offset_index => 0}]
569
-
570
- tzif_test(offsets, transitions) do |path, format|
571
- info = ZoneinfoTimezoneInfo.new('Zone/SixtyFourRange', path, @posix_tz_parser)
572
- assert_equal('Zone/SixtyFourRange', info.identifier)
573
-
574
- if SUPPORTS_64BIT && format >= 2
575
- # When the full range is supported, the following periods will be defined:
576
- #assert_period(:LMT, 3542, 0, false, nil, Time.at(-2**63).utc, info)
577
- #assert_period(:XST, 3600, 0, false, Time.at(-2**63).utc, Time.utc(2014, 5, 27), info)
578
- #assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), Time.at(2**63 - 1).utc, info)
579
- #assert_period(:LMT, 3542, 0, false, Time.at(2**63 - 1).utc, nil, info)
580
-
581
- # Without full range support, the following periods will be defined:
582
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(1700, 1, 1), info)
583
- assert_period(:XST, 3600, 0, false, Time.utc(1700, 1, 1), Time.utc(2014, 5, 27), info)
584
- assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
585
- elsif format < 2
586
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(2014, 5, 27), info)
587
- assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
588
- else
589
- min_supported = SUPPORTS_NEGATIVE ? -2**31 : 0
590
- assert_period(:LMT, 3542, 0, false, nil, Time.at(min_supported).utc, info)
591
- assert_period(:XST, 3600, 0, false, Time.at(min_supported).utc, Time.utc(2014, 5, 27), info)
592
- assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
593
- end
594
- end
595
- end
596
-
597
- def test_load_64bit_range_transition_at_earliest_supported
598
- # The full range of 64 bit timestamps is not currently supported because of
599
- # the way transitions are indexed. The last transition before the earliest
600
- # supported time will be moved to that time if there isn't already a
601
- # transition at that time. Transitions after the latest supported time are
602
- # ignored.
603
-
604
- offsets = [
605
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
606
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
607
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST2'},
608
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XNST'}]
609
-
610
- transitions = [
611
- {:at => -2**63, :offset_index => 1},
612
- {:at => -8520336000, :offset_index => 2}, # Time.utc(1700, 1, 1).to_i
613
- {:at => Time.utc(2014, 5, 27), :offset_index => 3},
614
- {:at => 2**63 - 1, :offset_index => 0}]
615
-
616
- tzif_test(offsets, transitions) do |path, format|
617
- info = ZoneinfoTimezoneInfo.new('Zone/SixtyFourRange', path, @posix_tz_parser)
618
- assert_equal('Zone/SixtyFourRange', info.identifier)
619
-
620
- if SUPPORTS_64BIT && format >= 2
621
- # When the full range is supported, the following periods will be defined:
622
- #assert_period(:LMT, 3542, 0, false, nil, Time.at(-2**63).utc, info)
623
- #assert_period(:XST, 3600, 0, false, Time.at(-2**63).utc, Time.utc(2014, 5, 27), info)
624
- #assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), Time.at(2**63 - 1).utc, info)
625
- #assert_period(:LMT, 3542, 0, false, Time.at(2**63 - 1).utc, nil, info)
626
-
627
- # Without full range support, the following periods will be defined:
628
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(1700, 1, 1), info)
629
- assert_period(:XST2, 3600, 0, false, Time.utc(1700, 1, 1), Time.utc(2014, 5, 27), info)
630
- assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
631
- elsif format < 2
632
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(2014, 5, 27), info)
633
- assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
634
- elsif SUPPORTS_NEGATIVE
635
- assert_period(:LMT, 3542, 0, false, nil, Time.at(-2**31).utc, info)
636
- assert_period(:XST, 3600, 0, false, Time.at(-2**31).utc, Time.utc(2014, 5, 27), info)
637
- assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
638
- else
639
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(1970, 1, 1), info)
640
- assert_period(:XST2, 3600, 0, false, Time.utc(1970, 1, 1), Time.utc(2014, 5, 27), info)
641
- assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
642
- end
643
- end
644
- end
645
-
646
- def test_load_supported_64bit_range
647
- # The full range of 64 bit timestamps is not currently supported because of
648
- # the way transitions are indexed.
649
-
650
- min_timestamp = -8520336000 # Time.utc(1700, 1, 1).to_i
651
- max_timestamp = 16725225600 # Time.utc(2500, 1, 1).to_i
652
-
653
- offsets = [
654
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
655
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
656
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XNST'}]
657
-
658
- transitions = [
659
- {:at => min_timestamp, :offset_index => 1},
660
- {:at => Time.utc(2014, 5, 27), :offset_index => 2},
661
- {:at => max_timestamp - 1, :offset_index => 0}]
662
-
663
- tzif_test(offsets, transitions) do |path, format|
664
- info = ZoneinfoTimezoneInfo.new('Zone/SupportedSixtyFourRange', path, @posix_tz_parser)
665
- assert_equal('Zone/SupportedSixtyFourRange', info.identifier)
666
-
667
- if SUPPORTS_64BIT && format >= 2
668
- assert_period(:LMT, 3542, 0, false, nil, Time.at(min_timestamp).utc, info)
669
- assert_period(:XST, 3600, 0, false, Time.at(min_timestamp).utc, Time.utc(2014, 5, 27), info)
670
- assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), Time.at(max_timestamp - 1).utc, info)
671
- assert_period(:LMT, 3542, 0, false, Time.at(max_timestamp - 1).utc, nil, info)
672
- elsif format < 2
673
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(2014, 5, 27), info)
674
- assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
675
- else
676
- min_supported = SUPPORTS_NEGATIVE ? -2**31 : 0
677
- assert_period(:LMT, 3542, 0, false, nil, Time.at(min_supported).utc, info)
678
- assert_period(:XST, 3600, 0, false, Time.at(min_supported).utc, Time.utc(2014, 5, 27), info)
679
- assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
680
- end
681
- end
682
- end
683
-
684
- def test_load_32bit_range
685
- offsets = [
686
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
687
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
688
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XNST'}]
689
-
690
- transitions = [
691
- {:at => -2**31, :offset_index => 1},
692
- {:at => Time.utc(2014, 5, 27), :offset_index => 2},
693
- {:at => 2**31 - 1, :offset_index => 0}]
694
-
695
- tzif_test(offsets, transitions) do |path, format|
696
- info = ZoneinfoTimezoneInfo.new('Zone/ThirtyTwoRange', path, @posix_tz_parser)
697
- assert_equal('Zone/ThirtyTwoRange', info.identifier)
698
-
699
- min_supported = SUPPORTS_NEGATIVE ? -2**31 : 0
700
- assert_period(:LMT, 3542, 0, false, nil, Time.at(min_supported).utc, info)
701
- assert_period(:XST, 3600, 0, false, Time.at(min_supported).utc, Time.utc(2014, 5, 27), info)
702
- assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), Time.at(2**31 - 1), info)
703
- assert_period(:LMT, 3542, 0, false, Time.at(2**31 - 1).utc, nil, info)
704
- end
705
- end
706
-
707
- def test_load_std_offset_changes
708
- # The zoneinfo files don't include the offset from standard time, so this
709
- # has to be derived by looking at changes in the total UTC offset.
710
-
711
- offsets = [
712
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
713
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
714
- {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'},
715
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDDT'}]
716
-
717
- transitions = [
718
- {:at => Time.utc(2000, 1, 1), :offset_index => 1},
719
- {:at => Time.utc(2000, 2, 1), :offset_index => 2},
720
- {:at => Time.utc(2000, 3, 1), :offset_index => 3},
721
- {:at => Time.utc(2000, 4, 1), :offset_index => 1}]
722
-
723
- tzif_test(offsets, transitions) do |path, format|
724
- info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path, @posix_tz_parser)
725
- assert_equal('Zone/DoubleDaylight', info.identifier)
726
-
727
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
728
- assert_period(:XST, 3600, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
729
- assert_period(:XDT, 3600, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
730
- assert_period(:XDDT, 3600, 7200, true, Time.utc(2000, 3, 1), Time.utc(2000, 4, 1), info)
731
- assert_period(:XST, 3600, 0, false, Time.utc(2000, 4, 1), nil, info)
732
- end
733
- end
734
-
735
- def test_load_std_offset_changes_jump_to_double_dst
736
- # The zoneinfo files don't include the offset from standard time, so this
737
- # has to be derived by looking at changes in the total UTC offset.
738
-
739
- offsets = [
740
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
741
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
742
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDDT'}]
743
-
744
- transitions = [
745
- {:at => Time.utc(2000, 4, 1), :offset_index => 1},
746
- {:at => Time.utc(2000, 5, 1), :offset_index => 2},
747
- {:at => Time.utc(2000, 6, 1), :offset_index => 1}]
748
-
749
- tzif_test(offsets, transitions) do |path, format|
750
- info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path, @posix_tz_parser)
751
- assert_equal('Zone/DoubleDaylight', info.identifier)
752
-
753
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(2000, 4, 1), info)
754
- assert_period(:XST, 3600, 0, false, Time.utc(2000, 4, 1), Time.utc(2000, 5, 1), info)
755
- assert_period(:XDDT, 3600, 7200, true, Time.utc(2000, 5, 1), Time.utc(2000, 6, 1), info)
756
- assert_period(:XST, 3600, 0, false, Time.utc(2000, 6, 1), nil, info)
757
- end
758
- end
759
-
760
- def test_load_std_offset_changes_negative
761
- # The zoneinfo files don't include the offset from standard time, so this
762
- # has to be derived by looking at changes in the total UTC offset.
763
-
764
- offsets = [
765
- {:gmtoff => -10821, :isdst => false, :abbrev => 'LMT'},
766
- {:gmtoff => -10800, :isdst => false, :abbrev => 'XST'},
767
- {:gmtoff => -7200, :isdst => true, :abbrev => 'XDT'},
768
- {:gmtoff => -3600, :isdst => true, :abbrev => 'XDDT'}]
769
-
770
- transitions = [
771
- {:at => Time.utc(2000, 1, 1), :offset_index => 1},
772
- {:at => Time.utc(2000, 2, 1), :offset_index => 2},
773
- {:at => Time.utc(2000, 3, 1), :offset_index => 3},
774
- {:at => Time.utc(2000, 4, 1), :offset_index => 1},
775
- {:at => Time.utc(2000, 5, 1), :offset_index => 3},
776
- {:at => Time.utc(2000, 6, 1), :offset_index => 1}]
777
-
778
- tzif_test(offsets, transitions) do |path, format|
779
- info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path, @posix_tz_parser)
780
- assert_equal('Zone/DoubleDaylight', info.identifier)
781
-
782
- assert_period(:LMT, -10821, 0, false, nil, Time.utc(2000, 1, 1), info)
783
- assert_period(:XST, -10800, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
784
- assert_period(:XDT, -10800, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
785
- assert_period(:XDDT, -10800, 7200, true, Time.utc(2000, 3, 1), Time.utc(2000, 4, 1), info)
786
- assert_period(:XST, -10800, 0, false, Time.utc(2000, 4, 1), Time.utc(2000, 5, 1), info)
787
- assert_period(:XDDT, -10800, 7200, true, Time.utc(2000, 5, 1), Time.utc(2000, 6, 1), info)
788
- assert_period(:XST, -10800, 0, false, Time.utc(2000, 6, 1), nil, info)
789
- end
790
- end
791
-
792
- def test_load_starts_two_hour_std_offset
793
- # The zoneinfo files don't include the offset from standard time, so this
794
- # has to be derived by looking at changes in the total UTC offset.
795
-
796
- offsets = [
797
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
798
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
799
- {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'},
800
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDDT'}]
801
-
802
- transitions = [
803
- {:at => Time.utc(2000, 1, 1), :offset_index => 3},
804
- {:at => Time.utc(2000, 2, 1), :offset_index => 2},
805
- {:at => Time.utc(2000, 3, 1), :offset_index => 1}]
806
-
807
- tzif_test(offsets, transitions) do |path, format|
808
- info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path, @posix_tz_parser)
809
- assert_equal('Zone/DoubleDaylight', info.identifier)
810
-
811
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
812
- assert_period(:XDDT, 3600, 7200, true, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
813
- assert_period(:XDT, 3600, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
814
- assert_period(:XST, 3600, 0, false, Time.utc(2000, 3, 1), nil, info)
815
- end
816
- end
817
-
818
- def test_load_starts_only_dst_transition_with_lmt
819
- # The zoneinfo files don't include the offset from standard time, so this
820
- # has to be derived by looking at changes in the total UTC offset.
821
-
822
- offsets = [
823
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
824
- {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'}]
825
-
826
- transitions = [{:at => Time.utc(2000, 1, 1), :offset_index => 1}]
827
-
828
- tzif_test(offsets, transitions) do |path, format|
829
- info = ZoneinfoTimezoneInfo.new('Zone/OnlyDST', path, @posix_tz_parser)
830
- assert_equal('Zone/OnlyDST', info.identifier)
831
-
832
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
833
- assert_period(:XDT, 3542, 3658, true, Time.utc(2000, 1, 1), nil, info)
834
- end
835
- end
836
-
837
- def test_load_starts_only_dst_transition_without_lmt
838
- # The zoneinfo files don't include the offset from standard time, so this
839
- # has to be derived by looking at changes in the total UTC offset.
840
-
841
- offsets = [{:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'}]
842
-
843
- transitions = [{:at => Time.utc(2000, 1, 1), :offset_index => 0}]
844
-
845
- tzif_test(offsets, transitions) do |path, format|
846
- info = ZoneinfoTimezoneInfo.new('Zone/OnlyDST', path, @posix_tz_parser)
847
- assert_equal('Zone/OnlyDST', info.identifier)
848
-
849
- assert_period(:XDT, 3600, 3600, true, nil, Time.utc(2000, 1, 1), info)
850
- assert_period(:XDT, 3600, 3600, true, Time.utc(2000, 1, 1), nil, info)
851
- end
852
- end
853
-
854
- def test_load_switch_to_dst_and_change_utc_offset
855
- # The zoneinfo files don't include the offset from standard time, so this
856
- # has to be derived by looking at changes in the total UTC offset.
857
-
858
- # Switch from non-DST to DST at the same time as moving the UTC offset
859
- # back an hour (i.e. wall clock time doesn't change).
860
-
861
- offsets = [
862
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
863
- {:gmtoff => 3600, :isdst => false, :abbrev => 'YST'},
864
- {:gmtoff => 3600, :isdst => true, :abbrev => 'XDT'}]
865
-
866
- transitions = [
867
- {:at => Time.utc(2000, 1, 1), :offset_index => 1},
868
- {:at => Time.utc(2000, 2, 1), :offset_index => 2}]
869
-
870
- tzif_test(offsets, transitions) do |path, format|
871
- info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path, @posix_tz_parser)
872
- assert_equal('Zone/DoubleDaylight', info.identifier)
873
-
874
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
875
- assert_period(:YST, 3600, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
876
- assert_period(:XDT, 0, 3600, true, Time.utc(2000, 2, 1), nil, info)
877
- end
878
- end
879
-
880
- def test_load_apia_international_dateline_change
881
- # The zoneinfo files don't include the offset from standard time, so this
882
- # has to be derived by looking at changes in the total UTC offset.
883
-
884
- # Pacific/Apia moved across the International Date Line whilst observing
885
- # daylight savings time.
886
-
887
- offsets = [
888
- {:gmtoff => 45184, :isdst => false, :abbrev => 'LMT'},
889
- {:gmtoff => -39600, :isdst => false, :abbrev => '-11'},
890
- {:gmtoff => -36000, :isdst => true, :abbrev => '-10'},
891
- {:gmtoff => 50400, :isdst => true, :abbrev => '+14'},
892
- {:gmtoff => 46800, :isdst => false, :abbrev => '+13'}]
893
-
894
- transitions = [
895
- {:at => Time.utc(2011, 4, 2, 14, 0, 0), :offset_index => 1},
896
- {:at => Time.utc(2011, 9, 24, 14, 0, 0), :offset_index => 2},
897
- {:at => Time.utc(2011, 12, 30, 10, 0, 0), :offset_index => 3},
898
- {:at => Time.utc(2012, 3, 31, 14, 0, 0), :offset_index => 4}]
899
-
900
- tzif_test(offsets, transitions) do |path, format|
901
- info = ZoneinfoTimezoneInfo.new('Test/Pacific/Apia', path, @posix_tz_parser)
902
- assert_equal('Test/Pacific/Apia', info.identifier)
903
-
904
- assert_period( :LMT, 45184, 0, false, nil, Time.utc(2011, 4, 2, 14, 0, 0), info)
905
- assert_period(:'-11', -39600, 0, false, Time.utc(2011, 4, 2, 14, 0, 0), Time.utc(2011, 9, 24, 14, 0, 0), info)
906
- assert_period(:'-10', -39600, 3600, true, Time.utc(2011, 9, 24, 14, 0, 0), Time.utc(2011, 12, 30, 10, 0, 0), info)
907
- assert_period(:'+14', 46800, 3600, true, Time.utc(2011, 12, 30, 10, 0, 0), Time.utc(2012, 3, 31, 14, 0, 0), info)
908
- assert_period(:'+13', 46800, 0, false, Time.utc(2012, 3, 31, 14, 0, 0), nil, info)
909
- end
910
- end
911
-
912
- def test_load_offset_split_for_different_utc_offset
913
- # The zoneinfo files don't include the offset from standard time, so this
914
- # has to be derived by looking at changes in the total UTC offset.
915
-
916
- offsets = [
917
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
918
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST1'},
919
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST2'},
920
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}]
921
-
922
- transitions = [
923
- {:at => Time.utc(2000, 1, 1), :offset_index => 1},
924
- {:at => Time.utc(2000, 2, 1), :offset_index => 3},
925
- {:at => Time.utc(2000, 3, 1), :offset_index => 1},
926
- {:at => Time.utc(2000, 4, 1), :offset_index => 2},
927
- {:at => Time.utc(2000, 5, 1), :offset_index => 3},
928
- {:at => Time.utc(2000, 6, 1), :offset_index => 2},
929
- {:at => Time.utc(2000, 7, 1), :offset_index => 1},
930
- {:at => Time.utc(2000, 8, 1), :offset_index => 3},
931
- {:at => Time.utc(2000, 9, 1), :offset_index => 1},
932
- {:at => Time.utc(2000, 10, 1), :offset_index => 2},
933
- {:at => Time.utc(2000, 11, 1), :offset_index => 3},
934
- {:at => Time.utc(2000, 12, 1), :offset_index => 2}]
935
-
936
- # XDT will be split and defined according to its surrounding standard time
937
- # offsets.
938
-
939
- tzif_test(offsets, transitions) do |path, format|
940
- info = ZoneinfoTimezoneInfo.new('Zone/SplitUtcOffset', path, @posix_tz_parser)
941
- assert_equal('Zone/SplitUtcOffset', info.identifier)
942
-
943
- assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
944
- assert_period(:XST1, 3600, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
945
- assert_period( :XDT, 3600, 7200, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
946
- assert_period(:XST1, 3600, 0, false, Time.utc(2000, 3, 1), Time.utc(2000, 4, 1), info)
947
- assert_period(:XST2, 7200, 0, false, Time.utc(2000, 4, 1), Time.utc(2000, 5, 1), info)
948
- assert_period( :XDT, 7200, 3600, true, Time.utc(2000, 5, 1), Time.utc(2000, 6, 1), info)
949
- assert_period(:XST2, 7200, 0, false, Time.utc(2000, 6, 1), Time.utc(2000, 7, 1), info)
950
- assert_period(:XST1, 3600, 0, false, Time.utc(2000, 7, 1), Time.utc(2000, 8, 1), info)
951
- assert_period( :XDT, 3600, 7200, true, Time.utc(2000, 8, 1), Time.utc(2000, 9, 1), info)
952
- assert_period(:XST1, 3600, 0, false, Time.utc(2000, 9, 1), Time.utc(2000, 10, 1), info)
953
- assert_period(:XST2, 7200, 0, false, Time.utc(2000, 10, 1), Time.utc(2000, 11, 1), info)
954
- assert_period( :XDT, 7200, 3600, true, Time.utc(2000, 11, 1), Time.utc(2000, 12, 1), info)
955
- assert_period(:XST2, 7200, 0, false, Time.utc(2000, 12, 1), nil, info)
956
-
957
- 1.upto(6) do |i|
958
- assert_same(info.period_for_utc(Time.utc(2000, i, 1)).offset, info.period_for_utc(Time.utc(2000, i + 6, 1)).offset)
959
- end
960
- end
961
- end
962
-
963
- def test_load_offset_utc_offset_taken_from_minimum_difference_minimum_after
964
- # The zoneinfo files don't include the offset from standard time, so this
965
- # has to be derived by looking at changes in the total UTC offset.
966
-
967
- offsets = [
968
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
969
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST1'},
970
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST2'},
971
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}]
972
-
973
- transitions = [
974
- {:at => Time.utc(2000, 1, 1), :offset_index => 1},
975
- {:at => Time.utc(2000, 2, 1), :offset_index => 3},
976
- {:at => Time.utc(2000, 3, 1), :offset_index => 2}]
977
-
978
- # XDT should use the closest utc_offset (7200) (and not an equivalent
979
- # utc_offset of 3600 and std_offset of 7200).
980
-
981
- tzif_test(offsets, transitions) do |path, format|
982
- info = ZoneinfoTimezoneInfo.new('Zone/MinimumUtcOffset', path, @posix_tz_parser)
983
- assert_equal('Zone/MinimumUtcOffset', info.identifier)
984
-
985
- assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
986
- assert_period(:XST1, 3600, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
987
- assert_period( :XDT, 7200, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
988
- assert_period(:XST2, 7200, 0, false, Time.utc(2000, 3, 1), nil, info)
989
- end
990
- end
991
-
992
- def test_load_offset_utc_offset_taken_from_minimum_difference_minimum_before
993
- # The zoneinfo files don't include the offset from standard time, so this
994
- # has to be derived by looking at changes in the total UTC offset.
995
-
996
- offsets = [
997
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
998
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST1'},
999
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST2'},
1000
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}]
1001
-
1002
- transitions = [
1003
- {:at => Time.utc(2000, 1, 1), :offset_index => 2},
1004
- {:at => Time.utc(2000, 2, 1), :offset_index => 3},
1005
- {:at => Time.utc(2000, 3, 1), :offset_index => 1}]
1006
-
1007
- # XDT should use the closest utc_offset (7200) (and not an equivalent
1008
- # utc_offset of 3600 and std_offset of 7200).
1009
-
1010
- tzif_test(offsets, transitions) do |path, format|
1011
- info = ZoneinfoTimezoneInfo.new('Zone/MinimumUtcOffset', path, @posix_tz_parser)
1012
- assert_equal('Zone/MinimumUtcOffset', info.identifier)
1013
-
1014
- assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
1015
- assert_period(:XST2, 7200, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
1016
- assert_period( :XDT, 7200, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
1017
- assert_period(:XST1, 3600, 0, false, Time.utc(2000, 3, 1), nil, info)
1018
- end
1019
- end
1020
-
1021
- def test_load_offset_does_not_use_equal_utc_total_offset_equal_after
1022
- # The zoneinfo files don't include the offset from standard time, so this
1023
- # has to be derived by looking at changes in the total UTC offset.
1024
-
1025
- offsets = [
1026
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
1027
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST1'},
1028
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST2'},
1029
- {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'}]
1030
-
1031
- transitions = [
1032
- {:at => Time.utc(2000, 1, 1), :offset_index => 1},
1033
- {:at => Time.utc(2000, 2, 1), :offset_index => 3},
1034
- {:at => Time.utc(2000, 3, 1), :offset_index => 2}]
1035
-
1036
- # XDT will be based on the utc_offset of XST1 even though XST2 has an
1037
- # equivalent (or greater) utc_total_offset.
1038
-
1039
- tzif_test(offsets, transitions) do |path, format|
1040
- info = ZoneinfoTimezoneInfo.new('Zone/UtcOffsetEqual', path, @posix_tz_parser)
1041
- assert_equal('Zone/UtcOffsetEqual', info.identifier)
1042
-
1043
- assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
1044
- assert_period(:XST1, 3600, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
1045
- assert_period( :XDT, 3600, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
1046
- assert_period(:XST2, 7200, 0, false, Time.utc(2000, 3, 1), nil, info)
1047
- end
1048
- end
1049
-
1050
- def test_load_offset_does_not_use_equal_utc_total_offset_equal_before
1051
- # The zoneinfo files don't include the offset from standard time, so this
1052
- # has to be derived by looking at changes in the total UTC offset.
1053
-
1054
- offsets = [
1055
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
1056
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST1'},
1057
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST2'},
1058
- {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'}]
1059
-
1060
- transitions = [
1061
- {:at => Time.utc(2000, 1, 1), :offset_index => 2},
1062
- {:at => Time.utc(2000, 2, 1), :offset_index => 3},
1063
- {:at => Time.utc(2000, 3, 1), :offset_index => 1}]
1064
-
1065
- # XDT will be based on the utc_offset of XST1 even though XST2 has an
1066
- # equivalent (or greater) utc_total_offset.
1067
-
1068
- tzif_test(offsets, transitions) do |path, format|
1069
- info = ZoneinfoTimezoneInfo.new('Zone/UtcOffsetEqual', path, @posix_tz_parser)
1070
- assert_equal('Zone/UtcOffsetEqual', info.identifier)
1071
-
1072
- assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
1073
- assert_period(:XST2, 7200, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
1074
- assert_period( :XDT, 3600, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
1075
- assert_period(:XST1, 3600, 0, false, Time.utc(2000, 3, 1), nil, info)
1076
- end
1077
- end
1078
-
1079
- def test_load_offset_both_adjacent_non_dst_equal_utc_total_offset
1080
- # The zoneinfo files don't include the offset from standard time, so this
1081
- # has to be derived by looking at changes in the total UTC offset.
1082
-
1083
- offsets = [
1084
- {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1085
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1086
- {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'}]
1087
-
1088
- transitions = [
1089
- {:at => Time.utc(2000, 1, 1), :offset_index => 1},
1090
- {:at => Time.utc(2000, 2, 1), :offset_index => 2},
1091
- {:at => Time.utc(2000, 3, 1), :offset_index => 1}]
1092
-
1093
- # XDT will just assume an std_offset of +1 hour and calculate the utc_offset
1094
- # from utc_total_offset - std_offset.
1095
-
1096
- tzif_test(offsets, transitions) do |path, format|
1097
- info = ZoneinfoTimezoneInfo.new('Zone/AdjacentEqual', path, @posix_tz_parser)
1098
- assert_equal('Zone/AdjacentEqual', info.identifier)
1099
-
1100
- assert_period(:LMT, 7142, 0, false, nil, Time.utc(2000, 1, 1), info)
1101
- assert_period(:XST, 7200, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
1102
- assert_period(:XDT, 3600, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
1103
- assert_period(:XST, 7200, 0, false, Time.utc(2000, 3, 1), nil, info)
1104
- end
1105
- end
1106
-
1107
- def test_load_offset_utc_offset_preserved_from_next
1108
- # The zoneinfo files don't include the offset from standard time, so this
1109
- # has to be derived by looking at changes in the total UTC offset.
1110
-
1111
- offsets = [
1112
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
1113
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST1'},
1114
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST2'},
1115
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT1'},
1116
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT2'}]
1117
-
1118
- transitions = [
1119
- {:at => Time.utc(2000, 1, 1), :offset_index => 1},
1120
- {:at => Time.utc(2000, 2, 1), :offset_index => 3},
1121
- {:at => Time.utc(2000, 3, 1), :offset_index => 4},
1122
- {:at => Time.utc(2000, 4, 1), :offset_index => 2}]
1123
-
1124
- # Both XDT1 and XDT2 should both use the closest utc_offset (7200) (and not
1125
- # an equivalent utc_offset of 3600 and std_offset of 7200).
1126
-
1127
- tzif_test(offsets, transitions) do |path, format|
1128
- info = ZoneinfoTimezoneInfo.new('Zone/UtcOffsetPreserved', path, @posix_tz_parser)
1129
- assert_equal('Zone/UtcOffsetPreserved', info.identifier)
1130
-
1131
- assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
1132
- assert_period(:XST1, 3600, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
1133
- assert_period(:XDT1, 7200, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
1134
- assert_period(:XDT2, 7200, 3600, true, Time.utc(2000, 3, 1), Time.utc(2000, 4, 1), info)
1135
- assert_period(:XST2, 7200, 0, false, Time.utc(2000, 4, 1), nil, info)
1136
- end
1137
- end
1138
-
1139
- def test_load_offset_utc_offset_preserved_from_previous
1140
- # The zoneinfo files don't include the offset from standard time, so this
1141
- # has to be derived by looking at changes in the total UTC offset.
1142
-
1143
- offsets = [
1144
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
1145
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST1'},
1146
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST2'},
1147
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT1'},
1148
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT2'}]
1149
-
1150
- transitions = [
1151
- {:at => Time.utc(2000, 1, 1), :offset_index => 2},
1152
- {:at => Time.utc(2000, 2, 1), :offset_index => 3},
1153
- {:at => Time.utc(2000, 3, 1), :offset_index => 4},
1154
- {:at => Time.utc(2000, 4, 1), :offset_index => 1}]
1155
-
1156
- # Both XDT1 and XDT2 should both use the closest utc_offset (7200) (and not
1157
- # an equivalent utc_offset of 3600 and std_offset of 7200).
1158
-
1159
- tzif_test(offsets, transitions) do |path, format|
1160
- info = ZoneinfoTimezoneInfo.new('Zone/UtcOffsetPreserved', path, @posix_tz_parser)
1161
- assert_equal('Zone/UtcOffsetPreserved', info.identifier)
1162
-
1163
- assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
1164
- assert_period(:XST2, 7200, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
1165
- assert_period(:XDT1, 7200, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
1166
- assert_period(:XDT2, 7200, 3600, true, Time.utc(2000, 3, 1), Time.utc(2000, 4, 1), info)
1167
- assert_period(:XST1, 3600, 0, false, Time.utc(2000, 4, 1), nil, info)
1168
- end
1169
- end
1170
-
1171
- def test_read_offset_negative_std_offset_dst
1172
- # The zoneinfo files don't include the offset from standard time, so this
1173
- # has to be derived by looking at changes in the total UTC offset.
1174
-
1175
- offsets = [
1176
- {:gmtoff => -100, :isdst => false, :abbrev => 'LMT'},
1177
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
1178
- {:gmtoff => 0, :isdst => true, :abbrev => 'XWT'}]
1179
-
1180
- transitions = [
1181
- {:at => Time.utc(2000, 1, 1), :offset_index => 1},
1182
- {:at => Time.utc(2000, 2, 1), :offset_index => 2},
1183
- {:at => Time.utc(2000, 3, 1), :offset_index => 1},
1184
- {:at => Time.utc(2000, 4, 1), :offset_index => 2},
1185
- {:at => Time.utc(2000, 5, 1), :offset_index => 1}]
1186
-
1187
- tzif_test(offsets, transitions) do |path, format|
1188
- info = ZoneinfoTimezoneInfo.new('Zone/NegativeStdOffsetDst', path, @posix_tz_parser)
1189
- assert_equal('Zone/NegativeStdOffsetDst', info.identifier)
1190
-
1191
- assert_period(:LMT, -100, 0, false, nil, Time.utc(2000, 1, 1), info)
1192
- assert_period(:XST, 3600, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
1193
- assert_period(:XWT, 3600, -3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
1194
- assert_period(:XST, 3600, 0, false, Time.utc(2000, 3, 1), Time.utc(2000, 4, 1), info)
1195
- assert_period(:XWT, 3600, -3600, true, Time.utc(2000, 4, 1), Time.utc(2000, 5, 1), info)
1196
- assert_period(:XST, 3600, 0, false, Time.utc(2000, 5, 1), nil, info)
1197
- end
1198
- end
1199
-
1200
- def test_read_offset_negative_std_offset_dst_initial_dst
1201
- # The zoneinfo files don't include the offset from standard time, so this
1202
- # has to be derived by looking at changes in the total UTC offset.
1203
-
1204
- offsets = [
1205
- {:gmtoff => -100, :isdst => false, :abbrev => 'LMT'},
1206
- {:gmtoff => 0, :isdst => true, :abbrev => 'XWT'},
1207
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'}]
1208
-
1209
- transitions = [
1210
- {:at => Time.utc(2000, 1, 1), :offset_index => 1},
1211
- {:at => Time.utc(2000, 2, 1), :offset_index => 2},
1212
- {:at => Time.utc(2000, 3, 1), :offset_index => 1},
1213
- {:at => Time.utc(2000, 4, 1), :offset_index => 2},
1214
- {:at => Time.utc(2000, 5, 1), :offset_index => 1}]
1215
-
1216
- tzif_test(offsets, transitions) do |path, format|
1217
- info = ZoneinfoTimezoneInfo.new('Zone/NegativeStdOffsetDstInitialDst', path, @posix_tz_parser)
1218
- assert_equal('Zone/NegativeStdOffsetDstInitialDst', info.identifier)
1219
-
1220
- assert_period(:LMT, -100, 0, false, nil, Time.utc(2000, 1, 1), info)
1221
- assert_period(:XWT, 3600, -3600, true, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
1222
- assert_period(:XST, 3600, 0, false, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
1223
- assert_period(:XWT, 3600, -3600, true, Time.utc(2000, 3, 1), Time.utc(2000, 4, 1), info)
1224
- assert_period(:XST, 3600, 0, false, Time.utc(2000, 4, 1), Time.utc(2000, 5, 1), info)
1225
- assert_period(:XWT, 3600, -3600, true, Time.utc(2000, 5, 1), nil, info)
1226
- end
1227
- end
1228
-
1229
- def test_read_offset_prefer_base_offset_moves_to_dst_not_hour
1230
- offsets = [
1231
- {:gmtoff => -100, :isdst => false, :abbrev => 'LMT'},
1232
- {:gmtoff => 0, :isdst => false, :abbrev => 'XST'},
1233
- {:gmtoff => 1800, :isdst => true, :abbrev => 'XDT'},
1234
- {:gmtoff => 1800, :isdst => false, :abbrev => 'XST'}]
1235
-
1236
- transitions = [
1237
- {:at => Time.utc(2000, 1, 1), :offset_index => 1},
1238
- {:at => Time.utc(2000, 2, 1), :offset_index => 2},
1239
- {:at => Time.utc(2000, 3, 1), :offset_index => 3}]
1240
-
1241
- tzif_test(offsets, transitions) do |path, format|
1242
- info = ZoneinfoTimezoneInfo.new('Zone/BaseOffsetMovesToDstNotHour', path, @posix_tz_parser)
1243
- assert_equal('Zone/BaseOffsetMovesToDstNotHour', info.identifier)
1244
-
1245
- assert_period(:LMT, -100, 0, false, nil, Time.utc(2000, 1, 1), info)
1246
- assert_period(:XST, 0, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
1247
- assert_period(:XDT, 0, 1800, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
1248
- assert_period(:XST, 1800, 0, false, Time.utc(2000, 3, 1), nil, info)
1249
- end
1250
- end
1251
-
1252
- def test_read_offset_prefer_base_offset_moves_from_dst_not_hour
1253
- offsets = [
1254
- {:gmtoff => -100, :isdst => false, :abbrev => 'LMT'},
1255
- {:gmtoff => 1800, :isdst => false, :abbrev => 'XST'},
1256
- {:gmtoff => 1800, :isdst => true, :abbrev => 'XDT'},
1257
- {:gmtoff => 0, :isdst => false, :abbrev => 'XST'}]
1258
-
1259
- transitions = [
1260
- {:at => Time.utc(2000, 1, 1), :offset_index => 1},
1261
- {:at => Time.utc(2000, 2, 1), :offset_index => 2},
1262
- {:at => Time.utc(2000, 3, 1), :offset_index => 3}]
1263
-
1264
- tzif_test(offsets, transitions) do |path, format|
1265
- info = ZoneinfoTimezoneInfo.new('Zone/BaseOffsetMovesFromDstNotHour', path, @posix_tz_parser)
1266
- assert_equal('Zone/BaseOffsetMovesFromDstNotHour', info.identifier)
1267
-
1268
- assert_period(:LMT, -100, 0, false, nil, Time.utc(2000, 1, 1), info)
1269
- assert_period(:XST, 1800, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
1270
- assert_period(:XDT, 0, 1800, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
1271
- assert_period(:XST, 0, 0, false, Time.utc(2000, 3, 1), nil, info)
1272
- end
1273
- end
1274
-
1275
- def test_load_in_safe_mode
1276
- offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
1277
-
1278
- tzif_test(offsets, []) do |path, format|
1279
- # untaint only required for Ruby 1.9.2
1280
- RubyCoreSupport.untaint(path)
1281
-
1282
- safe_test do
1283
- info = ZoneinfoTimezoneInfo.new('Zone/three', path, @posix_tz_parser)
1284
- assert_equal('Zone/three', info.identifier)
1285
-
1286
- assert_period(:LT, -12094, 0, false, nil, nil, info)
1287
- end
1288
- end
1289
- end
1290
-
1291
- def test_load_encoding
1292
- # tzfile.5 doesn't specify an encoding, but the source data is in ASCII.
1293
- # ZoneinfoTimezoneInfo will load as UTF-8 (a superset of ASCII).
1294
-
1295
- offsets = [
1296
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
1297
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST©'}]
1298
-
1299
- transitions = [
1300
- {:at => Time.utc(1971, 1, 2), :offset_index => 1}]
1301
-
1302
- tzif_test(offsets, transitions) do |path, format|
1303
- info = ZoneinfoTimezoneInfo.new('Zone/One', path, @posix_tz_parser)
1304
- assert_equal('Zone/One', info.identifier)
1305
-
1306
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(1971, 1, 2), info)
1307
- assert_period(:"XST©", 3600, 0, false, Time.utc(1971, 1, 2), nil, info)
1308
- end
1309
- end
1310
-
1311
- def test_load_binmode
1312
- offsets = [
1313
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
1314
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'}]
1315
-
1316
- # Transition time that includes CRLF (4EFF0D0A).
1317
- # Test that this doesn't get corrupted by translating CRLF to LF.
1318
- transitions = [
1319
- {:at => Time.utc(2011, 12, 31, 13, 24, 26), :offset_index => 1}]
1320
-
1321
- tzif_test(offsets, transitions) do |path, format|
1322
- info = ZoneinfoTimezoneInfo.new('Zone/One', path, @posix_tz_parser)
1323
- assert_equal('Zone/One', info.identifier)
1324
-
1325
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(2011, 12, 31, 13, 24, 26), info)
1326
- assert_period(:XST, 3600, 0, false, Time.utc(2011, 12, 31, 13, 24, 26), nil, info)
1327
- end
1328
- end
1329
-
1330
- def test_load_invalid_tz_string
1331
- offsets = [{:gmtoff => 0, :isdst => false, :abbrev => 'UTC'}]
1332
-
1333
- tzif_test(offsets, [], :rules => :fail) do |path, format|
1334
- error = assert_raises(InvalidZoneinfoFile) { ZoneinfoTimezoneInfo.new('Invalid/String', path, @posix_tz_parser) }
1335
- assert_equal("Failed to parse POSIX-style TZ string in file '#{path}': FakePosixTimeZoneParser Failure.", error.message)
1336
- end
1337
- end
1338
-
1339
- def test_load_tz_string_missing_start_newline
1340
- offsets = [{:gmtoff => 0, :isdst => false, :abbrev => 'UTC'}]
1341
- rules = TimezoneOffset.new(0, 0, 'UTC')
1342
-
1343
- tzif_test(offsets, [], :rules => rules, :omit_tz_string_start_new_line => true) do |path, format|
1344
- error = assert_raises(InvalidZoneinfoFile) { ZoneinfoTimezoneInfo.new('Missing/Start', path, @posix_tz_parser) }
1345
- assert_equal("Expected newline starting POSIX-style TZ string in file '#{path}'.", error.message)
1346
- end
1347
- end
1348
-
1349
- def test_load_tz_string_missing_end_newline
1350
- offsets = [{:gmtoff => 0, :isdst => false, :abbrev => 'UTC'}]
1351
- rules = TimezoneOffset.new(0, 0, 'UTC')
1352
-
1353
- tzif_test(offsets, [], :rules => rules, :omit_tz_string_end_new_line => true) do |path, format|
1354
- error = assert_raises(InvalidZoneinfoFile) { ZoneinfoTimezoneInfo.new('Missing/End', path, @posix_tz_parser) }
1355
- assert_equal("Expected newline ending POSIX-style TZ string in file '#{path}'.", error.message)
1356
- end
1357
- end
1358
-
1359
- [
1360
- [false, 1, 0, 'TEST'],
1361
- [false, 0, 1, 'TEST'],
1362
- [false, 0, 0, 'TEST2'],
1363
- [false, -1, 1, 'TEST'],
1364
- [true, 0, 0, 'TEST']
1365
- ].each do |(isdst, base_utc_offset, std_offset, abbreviation)|
1366
- define_method "test_load_tz_string_does_not_match_#{isdst ? 'dst' : 'std'}_constant_offset_#{base_utc_offset}_#{std_offset}_#{abbreviation}" do
1367
- offsets = [{:gmtoff => 0, :isdst => isdst, :abbrev => 'TEST'}]
1368
- rules = TimezoneOffset.new(base_utc_offset, std_offset, abbreviation)
1369
-
1370
- tzif_test(offsets, [], :rules => rules) do |path, format|
1371
- error = assert_raises(InvalidZoneinfoFile) { ZoneinfoTimezoneInfo.new('Offset/Mismatch', path, @posix_tz_parser) }
1372
- assert_equal("Constant offset POSIX-style TZ string does not match constant offset in file '#{path}'.", error.message)
1373
- end
1374
- end
1375
- end
1376
-
1377
- [
1378
- [3601, 'XST'],
1379
- [3600, 'YST']
1380
- ].each do |(base_utc_offset, abbreviation)|
1381
- define_method "test_load_tz_string_does_not_match_final_std_transition_offset_#{base_utc_offset}_#{abbreviation}" do
1382
- offsets = [
1383
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
1384
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
1385
- {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'}
1386
- ]
1387
-
1388
- transitions = [
1389
- {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 3542, :offset_index => 1},
1390
- {:at => Time.utc(1981, 4, 10, 2, 0, 0) - 3600, :offset_index => 2},
1391
- {:at => Time.utc(1981, 10, 27, 2, 0, 0) - 7200, :offset_index => 1}
1392
- ]
1393
-
1394
- rules = AnnualRules.new(
1395
- TimezoneOffset.new(base_utc_offset, 0, abbreviation),
1396
- TimezoneOffset.new(3600, 3600, 'XDT'),
1397
- JulianDayOfYearTransitionRule.new(100, 7200),
1398
- JulianDayOfYearTransitionRule.new(300, 7200)
1399
- )
1400
-
1401
- tzif_test(offsets, transitions, :rules => rules) do |path, format|
1402
- error = assert_raises(InvalidZoneinfoFile) { ZoneinfoTimezoneInfo.new('Offset/Mismatch', path, @posix_tz_parser) }
1403
- assert_equal("The first offset indicated by the POSIX-style TZ string did not match the final defined offset in file '#{path}'.", error.message)
1404
- end
1405
- end
1406
- end
1407
-
1408
- [
1409
- [3601, 0, 'XST'],
1410
- [3600, 1, 'XST'],
1411
- [3600, 0, 'YST']
1412
- ].each do |(base_utc_offset, std_offset, abbreviation)|
1413
- define_method "test_load_tz_string_does_not_match_final_dst_transition_offset_#{base_utc_offset}_#{std_offset}_#{abbreviation}" do
1414
- offsets = [
1415
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
1416
- {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
1417
- {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'}
1418
- ]
1419
-
1420
- transitions = [
1421
- {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 3542, :offset_index => 1},
1422
- {:at => Time.utc(1981, 4, 10, 2, 0, 0) - 3600, :offset_index => 2}
1423
- ]
1424
-
1425
- rules = AnnualRules.new(
1426
- TimezoneOffset.new(3600, 0, 'XST'),
1427
- TimezoneOffset.new(base_utc_offset, std_offset, abbreviation),
1428
- JulianDayOfYearTransitionRule.new(100, 7200),
1429
- JulianDayOfYearTransitionRule.new(300, 7200)
1430
- )
1431
-
1432
- tzif_test(offsets, transitions, :rules => rules) do |path, format|
1433
- error = assert_raises(InvalidZoneinfoFile) { ZoneinfoTimezoneInfo.new('Offset/Mismatch', path, @posix_tz_parser) }
1434
- assert_equal("The first offset indicated by the POSIX-style TZ string did not match the final defined offset in file '#{path}'.", error.message)
1435
- end
1436
- end
1437
- end
1438
-
1439
- [
1440
- [3600, 0],
1441
- [3600, 3600],
1442
- [10800, -3600]
1443
- ].each do |(base_utc_offset, std_offset)|
1444
- rules = TimezoneOffset.new(base_utc_offset, std_offset, 'TEST')
1445
-
1446
- define_method "test_load_tz_string_uses_constant_offset_with_no_transitions_#{base_utc_offset}_#{std_offset}" do
1447
- offsets = [{:gmtoff => base_utc_offset + std_offset, :isdst => std_offset != 0, :abbrev => 'TEST'}]
1448
-
1449
- tzif_test(offsets, [], :rules => rules) do |path, format|
1450
- info = ZoneinfoTimezoneInfo.new('Constant/Offset', path, @posix_tz_parser)
1451
- assert_equal('Constant/Offset', info.identifier)
1452
- assert_period(:TEST, base_utc_offset, std_offset, std_offset != 0, nil, nil, info)
1453
- end
1454
- end
1455
-
1456
- define_method "test_load_tz_string_uses_constant_offset_after_last_transition_#{base_utc_offset}_#{std_offset}" do
1457
- offsets = [
1458
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
1459
- {:gmtoff => base_utc_offset + std_offset, :isdst => std_offset != 0, :abbrev => 'TEST'}
1460
- ]
1461
-
1462
- transitions = [
1463
- {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 3542, :offset_index => 1}
1464
- ]
1465
-
1466
- t0 = Time.utc(1971, 1, 2, 2, 0, 0) - 3542
1467
-
1468
- tzif_test(offsets, transitions, :rules => rules) do |path, format|
1469
- info = ZoneinfoTimezoneInfo.new('Constant/After', path, @posix_tz_parser)
1470
- assert_equal('Constant/After', info.identifier)
1471
- assert_period(:LMT, 3542, 0, false, nil, t0, info)
1472
- assert_period(:TEST, base_utc_offset, std_offset, std_offset != 0, t0, nil, info)
1473
- end
1474
- end
1475
- end
1476
-
1477
- def test_load_tz_string_uses_rules_to_generate_all_transitions_when_none_defined
1478
- offsets = [{:gmtoff => 7200, :isdst => false, :abbrev => 'XST'}]
1479
-
1480
- rules = AnnualRules.new(
1481
- TimezoneOffset.new(7200, 0, 'XST'),
1482
- TimezoneOffset.new(7200, 3600, 'XDT'),
1483
- JulianDayOfYearTransitionRule.new(100, 3600),
1484
- JulianDayOfYearTransitionRule.new(300, 7200)
1485
- )
1486
-
1487
- generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1488
-
1489
- tzif_test(offsets, [], :rules => rules) do |path, format|
1490
- info = ZoneinfoTimezoneInfo.new('All/Rules', path, @posix_tz_parser)
1491
- assert_equal('All/Rules', info.identifier)
1492
-
1493
- assert_period(:XST, 7200, 0, false, nil, Time.utc(1970, 4, 10, 1, 0, 0) - 7200, info)
1494
-
1495
- 1970.upto(generate_up_to - 1).each do |year|
1496
- 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)
1497
- 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)
1498
- end
1499
-
1500
- 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)
1501
- assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1502
- end
1503
- end
1504
-
1505
- def test_load_tz_string_uses_rules_to_generate_all_transitions_when_none_defined_omitting_first_if_matches_first_offset
1506
- offsets = [{:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}]
1507
-
1508
- rules = AnnualRules.new(
1509
- TimezoneOffset.new(7200, 0, 'XST'),
1510
- TimezoneOffset.new(7200, 3600, 'XDT'),
1511
- JulianDayOfYearTransitionRule.new(100, 3600),
1512
- JulianDayOfYearTransitionRule.new(300, 7200)
1513
- )
1514
-
1515
- generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1516
-
1517
- tzif_test(offsets, [], :rules => rules) do |path, format|
1518
- info = ZoneinfoTimezoneInfo.new('All/Rules', path, @posix_tz_parser)
1519
- assert_equal('All/Rules', info.identifier)
1520
-
1521
- assert_period(:XDT, 7200, 3600, true, nil, Time.utc(1970, 10, 27, 2, 0, 0) - 10800, info)
1522
- 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)
1523
-
1524
- 1971.upto(generate_up_to - 1).each do |year|
1525
- 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)
1526
- 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)
1527
- end
1528
-
1529
- 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)
1530
- assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1531
- end
1532
- end
1533
-
1534
- def test_load_tz_string_uses_rules_to_generate_all_transitions_when_none_defined_with_previous_offset_of_first_matching_first_offset
1535
- offsets = [{:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'}]
1536
-
1537
- rules = AnnualRules.new(
1538
- TimezoneOffset.new(7200, 0, 'XST'),
1539
- TimezoneOffset.new(7200, 3600, 'XDT'),
1540
- JulianDayOfYearTransitionRule.new(100, 3600),
1541
- JulianDayOfYearTransitionRule.new(300, 7200)
1542
- )
1543
-
1544
- generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1545
-
1546
- tzif_test(offsets, [], :rules => rules) do |path, format|
1547
- info = ZoneinfoTimezoneInfo.new('All/Rules', path, @posix_tz_parser)
1548
- assert_equal('All/Rules', info.identifier)
1549
-
1550
- assert_period(:LMT, 7142, 0, false, nil, Time.utc(1970, 4, 10, 1, 0, 0) - 7200, info)
1551
-
1552
- 1970.upto(generate_up_to - 1).each do |year|
1553
- 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)
1554
- 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)
1555
- end
1556
-
1557
- 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)
1558
- assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1559
- end
1560
- end
1561
-
1562
- def test_load_tz_string_uses_rules_to_generate_all_transitions_when_none_defined_correcting_initial_offset
1563
- offsets = [{:gmtoff => 10800, :isdst => true, :abbrev => 'XDDT'}]
1564
-
1565
- rules = AnnualRules.new(
1566
- TimezoneOffset.new(3600, 0, 'XST'),
1567
- TimezoneOffset.new(3600, 7200, 'XDDT'),
1568
- JulianDayOfYearTransitionRule.new(100, 3600),
1569
- JulianDayOfYearTransitionRule.new(300, 7200)
1570
- )
1571
-
1572
- generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1573
-
1574
- tzif_test(offsets, [], :rules => rules) do |path, format|
1575
- info = ZoneinfoTimezoneInfo.new('All/Rules', path, @posix_tz_parser)
1576
- assert_equal('All/Rules', info.identifier)
1577
-
1578
- assert_period(:XDDT, 3600, 7200, true, nil, Time.utc(1970, 10, 27, 2, 0, 0) - 10800, info) # would be :XDT, 7200, 3600 otherwise
1579
- 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)
1580
-
1581
- 1971.upto(generate_up_to - 1).each do |year|
1582
- 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)
1583
- 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)
1584
- end
1585
-
1586
- 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)
1587
- assert_period(:XST, 3600, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1588
- end
1589
- end
1590
-
1591
- def test_load_tz_string_extends_transitions_starting_from_std_to_dst_following_year
1592
- offsets = [
1593
- {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1594
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1595
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
1596
- ]
1597
-
1598
- transitions = [
1599
- {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
1600
- {:at => Time.utc(1981, 4, 10, 1, 0, 0) - 7200, :offset_index => 2},
1601
- {:at => Time.utc(1981, 10, 27, 2, 0, 0) - 10800, :offset_index => 1}
1602
- ]
1603
-
1604
- rules = AnnualRules.new(
1605
- TimezoneOffset.new(7200, 0, 'XST'),
1606
- TimezoneOffset.new(7200, 3600, 'XDT'),
1607
- JulianDayOfYearTransitionRule.new(100, 3600),
1608
- JulianDayOfYearTransitionRule.new(300, 7200)
1609
- )
1610
-
1611
- generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1612
-
1613
- tzif_test(offsets, transitions, :rules => rules) do |path, format|
1614
- info = ZoneinfoTimezoneInfo.new('From/Rules', path, @posix_tz_parser)
1615
- assert_equal('From/Rules', info.identifier)
1616
-
1617
- assert_period(:LMT, 7142, 0, false, nil, Time.utc(1971, 1, 2, 2, 0, 0) - 7142, info)
1618
- 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)
1619
-
1620
- 1981.upto(generate_up_to - 1).each do |year|
1621
- 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)
1622
- 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)
1623
- end
1624
-
1625
- 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)
1626
- assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1627
- end
1628
- end
1629
-
1630
- def test_load_tz_string_extends_transitions_starting_from_dst_to_std_same_year
1631
- offsets = [
1632
- {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1633
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1634
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
1635
- ]
1636
-
1637
- transitions = [
1638
- {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
1639
- {:at => Time.utc(1981, 4, 10, 1, 0, 0) - 7200, :offset_index => 2},
1640
- {:at => Time.utc(1981, 10, 27, 2, 0, 0) - 10800, :offset_index => 1},
1641
- {:at => Time.utc(1982, 4, 10, 1, 0, 0) - 7200, :offset_index => 2}
1642
- ]
1643
-
1644
- rules = AnnualRules.new(
1645
- TimezoneOffset.new(7200, 0, 'XST'),
1646
- TimezoneOffset.new(7200, 3600, 'XDT'),
1647
- JulianDayOfYearTransitionRule.new(100, 3600),
1648
- JulianDayOfYearTransitionRule.new(300, 7200)
1649
- )
1650
-
1651
- generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1652
-
1653
- tzif_test(offsets, transitions, :rules => rules) do |path, format|
1654
- info = ZoneinfoTimezoneInfo.new('From/Rules', path, @posix_tz_parser)
1655
- assert_equal('From/Rules', info.identifier)
1656
-
1657
- assert_period(:LMT, 7142, 0, false, nil, Time.utc(1971, 1, 2, 2, 0, 0) - 7142, info)
1658
- 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)
1659
-
1660
- 1981.upto(generate_up_to - 1).each do |year|
1661
- 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)
1662
- 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)
1663
- end
1664
-
1665
- 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)
1666
- assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1667
- end
1668
- end
1669
-
1670
- def test_load_tz_string_extends_transitions_starting_from_dst_to_std_following_year
1671
- offsets = [
1672
- {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1673
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1674
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
1675
- ]
1676
-
1677
- transitions = [
1678
- {:at => Time.utc(1971, 1, 2, 1, 0, 0) - 7142, :offset_index => 1},
1679
- {:at => Time.utc(1981, 10, 27, 1, 0, 0) - 7200, :offset_index => 2},
1680
- {:at => Time.utc(1982, 4, 10, 2, 0, 0) - 10800, :offset_index => 1},
1681
- {:at => Time.utc(1982, 10, 27, 1, 0, 0) - 7200, :offset_index => 2}
1682
- ]
1683
-
1684
- rules = AnnualRules.new(
1685
- TimezoneOffset.new(7200, 0, 'XST'),
1686
- TimezoneOffset.new(7200, 3600, 'XDT'),
1687
- JulianDayOfYearTransitionRule.new(300, 3600),
1688
- JulianDayOfYearTransitionRule.new(100, 7200)
1689
- )
1690
-
1691
- generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1692
-
1693
- tzif_test(offsets, transitions, :rules => rules) do |path, format|
1694
- info = ZoneinfoTimezoneInfo.new('From/Rules', path, @posix_tz_parser)
1695
- assert_equal('From/Rules', info.identifier)
1696
-
1697
- assert_period(:LMT, 7142, 0, false, nil, Time.utc(1971, 1, 2, 1, 0, 0) - 7142, info)
1698
- 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)
1699
- 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)
1700
-
1701
- 1982.upto(generate_up_to - 1).each do |year|
1702
- 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)
1703
- 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)
1704
- end
1705
-
1706
- 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)
1707
- assert_period(:XDT, 7200, 3600, true, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1708
- end
1709
- end
1710
-
1711
- def test_load_tz_string_extends_transitions_starting_from_std_to_dst_same_year
1712
- offsets = [
1713
- {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1714
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1715
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
1716
- ]
1717
-
1718
- transitions = [
1719
- {:at => Time.utc(1971, 1, 2, 1, 0, 0) - 7142, :offset_index => 1},
1720
- {:at => Time.utc(1981, 10, 27, 1, 0, 0) - 7200, :offset_index => 2},
1721
- {:at => Time.utc(1982, 4, 10, 2, 0, 0) - 10800, :offset_index => 1},
1722
- {:at => Time.utc(1982, 10, 27, 1, 0, 0) - 7200, :offset_index => 2},
1723
- {:at => Time.utc(1983, 4, 10, 2, 0, 0) - 10800, :offset_index => 1}
1724
- ]
1725
-
1726
- rules = AnnualRules.new(
1727
- TimezoneOffset.new(7200, 0, 'XST'),
1728
- TimezoneOffset.new(7200, 3600, 'XDT'),
1729
- JulianDayOfYearTransitionRule.new(300, 3600),
1730
- JulianDayOfYearTransitionRule.new(100, 7200)
1731
- )
1732
-
1733
- generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1734
-
1735
- tzif_test(offsets, transitions, :rules => rules) do |path, format|
1736
- info = ZoneinfoTimezoneInfo.new('From/Rules', path, @posix_tz_parser)
1737
- assert_equal('From/Rules', info.identifier)
1738
-
1739
- assert_period(:LMT, 7142, 0, false, nil, Time.utc(1971, 1, 2, 1, 0, 0) - 7142, info)
1740
- 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)
1741
- 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)
1742
-
1743
- 1982.upto(generate_up_to - 1).each do |year|
1744
- 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)
1745
- 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)
1746
- end
1747
-
1748
- 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)
1749
- assert_period(:XDT, 7200, 3600, true, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1750
- end
1751
- end
1752
-
1753
- def test_load_tz_string_extends_transitions_negative_dst
1754
- offsets = [
1755
- {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1756
- {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'},
1757
- {:gmtoff => 10800, :isdst => false, :abbrev => 'XST'}
1758
- ]
1759
-
1760
- transitions = [
1761
- {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
1762
- {:at => Time.utc(1981, 4, 10, 1, 0, 0) - 7200, :offset_index => 2},
1763
- {:at => Time.utc(1981, 10, 27, 2, 0, 0) - 10800, :offset_index => 1}
1764
- ]
1765
-
1766
- rules = AnnualRules.new(
1767
- TimezoneOffset.new(10800, 0, 'XST'),
1768
- TimezoneOffset.new(10800, -3600, 'XDT'),
1769
- JulianDayOfYearTransitionRule.new(300, 7200),
1770
- JulianDayOfYearTransitionRule.new(100, 3600)
1771
- )
1772
-
1773
- generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1774
-
1775
- tzif_test(offsets, transitions, :rules => rules) do |path, format|
1776
- info = ZoneinfoTimezoneInfo.new('From/Rules', path, @posix_tz_parser)
1777
- assert_equal('From/Rules', info.identifier)
1778
-
1779
- assert_period(:LMT, 7142, 0, false, nil, Time.utc(1971, 1, 2, 2, 0, 0) - 7142, info)
1780
- 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)
1781
-
1782
- 1981.upto(generate_up_to - 1).each do |year|
1783
- 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)
1784
- 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)
1785
- end
1786
-
1787
- 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)
1788
- assert_period(:XDT, 10800, -3600, true, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1789
- end
1790
- end
1791
-
1792
- def test_load_tz_string_extends_single_transition_in_final_year
1793
- offsets = [
1794
- {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1795
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1796
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
1797
- ]
1798
-
1799
- generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1800
-
1801
- transitions = [
1802
- {:at => Time.utc( 1971, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
1803
- {:at => Time.utc(generate_up_to - 1, 4, 10, 1, 0, 0) - 7200, :offset_index => 2},
1804
- {:at => Time.utc(generate_up_to - 1, 10, 27, 2, 0, 0) - 10800, :offset_index => 1},
1805
- {:at => Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 7200, :offset_index => 2}
1806
- ]
1807
-
1808
- rules = AnnualRules.new(
1809
- TimezoneOffset.new(7200, 0, 'XST'),
1810
- TimezoneOffset.new(7200, 3600, 'XDT'),
1811
- JulianDayOfYearTransitionRule.new(100, 3600),
1812
- JulianDayOfYearTransitionRule.new(300, 7200)
1813
- )
1814
-
1815
- tzif_test(offsets, transitions, :rules => rules) do |path, format|
1816
- info = ZoneinfoTimezoneInfo.new('Final/Year', path, @posix_tz_parser)
1817
- assert_equal('Final/Year', info.identifier)
1818
-
1819
- assert_period(:LMT, 7142, 0, false, nil, Time.utc( 1971, 1, 2, 2, 0, 0) - 7142, info)
1820
- 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)
1821
- 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)
1822
- 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)
1823
- 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)
1824
- assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1825
- end
1826
- end
1827
-
1828
- def test_load_tz_string_adds_nothing_if_transitions_up_to_final_year
1829
- offsets = [
1830
- {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1831
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1832
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
1833
- ]
1834
-
1835
- generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1836
-
1837
- transitions = [
1838
- {:at => Time.utc( 1971, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
1839
- {:at => Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 7200, :offset_index => 2},
1840
- {:at => Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, :offset_index => 1},
1841
- ]
1842
-
1843
- rules = AnnualRules.new(
1844
- TimezoneOffset.new(7200, 0, 'XST'),
1845
- TimezoneOffset.new(7200, 3600, 'XDT'),
1846
- JulianDayOfYearTransitionRule.new(100, 3600),
1847
- JulianDayOfYearTransitionRule.new(300, 7200)
1848
- )
1849
-
1850
- tzif_test(offsets, transitions, :rules => rules) do |path, format|
1851
- info = ZoneinfoTimezoneInfo.new('Final/Year', path, @posix_tz_parser)
1852
- assert_equal('Final/Year', info.identifier)
1853
-
1854
- assert_period(:LMT, 7142, 0, false, nil, Time.utc( 1971, 1, 2, 2, 0, 0) - 7142, info)
1855
- 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)
1856
- assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1857
- end
1858
- end
1859
-
1860
- def test_load_tz_string_corrects_offset_of_final_transition
1861
- offsets = [
1862
- {:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
1863
- {:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'}]
1864
-
1865
- transitions = [{:at => Time.utc(2000, 4, 10, 1, 0, 0) - 3542, :offset_index => 1}]
1866
-
1867
- rules = AnnualRules.new(
1868
- TimezoneOffset.new(3600, 0, 'XST'),
1869
- TimezoneOffset.new(3600, 3600, 'XDT'),
1870
- JulianDayOfYearTransitionRule.new(100, 3600),
1871
- JulianDayOfYearTransitionRule.new(300, 7200)
1872
- )
1873
-
1874
- generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1875
-
1876
- tzif_test(offsets, transitions, :rules => rules) do |path, format|
1877
- info = ZoneinfoTimezoneInfo.new('Correct/Final', path, @posix_tz_parser)
1878
- assert_equal('Correct/Final', info.identifier)
1879
-
1880
- assert_period(:LMT, 3542, 0, false, nil, Time.utc(2000, 4, 10, 1, 0, 0) - 3542, info)
1881
- 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
1882
- 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)
1883
-
1884
- 2001.upto(generate_up_to - 1).each do |year|
1885
- 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)
1886
- 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)
1887
- end
1888
-
1889
- 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)
1890
- assert_period(:XST, 3600, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 7200, nil, info)
1891
- end
1892
- end
1893
-
1894
- def test_load_tz_string_specifies_transition_to_offset_of_final_transition_same_year_skip_dst_start
1895
- # TZInfo v1.2.8 considered this to be an error. However, this is a valid
1896
- # situation with Africa/Casablanca in 2018e.
1897
- #
1898
- # The last defined transitions are:
1899
- # At 2037-03-29 02:00Z change to WEST UTC+1
1900
- # At 2037-10-04 02:00Z change to WET UTC+0
1901
- #
1902
- # The rules define the end of DST to be at 03:00 local time on the last
1903
- # Sunday of October (2037-10-31). This later transition needs to be
1904
- # ignored.
1905
-
1906
- offsets = [
1907
- {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1908
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1909
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
1910
- ]
1911
-
1912
- transitions = [
1913
- {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
1914
- {:at => Time.utc(1981, 4, 10, 1, 0, 0) - 7200, :offset_index => 2},
1915
- {:at => Time.utc(1981, 10, 27, 2, 0, 0) - 10800, :offset_index => 1},
1916
- {:at => Time.utc(1982, 4, 10, 1, 0, 0) - 7200, :offset_index => 2}
1917
- ]
1918
-
1919
- rules = AnnualRules.new(
1920
- TimezoneOffset.new(7200, 0, 'XST'),
1921
- TimezoneOffset.new(7200, 3600, 'XDT'),
1922
- JulianDayOfYearTransitionRule.new(101, 3600),
1923
- JulianDayOfYearTransitionRule.new(300, 7200)
1924
- )
1925
-
1926
- generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1927
-
1928
- tzif_test(offsets, transitions, :rules => rules) do |path, format|
1929
- info = ZoneinfoTimezoneInfo.new('Ignore/Std', path, @posix_tz_parser)
1930
- assert_equal('Ignore/Std', info.identifier)
1931
-
1932
- assert_period(:LMT, 7142, 0, false, nil, Time.utc(1971, 1, 2, 2, 0, 0) - 7142, info)
1933
- 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)
1934
- assert_period(:XDT, 7200, 3600, true, Time.utc(1981, 4, 10, 1, 0, 0) - 7200, Time.utc(1981, 10, 27, 2, 0, 0) - 10800, info)
1935
- assert_period(:XST, 7200, 0, false, Time.utc(1981, 10, 27, 2, 0, 0) - 10800, Time.utc(1982, 4, 10, 1, 0, 0) - 7200, info)
1936
- assert_period(:XDT, 7200, 3600, true, Time.utc(1982, 4, 10, 1, 0, 0) - 7200, Time.utc(1982, 10, 27, 2, 0, 0) - 10800, info)
1937
-
1938
- 1983.upto(generate_up_to).each do |year|
1939
- assert_period(:XST, 7200, 0, false, Time.utc(year - 1, 10, 27, 2, 0, 0) - 10800, Time.utc(year, 4, 11, 1, 0, 0) - 7200, info)
1940
- assert_period(:XDT, 7200, 3600, true, Time.utc(year, 4, 11, 1, 0, 0) - 7200, Time.utc(year, 10, 27, 2, 0, 0) - 10800, info)
1941
- end
1942
-
1943
- assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
1944
- end
1945
- end
1946
-
1947
- def test_load_tz_string_specifies_transition_to_offset_of_final_transition_same_year_skip_dst_end
1948
- # TZInfo v1.2.8 considered this to be an error. However, this is a valid
1949
- # situation with Africa/Casablanca in 2018e.
1950
- #
1951
- # The last defined transitions are:
1952
- # At 2037-03-29 02:00Z change to WEST UTC+1
1953
- # At 2037-10-04 02:00Z change to WET UTC+0
1954
- #
1955
- # The rules define the end of DST to be at 03:00 local time on the last
1956
- # Sunday of October (2037-10-31). This later transition needs to be
1957
- # ignored.
1958
-
1959
- offsets = [
1960
- {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
1961
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
1962
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
1963
- ]
1964
-
1965
- transitions = [
1966
- {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
1967
- {:at => Time.utc(1981, 4, 10, 1, 0, 0) - 7200, :offset_index => 2},
1968
- {:at => Time.utc(1981, 10, 27, 2, 0, 0) - 10800, :offset_index => 1}
1969
- ]
1970
-
1971
- rules = AnnualRules.new(
1972
- TimezoneOffset.new(7200, 0, 'XST'),
1973
- TimezoneOffset.new(7200, 3600, 'XDT'),
1974
- JulianDayOfYearTransitionRule.new(100, 3600),
1975
- JulianDayOfYearTransitionRule.new(301, 7200)
1976
- )
1977
-
1978
- generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
1979
-
1980
- tzif_test(offsets, transitions, :rules => rules) do |path, format|
1981
- info = ZoneinfoTimezoneInfo.new('Ignore/Std', path, @posix_tz_parser)
1982
- assert_equal('Ignore/Std', info.identifier)
1983
-
1984
- assert_period(:LMT, 7142, 0, false, nil, Time.utc(1971, 1, 2, 2, 0, 0) - 7142, info)
1985
- 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)
1986
- assert_period(:XDT, 7200, 3600, true, Time.utc(1981, 4, 10, 1, 0, 0) - 7200, Time.utc(1981, 10, 27, 2, 0, 0) - 10800, info)
1987
- assert_period(:XST, 7200, 0, false, Time.utc(1981, 10, 27, 2, 0, 0) - 10800, Time.utc(1982, 4, 10, 1, 0, 0) - 7200, info)
1988
-
1989
- 1982.upto(generate_up_to - 1).each do |year|
1990
- assert_period(:XDT, 7200, 3600, true, Time.utc(year, 4, 10, 1, 0, 0) - 7200, Time.utc(year, 10, 28, 2, 0, 0) - 10800, info)
1991
- assert_period(:XST, 7200, 0, false, Time.utc(year, 10, 28, 2, 0, 0) - 10800, Time.utc(year + 1, 4, 10, 1, 0, 0) - 7200, info)
1992
- end
1993
-
1994
- assert_period(:XDT, 7200, 3600, true, Time.utc(generate_up_to, 4, 10, 1, 0, 0) - 7200, Time.utc(generate_up_to, 10, 28, 2, 0, 0) - 10800, info)
1995
- assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 28, 2, 0, 0) - 10800, nil, info)
1996
- end
1997
- end
1998
-
1999
- def test_load_tz_string_specifies_transition_to_offset_of_final_transition_following_year
2000
- offsets = [
2001
- {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
2002
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
2003
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
2004
- ]
2005
-
2006
- transitions = [
2007
- {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
2008
- {:at => Time.utc(1981, 10, 27, 2, 0, 0) - 7200, :offset_index => 2}
2009
- ]
2010
-
2011
- rules = AnnualRules.new(
2012
- TimezoneOffset.new(7200, 0, 'XST'),
2013
- TimezoneOffset.new(7200, 3600, 'XDT'),
2014
- JulianDayOfYearTransitionRule.new(100, 3600),
2015
- JulianDayOfYearTransitionRule.new(299, 7200)
2016
- )
2017
-
2018
- tzif_test(offsets, transitions, :rules => rules) do |path, format|
2019
- error = assert_raises(InvalidZoneinfoFile) { ZoneinfoTimezoneInfo.new('Invalid/Offset', path, @posix_tz_parser) }
2020
- assert_equal("The first offset indicated by the POSIX-style TZ string did not match the final defined offset in file '#{path}'.", error.message)
2021
- end
2022
- end
2023
-
2024
- unless SUPPORTS_64BIT
2025
- def test_generate_up_to_limited_to_2037_with_no_64_bit_support
2026
- assert_equal(2037, ZoneinfoTimezoneInfo::GENERATE_UP_TO)
2027
- end
2028
-
2029
- def test_load_tz_string_does_not_generate_if_transition_after_32_bit_range_with_no_64_bit_support
2030
- offsets = [
2031
- {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
2032
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
2033
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
2034
- ]
2035
-
2036
- transitions = [
2037
- {:at => Time.utc(1971, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
2038
- {:at => 2154474000 - 7200, :offset_index => 2}, # Time.utc(2038, 4, 10, 1, 0, 0).to_i
2039
- {:at => 2171757600 - 10800, :offset_index => 1} # Time.utc(2038, 10, 27, 2, 0, 0).to_i
2040
- ]
2041
-
2042
- rules = AnnualRules.new(
2043
- TimezoneOffset.new(7200, 0, 'XST'),
2044
- TimezoneOffset.new(7200, 3600, 'XDT'),
2045
- JulianDayOfYearTransitionRule.new(100, 3600),
2046
- JulianDayOfYearTransitionRule.new(300, 7200)
2047
- )
2048
-
2049
- tzif_test(offsets, transitions, :rules => rules) do |path, format|
2050
- info = ZoneinfoTimezoneInfo.new('From/Rules', path, @posix_tz_parser)
2051
- assert_equal('From/Rules', info.identifier)
2052
-
2053
- assert_period(:LMT, 7142, 0, false, nil, Time.utc(1971, 1, 2, 2, 0, 0) - 7142, info)
2054
- assert_period(:XST, 7200, 0, false, Time.utc(1971, 1, 2, 2, 0, 0) - 7142, nil, info)
2055
- end
2056
- end
2057
- end
2058
-
2059
- if SUPPORTS_NEGATIVE
2060
- def test_load_tz_string_generates_from_last_transition_if_before_1970_and_supports_negative
2061
- offsets = [
2062
- {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
2063
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
2064
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
2065
- ]
2066
-
2067
- transitions = [
2068
- {:at => Time.utc(1961, 1, 2, 2, 0, 0) - 7142, :offset_index => 1},
2069
- {:at => Time.utc(1962, 4, 10, 1, 0, 0) - 7200, :offset_index => 2},
2070
- {:at => Time.utc(1962, 10, 27, 2, 0, 0) - 10800, :offset_index => 1}
2071
- ]
2072
-
2073
- rules = AnnualRules.new(
2074
- TimezoneOffset.new(7200, 0, 'XST'),
2075
- TimezoneOffset.new(7200, 3600, 'XDT'),
2076
- JulianDayOfYearTransitionRule.new(100, 3600),
2077
- JulianDayOfYearTransitionRule.new(300, 7200)
2078
- )
2079
-
2080
- generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
2081
-
2082
- tzif_test(offsets, transitions, :rules => rules) do |path, format|
2083
- info = ZoneinfoTimezoneInfo.new('Pre/1970', path, @posix_tz_parser)
2084
- assert_equal('Pre/1970', info.identifier)
2085
-
2086
- assert_period(:LMT, 7142, 0, false, nil, Time.utc(1961, 1, 2, 2, 0, 0) - 7142, info)
2087
- 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)
2088
-
2089
- 1962.upto(generate_up_to - 1).each do |year|
2090
- 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)
2091
- 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)
2092
- end
2093
-
2094
- 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)
2095
- assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
2096
- end
2097
- end
2098
- else
2099
- def test_load_tz_string_generates_from_1970_if_last_transition_before_1970_and_does_not_support_negative
2100
- offsets = [
2101
- {:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
2102
- {:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
2103
- {:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}
2104
- ]
2105
-
2106
- transitions = [
2107
- {:at => -283903200 - 7142, :offset_index => 1}, # Time.utc(1961, 1, 2, 2, 0, 0)
2108
- {:at => -243903600 - 7200, :offset_index => 2}, # Time.utc(1962, 4, 10, 1, 0, 0)
2109
- {:at => -226620000 - 10800, :offset_index => 1} # Time.utc(1962, 10, 27, 2, 0, 0)
2110
- ]
2111
-
2112
- rules = AnnualRules.new(
2113
- TimezoneOffset.new(7200, 0, 'XST'),
2114
- TimezoneOffset.new(7200, 3600, 'XDT'),
2115
- JulianDayOfYearTransitionRule.new(100, 3600),
2116
- JulianDayOfYearTransitionRule.new(300, 7200)
2117
- )
2118
-
2119
- generate_up_to = ZoneinfoTimezoneInfo::GENERATE_UP_TO
2120
-
2121
- tzif_test(offsets, transitions, :rules => rules) do |path, format|
2122
- info = ZoneinfoTimezoneInfo.new('Pre/1970', path, @posix_tz_parser)
2123
- assert_equal('Pre/1970', info.identifier)
2124
-
2125
- assert_period(:LMT, 7142, 0, false, nil, Time.utc(1970, 1, 1), info)
2126
- assert_period(:XST, 7200, 0, false, Time.utc(1970, 1, 1), Time.utc(1970, 4, 10, 1, 0, 0) - 7200, info)
2127
-
2128
- 1970.upto(generate_up_to - 1).each do |year|
2129
- 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)
2130
- 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)
2131
- end
2132
-
2133
- 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)
2134
- assert_period(:XST, 7200, 0, false, Time.utc(generate_up_to, 10, 27, 2, 0, 0) - 10800, nil, info)
2135
- end
2136
- end
2137
- end
2138
-
2139
- def test_load_tz_string_as_utf8
2140
- offsets = [{:gmtoff => 3600, :isdst => false, :abbrev => 'áccént'}]
2141
- rules = TimezoneOffset.new(3600, 0, 'áccént')
2142
-
2143
- tzif_test(offsets, [], :tz_string => '<áccént>1', :rules => rules) do |path, format|
2144
- # FakePosixTimeZoneParser will test that the tz_string matches.
2145
- info = ZoneinfoTimezoneInfo.new('Test/Utf8', path, @posix_tz_parser)
2146
- assert_period(:'áccént', 3600, 0, false, nil, nil, info)
2147
- end
2148
- end
2149
- end