tzinfo 1.2.10 → 2.0.6

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