tzinfo 1.2.5
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of tzinfo might be problematic. Click here for more details.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +3 -0
- data.tar.gz.sig +0 -0
- data/.yardopts +6 -0
- data/CHANGES.md +786 -0
- data/LICENSE +19 -0
- data/README.md +151 -0
- data/Rakefile +107 -0
- data/lib/tzinfo.rb +40 -0
- data/lib/tzinfo/country.rb +196 -0
- data/lib/tzinfo/country_index_definition.rb +31 -0
- data/lib/tzinfo/country_info.rb +42 -0
- data/lib/tzinfo/country_timezone.rb +135 -0
- data/lib/tzinfo/data_source.rb +190 -0
- data/lib/tzinfo/data_timezone.rb +58 -0
- data/lib/tzinfo/data_timezone_info.rb +55 -0
- data/lib/tzinfo/info_timezone.rb +30 -0
- data/lib/tzinfo/linked_timezone.rb +63 -0
- data/lib/tzinfo/linked_timezone_info.rb +26 -0
- data/lib/tzinfo/offset_rationals.rb +77 -0
- data/lib/tzinfo/ruby_core_support.rb +146 -0
- data/lib/tzinfo/ruby_country_info.rb +74 -0
- data/lib/tzinfo/ruby_data_source.rb +136 -0
- data/lib/tzinfo/time_or_datetime.rb +340 -0
- data/lib/tzinfo/timezone.rb +669 -0
- data/lib/tzinfo/timezone_definition.rb +36 -0
- data/lib/tzinfo/timezone_index_definition.rb +54 -0
- data/lib/tzinfo/timezone_info.rb +30 -0
- data/lib/tzinfo/timezone_offset.rb +101 -0
- data/lib/tzinfo/timezone_period.rb +245 -0
- data/lib/tzinfo/timezone_proxy.rb +105 -0
- data/lib/tzinfo/timezone_transition.rb +130 -0
- data/lib/tzinfo/timezone_transition_definition.rb +104 -0
- data/lib/tzinfo/transition_data_timezone_info.rb +274 -0
- data/lib/tzinfo/zoneinfo_country_info.rb +37 -0
- data/lib/tzinfo/zoneinfo_data_source.rb +488 -0
- data/lib/tzinfo/zoneinfo_timezone_info.rb +296 -0
- data/test/tc_country.rb +234 -0
- data/test/tc_country_index_definition.rb +69 -0
- data/test/tc_country_info.rb +16 -0
- data/test/tc_country_timezone.rb +173 -0
- data/test/tc_data_source.rb +218 -0
- data/test/tc_data_timezone.rb +99 -0
- data/test/tc_data_timezone_info.rb +18 -0
- data/test/tc_info_timezone.rb +34 -0
- data/test/tc_linked_timezone.rb +155 -0
- data/test/tc_linked_timezone_info.rb +23 -0
- data/test/tc_offset_rationals.rb +23 -0
- data/test/tc_ruby_core_support.rb +168 -0
- data/test/tc_ruby_country_info.rb +110 -0
- data/test/tc_ruby_data_source.rb +143 -0
- data/test/tc_time_or_datetime.rb +654 -0
- data/test/tc_timezone.rb +1350 -0
- data/test/tc_timezone_definition.rb +113 -0
- data/test/tc_timezone_index_definition.rb +73 -0
- data/test/tc_timezone_info.rb +11 -0
- data/test/tc_timezone_london.rb +143 -0
- data/test/tc_timezone_melbourne.rb +142 -0
- data/test/tc_timezone_new_york.rb +142 -0
- data/test/tc_timezone_offset.rb +126 -0
- data/test/tc_timezone_period.rb +555 -0
- data/test/tc_timezone_proxy.rb +136 -0
- data/test/tc_timezone_transition.rb +366 -0
- data/test/tc_timezone_transition_definition.rb +295 -0
- data/test/tc_timezone_utc.rb +27 -0
- data/test/tc_transition_data_timezone_info.rb +423 -0
- data/test/tc_zoneinfo_country_info.rb +78 -0
- data/test/tc_zoneinfo_data_source.rb +1195 -0
- data/test/tc_zoneinfo_timezone_info.rb +1232 -0
- data/test/test_utils.rb +163 -0
- data/test/ts_all.rb +7 -0
- data/test/ts_all_ruby.rb +5 -0
- data/test/ts_all_zoneinfo.rb +7 -0
- data/test/tzinfo-data/tzinfo/data.rb +8 -0
- data/test/tzinfo-data/tzinfo/data/definitions/America/Argentina/Buenos_Aires.rb +89 -0
- data/test/tzinfo-data/tzinfo/data/definitions/America/New_York.rb +315 -0
- data/test/tzinfo-data/tzinfo/data/definitions/Australia/Melbourne.rb +218 -0
- data/test/tzinfo-data/tzinfo/data/definitions/EST.rb +19 -0
- data/test/tzinfo-data/tzinfo/data/definitions/Etc/GMT__m__1.rb +21 -0
- data/test/tzinfo-data/tzinfo/data/definitions/Etc/GMT__p__1.rb +21 -0
- data/test/tzinfo-data/tzinfo/data/definitions/Etc/UTC.rb +21 -0
- data/test/tzinfo-data/tzinfo/data/definitions/Europe/Amsterdam.rb +261 -0
- data/test/tzinfo-data/tzinfo/data/definitions/Europe/Andorra.rb +186 -0
- data/test/tzinfo-data/tzinfo/data/definitions/Europe/London.rb +321 -0
- data/test/tzinfo-data/tzinfo/data/definitions/Europe/Paris.rb +265 -0
- data/test/tzinfo-data/tzinfo/data/definitions/Europe/Prague.rb +220 -0
- data/test/tzinfo-data/tzinfo/data/definitions/UTC.rb +16 -0
- data/test/tzinfo-data/tzinfo/data/indexes/countries.rb +927 -0
- data/test/tzinfo-data/tzinfo/data/indexes/timezones.rb +596 -0
- data/test/tzinfo-data/tzinfo/data/version.rb +14 -0
- data/test/zoneinfo/America/Argentina/Buenos_Aires +0 -0
- data/test/zoneinfo/America/New_York +0 -0
- data/test/zoneinfo/Australia/Melbourne +0 -0
- data/test/zoneinfo/EST +0 -0
- data/test/zoneinfo/Etc/UTC +0 -0
- data/test/zoneinfo/Europe/Amsterdam +0 -0
- data/test/zoneinfo/Europe/Andorra +0 -0
- data/test/zoneinfo/Europe/London +0 -0
- data/test/zoneinfo/Europe/Paris +0 -0
- data/test/zoneinfo/Europe/Prague +0 -0
- data/test/zoneinfo/Factory +0 -0
- data/test/zoneinfo/iso3166.tab +275 -0
- data/test/zoneinfo/leapseconds +61 -0
- data/test/zoneinfo/posix/Europe/London +0 -0
- data/test/zoneinfo/posixrules +0 -0
- data/test/zoneinfo/right/Europe/London +0 -0
- data/test/zoneinfo/zone.tab +439 -0
- data/test/zoneinfo/zone1970.tab +369 -0
- data/tzinfo.gemspec +21 -0
- metadata +193 -0
- metadata.gz.sig +2 -0
@@ -0,0 +1,1232 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), 'test_utils')
|
4
|
+
require 'tempfile'
|
5
|
+
|
6
|
+
include TZInfo
|
7
|
+
|
8
|
+
class TCZoneinfoTimezoneInfo < Minitest::Test
|
9
|
+
|
10
|
+
begin
|
11
|
+
Time.at(-2147483649)
|
12
|
+
Time.at(2147483648)
|
13
|
+
SUPPORTS_64BIT = true
|
14
|
+
rescue RangeError
|
15
|
+
SUPPORTS_64BIT = false
|
16
|
+
end
|
17
|
+
|
18
|
+
begin
|
19
|
+
Time.at(-1)
|
20
|
+
Time.at(-2147483648)
|
21
|
+
SUPPORTS_NEGATIVE = true
|
22
|
+
rescue ArgumentError
|
23
|
+
SUPPORTS_NEGATIVE = false
|
24
|
+
end
|
25
|
+
|
26
|
+
def assert_period(abbreviation, utc_offset, std_offset, dst, start_at, end_at, info)
|
27
|
+
if start_at
|
28
|
+
period = info.period_for_utc(start_at)
|
29
|
+
elsif end_at
|
30
|
+
period = info.period_for_utc(TimeOrDateTime.wrap(end_at).add_with_convert(-1).to_orig)
|
31
|
+
else
|
32
|
+
# no transitions, pick the epoch
|
33
|
+
period = info.period_for_utc(Time.utc(1970, 1, 1))
|
34
|
+
end
|
35
|
+
|
36
|
+
assert_equal(abbreviation, period.abbreviation)
|
37
|
+
assert_equal(utc_offset, period.utc_offset)
|
38
|
+
assert_equal(std_offset, period.std_offset)
|
39
|
+
assert_equal(dst, period.dst?)
|
40
|
+
|
41
|
+
if start_at
|
42
|
+
refute_nil(period.utc_start_time)
|
43
|
+
assert_equal(start_at, period.utc_start_time)
|
44
|
+
else
|
45
|
+
assert_nil(period.utc_start_time)
|
46
|
+
end
|
47
|
+
|
48
|
+
if end_at
|
49
|
+
refute_nil(period.utc_end_time)
|
50
|
+
assert_equal(end_at, period.utc_end_time)
|
51
|
+
else
|
52
|
+
assert_nil(period.utc_end_time)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def convert_times_to_i(items, key = :at)
|
57
|
+
items.each do |item|
|
58
|
+
if item[key].kind_of?(Time)
|
59
|
+
item[key] = item[key].utc.to_i
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def select_with_32bit_values(items, key = :at)
|
65
|
+
items.select do |item|
|
66
|
+
i = item[key]
|
67
|
+
i >= -2147483648 && i <= 2147483647
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def pack_int64_network_order(values)
|
72
|
+
values.collect {|value| [value >> 32, value & 0xFFFFFFFF]}.flatten.pack('NN' * values.length)
|
73
|
+
end
|
74
|
+
|
75
|
+
def pack_int64_signed_network_order(values)
|
76
|
+
# Convert to the equivalent 64-bit unsigned integer with the same bit representation
|
77
|
+
pack_int64_network_order(values.collect {|value| value < 0 ? value + 0x10000000000000000 : value})
|
78
|
+
end
|
79
|
+
|
80
|
+
def write_tzif(format, offsets, transitions, leaps = [], options = {})
|
81
|
+
|
82
|
+
# Options for testing malformed zoneinfo files.
|
83
|
+
magic = options[:magic]
|
84
|
+
section2_magic = options[:section2_magic]
|
85
|
+
abbrev_separator = options[:abbrev_separator] || "\0"
|
86
|
+
abbrev_offset_base = options[:abbrev_offset_base] || 0
|
87
|
+
|
88
|
+
unless magic
|
89
|
+
if format == 1
|
90
|
+
magic = "TZif\0"
|
91
|
+
elsif format >= 2
|
92
|
+
magic = "TZif#{format}"
|
93
|
+
else
|
94
|
+
raise ArgumentError, 'Invalid format specified'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
if section2_magic.kind_of?(Proc)
|
99
|
+
section2_magic = section2_magic.call(format)
|
100
|
+
else
|
101
|
+
section2_magic = magic unless section2_magic
|
102
|
+
end
|
103
|
+
|
104
|
+
convert_times_to_i(transitions)
|
105
|
+
convert_times_to_i(leaps)
|
106
|
+
|
107
|
+
abbrevs = offsets.collect {|o| o[:abbrev]}.uniq
|
108
|
+
|
109
|
+
if abbrevs.length > 0
|
110
|
+
abbrevs = abbrevs.collect {|a| a.encode('UTF-8')} if abbrevs.first.respond_to?(:encode)
|
111
|
+
|
112
|
+
if abbrevs.first.respond_to?(:bytesize)
|
113
|
+
abbrevs_length = abbrevs.inject(0) {|sum, a| sum + a.bytesize + abbrev_separator.bytesize}
|
114
|
+
else
|
115
|
+
abbrevs_length = abbrevs.inject(0) {|sum, a| sum + a.length + abbrev_separator.length}
|
116
|
+
end
|
117
|
+
else
|
118
|
+
abbrevs_length = 0
|
119
|
+
end
|
120
|
+
|
121
|
+
b32_transitions = select_with_32bit_values(transitions)
|
122
|
+
b32_leaps = select_with_32bit_values(leaps)
|
123
|
+
|
124
|
+
Tempfile.open('tzinfo-test-zone') do |file|
|
125
|
+
file.binmode
|
126
|
+
|
127
|
+
file.write(
|
128
|
+
[magic, offsets.length, offsets.length, leaps.length,
|
129
|
+
b32_transitions.length, offsets.length, abbrevs_length].pack('a5 x15 NNNNNN'))
|
130
|
+
|
131
|
+
unless b32_transitions.empty?
|
132
|
+
file.write(b32_transitions.collect {|t| t[:at]}.pack('N' * b32_transitions.length))
|
133
|
+
file.write(b32_transitions.collect {|t| t[:offset_index]}.pack('C' * b32_transitions.length))
|
134
|
+
end
|
135
|
+
|
136
|
+
offsets.each do |offset|
|
137
|
+
index = abbrevs.index(offset[:abbrev])
|
138
|
+
abbrev_offset = abbrev_offset_base
|
139
|
+
0.upto(index - 1) {|i| abbrev_offset += abbrevs[i].length + 1}
|
140
|
+
|
141
|
+
file.write([offset[:gmtoff], offset[:isdst] ? 1 : 0, abbrev_offset].pack('NCC'))
|
142
|
+
end
|
143
|
+
|
144
|
+
abbrevs.each do |a|
|
145
|
+
file.write(a)
|
146
|
+
file.write(abbrev_separator)
|
147
|
+
end
|
148
|
+
|
149
|
+
b32_leaps.each do |leap|
|
150
|
+
file.write([leap[:at], leap[:seconds]].pack('NN'))
|
151
|
+
end
|
152
|
+
|
153
|
+
unless offsets.empty?
|
154
|
+
file.write("\0" * offsets.length * 2)
|
155
|
+
end
|
156
|
+
|
157
|
+
if format >= 2
|
158
|
+
file.write(
|
159
|
+
[section2_magic, offsets.length, offsets.length, leaps.length,
|
160
|
+
transitions.length, offsets.length, abbrevs_length].pack('a5 x15 NNNNNN'))
|
161
|
+
|
162
|
+
unless transitions.empty?
|
163
|
+
file.write(pack_int64_signed_network_order(transitions.collect {|t| t[:at]}))
|
164
|
+
file.write(transitions.collect {|t| t[:offset_index]}.pack('C' * transitions.length))
|
165
|
+
end
|
166
|
+
|
167
|
+
offsets.each do |offset|
|
168
|
+
index = abbrevs.index(offset[:abbrev])
|
169
|
+
abbrev_offset = abbrev_offset_base
|
170
|
+
0.upto(index - 1) {|i| abbrev_offset += abbrevs[i].length + 1}
|
171
|
+
|
172
|
+
file.write([offset[:gmtoff], offset[:isdst] ? 1 : 0, abbrev_offset].pack('NCC'))
|
173
|
+
end
|
174
|
+
|
175
|
+
abbrevs.each do |a|
|
176
|
+
file.write(a)
|
177
|
+
file.write(abbrev_separator)
|
178
|
+
end
|
179
|
+
|
180
|
+
leaps.each do |leap|
|
181
|
+
file.write(pack_int64_signed_network_order([leap[:at]]))
|
182
|
+
file.write([leap[:seconds]].pack('N'))
|
183
|
+
end
|
184
|
+
|
185
|
+
unless offsets.empty?
|
186
|
+
file.write("\0" * offsets.length * 2)
|
187
|
+
end
|
188
|
+
|
189
|
+
# Empty POSIX timezone string
|
190
|
+
file.write("\n\n")
|
191
|
+
end
|
192
|
+
|
193
|
+
file.flush
|
194
|
+
|
195
|
+
yield file.path, format
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def tzif_test(offsets, transitions, leaps = [], options = {}, &block)
|
200
|
+
min_format = options[:min_format] || 1
|
201
|
+
|
202
|
+
min_format.upto(3) do |format|
|
203
|
+
write_tzif(format, offsets, transitions, leaps, options, &block)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_load
|
208
|
+
offsets = [
|
209
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
210
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
|
211
|
+
{:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'},
|
212
|
+
{:gmtoff => 0, :isdst => false, :abbrev => 'XNST'}]
|
213
|
+
|
214
|
+
transitions = [
|
215
|
+
{:at => Time.utc(1971, 1, 2), :offset_index => 1},
|
216
|
+
{:at => Time.utc(1980, 4, 22), :offset_index => 2},
|
217
|
+
{:at => Time.utc(1980, 10, 21), :offset_index => 1},
|
218
|
+
{:at => Time.utc(2000, 12, 31), :offset_index => 3}]
|
219
|
+
|
220
|
+
tzif_test(offsets, transitions) do |path, format|
|
221
|
+
info = ZoneinfoTimezoneInfo.new('Zone/One', path)
|
222
|
+
assert_equal('Zone/One', info.identifier)
|
223
|
+
|
224
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.utc(1971, 1, 2), info)
|
225
|
+
assert_period(:XST, 3600, 0, false, Time.utc(1971, 1, 2), Time.utc(1980, 4, 22), info)
|
226
|
+
assert_period(:XDT, 3600, 3600, true, Time.utc(1980, 4, 22), Time.utc(1980, 10, 21), info)
|
227
|
+
assert_period(:XST, 3600, 0, false, Time.utc(1980, 10, 21), Time.utc(2000, 12, 31), info)
|
228
|
+
assert_period(:XNST, 0, 0, false, Time.utc(2000, 12, 31), nil, info)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_load_negative_utc_offset
|
233
|
+
offsets = [
|
234
|
+
{:gmtoff => -12492, :isdst => false, :abbrev => 'LMT'},
|
235
|
+
{:gmtoff => -12000, :isdst => false, :abbrev => 'XST'},
|
236
|
+
{:gmtoff => -8400, :isdst => true, :abbrev => 'XDT'},
|
237
|
+
{:gmtoff => -8400, :isdst => false, :abbrev => 'XNST'}]
|
238
|
+
|
239
|
+
transitions = [
|
240
|
+
{:at => Time.utc(1971, 7, 9, 3, 0, 0), :offset_index => 1},
|
241
|
+
{:at => Time.utc(1972, 10, 12, 3, 0, 0), :offset_index => 2},
|
242
|
+
{:at => Time.utc(1973, 4, 29, 3, 0, 0), :offset_index => 1},
|
243
|
+
{:at => Time.utc(1992, 4, 1, 4, 30, 0), :offset_index => 3}]
|
244
|
+
|
245
|
+
tzif_test(offsets, transitions) do |path, format|
|
246
|
+
info = ZoneinfoTimezoneInfo.new('Zone/One', path)
|
247
|
+
assert_equal('Zone/One', info.identifier)
|
248
|
+
|
249
|
+
assert_period(:LMT, -12492, 0, false, nil, Time.utc(1971, 7, 9, 3, 0, 0), info)
|
250
|
+
assert_period(:XST, -12000, 0, false, Time.utc(1971, 7, 9, 3, 0, 0), Time.utc(1972, 10, 12, 3, 0, 0), info)
|
251
|
+
assert_period(:XDT, -12000, 3600, true, Time.utc(1972, 10, 12, 3, 0, 0), Time.utc(1973, 4, 29, 3, 0, 0), info)
|
252
|
+
assert_period(:XST, -12000, 0, false, Time.utc(1973, 4, 29, 3, 0, 0), Time.utc(1992, 4, 1, 4, 30, 0), info)
|
253
|
+
assert_period(:XNST, -8400, 0, false, Time.utc(1992, 4, 1, 4, 30, 0), nil, info)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
def test_load_dst_first
|
258
|
+
offsets = [
|
259
|
+
{:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'},
|
260
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
261
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
|
262
|
+
{:gmtoff => 0, :isdst => false, :abbrev => 'XNST'}]
|
263
|
+
|
264
|
+
transitions = [
|
265
|
+
{:at => Time.utc(1979, 1, 2), :offset_index => 2},
|
266
|
+
{:at => Time.utc(1980, 4, 22), :offset_index => 0},
|
267
|
+
{:at => Time.utc(1980, 10, 21), :offset_index => 2},
|
268
|
+
{:at => Time.utc(2000, 12, 31), :offset_index => 3}]
|
269
|
+
|
270
|
+
tzif_test(offsets, transitions) do |path, format|
|
271
|
+
info = ZoneinfoTimezoneInfo.new('Zone/Two', path)
|
272
|
+
assert_equal('Zone/Two', info.identifier)
|
273
|
+
|
274
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.utc(1979, 1, 2), info)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def test_load_no_transitions
|
279
|
+
offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
|
280
|
+
|
281
|
+
tzif_test(offsets, []) do |path, format|
|
282
|
+
info = ZoneinfoTimezoneInfo.new('Zone/three', path)
|
283
|
+
assert_equal('Zone/three', info.identifier)
|
284
|
+
|
285
|
+
assert_period(:LT, -12094, 0, false, nil, nil, info)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
def test_load_no_offsets
|
290
|
+
offsets = []
|
291
|
+
transitions = [{:at => Time.utc(2000, 12, 31), :offset_index => 0}]
|
292
|
+
|
293
|
+
tzif_test(offsets, transitions) do |path, format|
|
294
|
+
assert_raises(InvalidZoneinfoFile) do
|
295
|
+
ZoneinfoTimezoneInfo.new('Zone', path)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
def test_load_invalid_offset_index
|
301
|
+
offsets = [{:gmtoff => -0, :isdst => false, :abbrev => 'LMT'}]
|
302
|
+
transitions = [{:at => Time.utc(2000, 12, 31), :offset_index => 2}]
|
303
|
+
|
304
|
+
tzif_test(offsets, transitions) do |path, format|
|
305
|
+
assert_raises(InvalidZoneinfoFile) do
|
306
|
+
ZoneinfoTimezoneInfo.new('Zone', path)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
def test_load_with_leap_seconds
|
312
|
+
offsets = [{:gmtoff => -0, :isdst => false, :abbrev => 'LMT'}]
|
313
|
+
leaps = [{:at => Time.utc(1972,6,30,23,59,60), :seconds => 1}]
|
314
|
+
|
315
|
+
tzif_test(offsets, [], leaps) do |path, format|
|
316
|
+
assert_raises(InvalidZoneinfoFile) do
|
317
|
+
ZoneinfoTimezoneInfo.new('Zone', path)
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
def test_load_invalid_magic
|
323
|
+
['TZif4', 'tzif2', '12345'].each do |magic|
|
324
|
+
offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
|
325
|
+
|
326
|
+
tzif_test(offsets, [], [], :magic => magic) do |path, format|
|
327
|
+
assert_raises(InvalidZoneinfoFile) do
|
328
|
+
ZoneinfoTimezoneInfo.new('Zone2', path)
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
# These tests can only be run if the platform supports 64-bit Times. When
|
335
|
+
# 64-bit support is unavailable, the second section will not be read, so no
|
336
|
+
# error will be raised.
|
337
|
+
if SUPPORTS_64BIT
|
338
|
+
def test_load_invalid_section2_magic
|
339
|
+
['TZif4', 'tzif2', '12345'].each do |section2_magic|
|
340
|
+
offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
|
341
|
+
|
342
|
+
tzif_test(offsets, [], [], :min_format => 2, :section2_magic => section2_magic) do |path, format|
|
343
|
+
assert_raises(InvalidZoneinfoFile) do
|
344
|
+
ZoneinfoTimezoneInfo.new('Zone4', path)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
def test_load_mismatched_section2_magic
|
351
|
+
minus_one = Proc.new {|f| f == 2 ? "TZif\0" : "TZif#{f - 1}" }
|
352
|
+
plus_one = Proc.new {|f| "TZif#{f + 1}" }
|
353
|
+
|
354
|
+
[minus_one, plus_one].each do |section2_magic|
|
355
|
+
offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
|
356
|
+
|
357
|
+
tzif_test(offsets, [], [], :min_format => 2, :section2_magic => section2_magic) do |path, format|
|
358
|
+
assert_raises(InvalidZoneinfoFile) do
|
359
|
+
ZoneinfoTimezoneInfo.new('Zone5', path)
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
def test_load_invalid_format
|
367
|
+
Tempfile.open('tzinfo-test-zone') do |file|
|
368
|
+
file.write('Invalid')
|
369
|
+
file.flush
|
370
|
+
|
371
|
+
assert_raises(InvalidZoneinfoFile) do
|
372
|
+
ZoneinfoTimezoneInfo.new('Zone3', file.path)
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
def test_load_missing_abbrev_null_termination
|
378
|
+
offsets = [
|
379
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
380
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST'}]
|
381
|
+
|
382
|
+
transitions = [
|
383
|
+
{:at => Time.utc(2000, 1, 1), :offset_index => 1}]
|
384
|
+
|
385
|
+
tzif_test(offsets, transitions, [], :abbrev_separator => '^') do |path, format|
|
386
|
+
assert_raises(InvalidZoneinfoFile) do
|
387
|
+
ZoneinfoTimezoneInfo.new('Zone', path)
|
388
|
+
end
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
def test_load_out_of_range_abbrev_offsets
|
393
|
+
offsets = [
|
394
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
395
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST'}]
|
396
|
+
|
397
|
+
transitions = [
|
398
|
+
{:at => Time.utc(2000, 1, 1), :offset_index => 1}]
|
399
|
+
|
400
|
+
tzif_test(offsets, transitions, [], :abbrev_offset_base => 8) do |path, format|
|
401
|
+
assert_raises(InvalidZoneinfoFile) do
|
402
|
+
ZoneinfoTimezoneInfo.new('Zone', path)
|
403
|
+
end
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
def test_load_before_epoch
|
408
|
+
# Some platforms don't support negative timestamps for times before the
|
409
|
+
# epoch. Check that they are returned when supported and skipped when not.
|
410
|
+
|
411
|
+
# Note the last transition before the epoch (and within the 32-bit range) is
|
412
|
+
# moved to the epoch on platforms that do not support negative timestamps.
|
413
|
+
|
414
|
+
offsets = [
|
415
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
416
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
|
417
|
+
{:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'},
|
418
|
+
{:gmtoff => 0, :isdst => false, :abbrev => 'XNST'}]
|
419
|
+
|
420
|
+
transitions = [
|
421
|
+
{:at => -694224000, :offset_index => 1}, # Time.utc(1948, 1, 2)
|
422
|
+
{:at => -21945600, :offset_index => 2}, # Time.utc(1969, 4, 22)
|
423
|
+
{:at => Time.utc(1970, 10, 21), :offset_index => 1},
|
424
|
+
{:at => Time.utc(2000, 12, 31), :offset_index => 3}]
|
425
|
+
|
426
|
+
tzif_test(offsets, transitions) do |path, format|
|
427
|
+
info = ZoneinfoTimezoneInfo.new('Zone/Negative', path)
|
428
|
+
assert_equal('Zone/Negative', info.identifier)
|
429
|
+
|
430
|
+
if SUPPORTS_NEGATIVE
|
431
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.utc(1948, 1, 2), info)
|
432
|
+
assert_period(:XST, 3600, 0, false, Time.utc(1948, 1, 2), Time.utc(1969, 4, 22), info)
|
433
|
+
assert_period(:XDT, 3600, 3600, true, Time.utc(1969, 4, 22), Time.utc(1970, 10, 21), info)
|
434
|
+
else
|
435
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.utc(1970, 1, 1), info)
|
436
|
+
assert_period(:XDT, 3600, 3600, true, Time.utc(1970, 1, 1), Time.utc(1970, 10, 21), info)
|
437
|
+
end
|
438
|
+
|
439
|
+
assert_period(:XST, 3600, 0, false, Time.utc(1970, 10, 21), Time.utc(2000, 12, 31), info)
|
440
|
+
assert_period(:XNST, 0, 0, false, Time.utc(2000, 12, 31), nil, info)
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
def test_load_on_epoch
|
445
|
+
offsets = [
|
446
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
447
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
|
448
|
+
{:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'},
|
449
|
+
{:gmtoff => 0, :isdst => false, :abbrev => 'XNST'}]
|
450
|
+
|
451
|
+
transitions = [
|
452
|
+
{:at => -694224000, :offset_index => 1}, # Time.utc(1948, 1, 2)
|
453
|
+
{:at => -21945600, :offset_index => 2}, # Time.utc(1969, 4, 22)
|
454
|
+
{:at => Time.utc(1970, 1, 1), :offset_index => 1},
|
455
|
+
{:at => Time.utc(2000, 12, 31), :offset_index => 3}]
|
456
|
+
|
457
|
+
tzif_test(offsets, transitions) do |path, format|
|
458
|
+
info = ZoneinfoTimezoneInfo.new('Zone/Negative', path)
|
459
|
+
assert_equal('Zone/Negative', info.identifier)
|
460
|
+
|
461
|
+
if SUPPORTS_NEGATIVE
|
462
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.utc(1948, 1, 2), info)
|
463
|
+
assert_period(:XST, 3600, 0, false, Time.utc(1948, 1, 2), Time.utc(1969, 4, 22), info)
|
464
|
+
assert_period(:XDT, 3600, 3600, true, Time.utc(1969, 4, 22), Time.utc(1970, 1, 1), info)
|
465
|
+
else
|
466
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.utc(1970, 1, 1), info)
|
467
|
+
end
|
468
|
+
|
469
|
+
assert_period(:XST, 3600, 0, false, Time.utc(1970, 1, 1), Time.utc(2000, 12, 31), info)
|
470
|
+
assert_period(:XNST, 0, 0, false, Time.utc(2000, 12, 31), nil, info)
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
def test_load_64bit
|
475
|
+
# Some platforms support 64-bit Times, others only 32-bit. The TZif version
|
476
|
+
# 2 and later format contains both 32-bit and 64-bit times.
|
477
|
+
|
478
|
+
# Where 64-bit is supported and a TZif 2 or later file is provided, the
|
479
|
+
# 64-bit times should be used, otherwise the 32-bit information should be
|
480
|
+
# used.
|
481
|
+
|
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 => -3786739200, :offset_index => 1}, # Time.utc(1850, 1, 2)
|
490
|
+
{:at => Time.utc(2003, 4, 22), :offset_index => 2},
|
491
|
+
{:at => Time.utc(2003, 10, 21), :offset_index => 1},
|
492
|
+
{:at => 2240524800, :offset_index => 3}] # Time.utc(2040, 12, 31)
|
493
|
+
|
494
|
+
tzif_test(offsets, transitions) do |path, format|
|
495
|
+
info = ZoneinfoTimezoneInfo.new('Zone/SixtyFour', path)
|
496
|
+
assert_equal('Zone/SixtyFour', info.identifier)
|
497
|
+
|
498
|
+
if SUPPORTS_64BIT && format >= 2
|
499
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.utc(1850, 1, 2), info)
|
500
|
+
assert_period(:XST, 3600, 0, false, Time.utc(1850, 1, 2), Time.utc(2003, 4, 22), info)
|
501
|
+
assert_period(:XDT, 3600, 3600, true, Time.utc(2003, 4, 22), Time.utc(2003, 10, 21), info)
|
502
|
+
assert_period(:XST, 3600, 0, false, Time.utc(2003, 10, 21), Time.utc(2040, 12, 31), info)
|
503
|
+
assert_period(:XNST, 0, 0, false, Time.utc(2040, 12, 31), nil, info)
|
504
|
+
else
|
505
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.utc(2003, 4, 22), info)
|
506
|
+
assert_period(:XDT, 3600, 3600, true, Time.utc(2003, 4, 22), Time.utc(2003, 10, 21), info)
|
507
|
+
assert_period(:XST, 3600, 0, false, Time.utc(2003, 10, 21), nil, info)
|
508
|
+
end
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
512
|
+
def test_load_64bit_range
|
513
|
+
# The full range of 64 bit timestamps is not currently supported because of
|
514
|
+
# the way transitions are indexed. Transitions outside the supported range
|
515
|
+
# will be ignored.
|
516
|
+
|
517
|
+
offsets = [
|
518
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
519
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
|
520
|
+
{:gmtoff => 7200, :isdst => false, :abbrev => 'XNST'}]
|
521
|
+
|
522
|
+
transitions = [
|
523
|
+
{:at => -2**63, :offset_index => 1},
|
524
|
+
{:at => Time.utc(2014, 5, 27), :offset_index => 2},
|
525
|
+
{:at => 2**63 - 1, :offset_index => 0}]
|
526
|
+
|
527
|
+
tzif_test(offsets, transitions) do |path, format|
|
528
|
+
info = ZoneinfoTimezoneInfo.new('Zone/SixtyFourRange', path)
|
529
|
+
assert_equal('Zone/SixtyFourRange', info.identifier)
|
530
|
+
|
531
|
+
if SUPPORTS_64BIT && format >= 2
|
532
|
+
# When the full range is supported, the following periods will be defined:
|
533
|
+
#assert_period(:LMT, 3542, 0, false, nil, Time.at(-2**63).utc, info)
|
534
|
+
#assert_period(:XST, 3600, 0, false, Time.at(-2**63).utc, Time.utc(2014, 5, 27), info)
|
535
|
+
#assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), Time.at(2**63 - 1).utc, info)
|
536
|
+
#assert_period(:LMT, 3542, 0, false, Time.at(2**63 - 1).utc, nil, info)
|
537
|
+
|
538
|
+
# Without full range support, the following periods will be defined:
|
539
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.utc(2014, 5, 27), info)
|
540
|
+
assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
|
541
|
+
else
|
542
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.utc(2014, 5, 27), info)
|
543
|
+
assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
|
544
|
+
end
|
545
|
+
end
|
546
|
+
end
|
547
|
+
|
548
|
+
def test_load_supported_64bit_range
|
549
|
+
# The full range of 64 bit timestamps is not currently supported because of
|
550
|
+
# the way transitions are indexed. Transitions outside the supported range
|
551
|
+
# will be ignored.
|
552
|
+
|
553
|
+
min_timestamp = -8520336000 # Time.utc(1700, 1, 1).to_i
|
554
|
+
max_timestamp = 16725225600 # Time.utc(2500, 1, 1).to_i
|
555
|
+
|
556
|
+
offsets = [
|
557
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
558
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
|
559
|
+
{:gmtoff => 7200, :isdst => false, :abbrev => 'XNST'}]
|
560
|
+
|
561
|
+
transitions = [
|
562
|
+
{:at => min_timestamp, :offset_index => 1},
|
563
|
+
{:at => Time.utc(2014, 5, 27), :offset_index => 2},
|
564
|
+
{:at => max_timestamp - 1, :offset_index => 0}]
|
565
|
+
|
566
|
+
tzif_test(offsets, transitions) do |path, format|
|
567
|
+
info = ZoneinfoTimezoneInfo.new('Zone/SupportedSixtyFourRange', path)
|
568
|
+
assert_equal('Zone/SupportedSixtyFourRange', info.identifier)
|
569
|
+
|
570
|
+
if SUPPORTS_64BIT && format >= 2
|
571
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.at(min_timestamp).utc, info)
|
572
|
+
assert_period(:XST, 3600, 0, false, Time.at(min_timestamp).utc, Time.utc(2014, 5, 27), info)
|
573
|
+
assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), Time.at(max_timestamp - 1).utc, info)
|
574
|
+
assert_period(:LMT, 3542, 0, false, Time.at(max_timestamp - 1).utc, nil, info)
|
575
|
+
else
|
576
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.utc(2014, 5, 27), info)
|
577
|
+
assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), nil, info)
|
578
|
+
end
|
579
|
+
end
|
580
|
+
end
|
581
|
+
|
582
|
+
def test_load_32bit_range
|
583
|
+
offsets = [
|
584
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
585
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
|
586
|
+
{:gmtoff => 7200, :isdst => false, :abbrev => 'XNST'}]
|
587
|
+
|
588
|
+
transitions = [
|
589
|
+
{:at => -2**31, :offset_index => 1},
|
590
|
+
{:at => Time.utc(2014, 5, 27), :offset_index => 2},
|
591
|
+
{:at => 2**31 - 1, :offset_index => 0}]
|
592
|
+
|
593
|
+
tzif_test(offsets, transitions) do |path, format|
|
594
|
+
info = ZoneinfoTimezoneInfo.new('Zone/ThirtyTwoRange', path)
|
595
|
+
assert_equal('Zone/ThirtyTwoRange', info.identifier)
|
596
|
+
|
597
|
+
if SUPPORTS_NEGATIVE
|
598
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.at(-2**31).utc, info)
|
599
|
+
assert_period(:XST, 3600, 0, false, Time.at(-2**31).utc, Time.utc(2014, 5, 27), info)
|
600
|
+
assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), Time.at(2**31 - 1).utc, info)
|
601
|
+
assert_period(:LMT, 3542, 0, false, Time.at(2**31 - 1).utc, nil, info)
|
602
|
+
else
|
603
|
+
assert_period(:XST, 3600, 0, false, Time.utc(1970, 1, 1), Time.utc(2014, 5, 27), info)
|
604
|
+
assert_period(:XNST, 7200, 0, false, Time.utc(2014, 5, 27), Time.at(2**31 - 1).utc, info)
|
605
|
+
assert_period(:LMT, 3542, 0, false, Time.at(2**31 - 1).utc, nil, info)
|
606
|
+
end
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
610
|
+
def test_load_std_offset_changes
|
611
|
+
# The zoneinfo files don't include the offset from standard time, so this
|
612
|
+
# has to be derived by looking at changes in the total UTC offset.
|
613
|
+
|
614
|
+
offsets = [
|
615
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
616
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
|
617
|
+
{:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'},
|
618
|
+
{:gmtoff => 10800, :isdst => true, :abbrev => 'XDDT'}]
|
619
|
+
|
620
|
+
transitions = [
|
621
|
+
{:at => Time.utc(2000, 1, 1), :offset_index => 1},
|
622
|
+
{:at => Time.utc(2000, 2, 1), :offset_index => 2},
|
623
|
+
{:at => Time.utc(2000, 3, 1), :offset_index => 3},
|
624
|
+
{:at => Time.utc(2000, 4, 1), :offset_index => 1}]
|
625
|
+
|
626
|
+
tzif_test(offsets, transitions) do |path, format|
|
627
|
+
info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path)
|
628
|
+
assert_equal('Zone/DoubleDaylight', info.identifier)
|
629
|
+
|
630
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
|
631
|
+
assert_period(:XST, 3600, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
|
632
|
+
assert_period(:XDT, 3600, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
|
633
|
+
assert_period(:XDDT, 3600, 7200, true, Time.utc(2000, 3, 1), Time.utc(2000, 4, 1), info)
|
634
|
+
assert_period(:XST, 3600, 0, false, Time.utc(2000, 4, 1), nil, info)
|
635
|
+
end
|
636
|
+
end
|
637
|
+
|
638
|
+
def test_load_std_offset_changes_jump_to_double_dst
|
639
|
+
# The zoneinfo files don't include the offset from standard time, so this
|
640
|
+
# has to be derived by looking at changes in the total UTC offset.
|
641
|
+
|
642
|
+
offsets = [
|
643
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
644
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
|
645
|
+
{:gmtoff => 10800, :isdst => true, :abbrev => 'XDDT'}]
|
646
|
+
|
647
|
+
transitions = [
|
648
|
+
{:at => Time.utc(2000, 4, 1), :offset_index => 1},
|
649
|
+
{:at => Time.utc(2000, 5, 1), :offset_index => 2},
|
650
|
+
{:at => Time.utc(2000, 6, 1), :offset_index => 1}]
|
651
|
+
|
652
|
+
tzif_test(offsets, transitions) do |path, format|
|
653
|
+
info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path)
|
654
|
+
assert_equal('Zone/DoubleDaylight', info.identifier)
|
655
|
+
|
656
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.utc(2000, 4, 1), info)
|
657
|
+
assert_period(:XST, 3600, 0, false, Time.utc(2000, 4, 1), Time.utc(2000, 5, 1), info)
|
658
|
+
assert_period(:XDDT, 3600, 7200, true, Time.utc(2000, 5, 1), Time.utc(2000, 6, 1), info)
|
659
|
+
assert_period(:XST, 3600, 0, false, Time.utc(2000, 6, 1), nil, info)
|
660
|
+
end
|
661
|
+
end
|
662
|
+
|
663
|
+
def test_load_std_offset_changes_negative
|
664
|
+
# The zoneinfo files don't include the offset from standard time, so this
|
665
|
+
# has to be derived by looking at changes in the total UTC offset.
|
666
|
+
|
667
|
+
offsets = [
|
668
|
+
{:gmtoff => -10821, :isdst => false, :abbrev => 'LMT'},
|
669
|
+
{:gmtoff => -10800, :isdst => false, :abbrev => 'XST'},
|
670
|
+
{:gmtoff => -7200, :isdst => true, :abbrev => 'XDT'},
|
671
|
+
{:gmtoff => -3600, :isdst => true, :abbrev => 'XDDT'}]
|
672
|
+
|
673
|
+
transitions = [
|
674
|
+
{:at => Time.utc(2000, 1, 1), :offset_index => 1},
|
675
|
+
{:at => Time.utc(2000, 2, 1), :offset_index => 2},
|
676
|
+
{:at => Time.utc(2000, 3, 1), :offset_index => 3},
|
677
|
+
{:at => Time.utc(2000, 4, 1), :offset_index => 1},
|
678
|
+
{:at => Time.utc(2000, 5, 1), :offset_index => 3},
|
679
|
+
{:at => Time.utc(2000, 6, 1), :offset_index => 1}]
|
680
|
+
|
681
|
+
tzif_test(offsets, transitions) do |path, format|
|
682
|
+
info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path)
|
683
|
+
assert_equal('Zone/DoubleDaylight', info.identifier)
|
684
|
+
|
685
|
+
assert_period(:LMT, -10821, 0, false, nil, Time.utc(2000, 1, 1), info)
|
686
|
+
assert_period(:XST, -10800, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
|
687
|
+
assert_period(:XDT, -10800, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
|
688
|
+
assert_period(:XDDT, -10800, 7200, true, Time.utc(2000, 3, 1), Time.utc(2000, 4, 1), info)
|
689
|
+
assert_period(:XST, -10800, 0, false, Time.utc(2000, 4, 1), Time.utc(2000, 5, 1), info)
|
690
|
+
assert_period(:XDDT, -10800, 7200, true, Time.utc(2000, 5, 1), Time.utc(2000, 6, 1), info)
|
691
|
+
assert_period(:XST, -10800, 0, false, Time.utc(2000, 6, 1), nil, info)
|
692
|
+
end
|
693
|
+
end
|
694
|
+
|
695
|
+
def test_load_starts_two_hour_std_offset
|
696
|
+
# The zoneinfo files don't include the offset from standard time, so this
|
697
|
+
# has to be derived by looking at changes in the total UTC offset.
|
698
|
+
|
699
|
+
offsets = [
|
700
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
701
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
|
702
|
+
{:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'},
|
703
|
+
{:gmtoff => 10800, :isdst => true, :abbrev => 'XDDT'}]
|
704
|
+
|
705
|
+
transitions = [
|
706
|
+
{:at => Time.utc(2000, 1, 1), :offset_index => 3},
|
707
|
+
{:at => Time.utc(2000, 2, 1), :offset_index => 2},
|
708
|
+
{:at => Time.utc(2000, 3, 1), :offset_index => 1}]
|
709
|
+
|
710
|
+
tzif_test(offsets, transitions) do |path, format|
|
711
|
+
info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path)
|
712
|
+
assert_equal('Zone/DoubleDaylight', info.identifier)
|
713
|
+
|
714
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
|
715
|
+
assert_period(:XDDT, 3600, 7200, true, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
|
716
|
+
assert_period(:XDT, 3600, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
|
717
|
+
assert_period(:XST, 3600, 0, false, Time.utc(2000, 3, 1), nil, info)
|
718
|
+
end
|
719
|
+
end
|
720
|
+
|
721
|
+
def test_load_starts_only_dst_transition_with_lmt
|
722
|
+
# The zoneinfo files don't include the offset from standard time, so this
|
723
|
+
# has to be derived by looking at changes in the total UTC offset.
|
724
|
+
|
725
|
+
offsets = [
|
726
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
727
|
+
{:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'}]
|
728
|
+
|
729
|
+
transitions = [{:at => Time.utc(2000, 1, 1), :offset_index => 1}]
|
730
|
+
|
731
|
+
tzif_test(offsets, transitions) do |path, format|
|
732
|
+
info = ZoneinfoTimezoneInfo.new('Zone/OnlyDST', path)
|
733
|
+
assert_equal('Zone/OnlyDST', info.identifier)
|
734
|
+
|
735
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
|
736
|
+
assert_period(:XDT, 3542, 3658, true, Time.utc(2000, 1, 1), nil, info)
|
737
|
+
end
|
738
|
+
end
|
739
|
+
|
740
|
+
def test_load_starts_only_dst_transition_without_lmt
|
741
|
+
# The zoneinfo files don't include the offset from standard time, so this
|
742
|
+
# has to be derived by looking at changes in the total UTC offset.
|
743
|
+
|
744
|
+
offsets = [{:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'}]
|
745
|
+
|
746
|
+
transitions = [{:at => Time.utc(2000, 1, 1), :offset_index => 0}]
|
747
|
+
|
748
|
+
tzif_test(offsets, transitions) do |path, format|
|
749
|
+
info = ZoneinfoTimezoneInfo.new('Zone/OnlyDST', path)
|
750
|
+
assert_equal('Zone/OnlyDST', info.identifier)
|
751
|
+
|
752
|
+
assert_period(:XDT, 3600, 3600, true, nil, Time.utc(2000, 1, 1), info)
|
753
|
+
assert_period(:XDT, 3600, 3600, true, Time.utc(2000, 1, 1), nil, info)
|
754
|
+
end
|
755
|
+
end
|
756
|
+
|
757
|
+
def test_load_switch_to_dst_and_change_utc_offset
|
758
|
+
# The zoneinfo files don't include the offset from standard time, so this
|
759
|
+
# has to be derived by looking at changes in the total UTC offset.
|
760
|
+
|
761
|
+
# Switch from non-DST to DST at the same time as moving the UTC offset
|
762
|
+
# back an hour (i.e. wall clock time doesn't change).
|
763
|
+
|
764
|
+
offsets = [
|
765
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
766
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'YST'},
|
767
|
+
{:gmtoff => 3600, :isdst => true, :abbrev => 'XDT'}]
|
768
|
+
|
769
|
+
transitions = [
|
770
|
+
{:at => Time.utc(2000, 1, 1), :offset_index => 1},
|
771
|
+
{:at => Time.utc(2000, 2, 1), :offset_index => 2}]
|
772
|
+
|
773
|
+
tzif_test(offsets, transitions) do |path, format|
|
774
|
+
info = ZoneinfoTimezoneInfo.new('Zone/DoubleDaylight', path)
|
775
|
+
assert_equal('Zone/DoubleDaylight', info.identifier)
|
776
|
+
|
777
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
|
778
|
+
assert_period(:YST, 3600, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
|
779
|
+
assert_period(:XDT, 0, 3600, true, Time.utc(2000, 2, 1), nil, info)
|
780
|
+
end
|
781
|
+
end
|
782
|
+
|
783
|
+
def test_load_apia_international_dateline_change
|
784
|
+
# The zoneinfo files don't include the offset from standard time, so this
|
785
|
+
# has to be derived by looking at changes in the total UTC offset.
|
786
|
+
|
787
|
+
# Pacific/Apia moved across the International Date Line whilst observing
|
788
|
+
# daylight savings time.
|
789
|
+
|
790
|
+
offsets = [
|
791
|
+
{:gmtoff => 45184, :isdst => false, :abbrev => 'LMT'},
|
792
|
+
{:gmtoff => -39600, :isdst => false, :abbrev => '-11'},
|
793
|
+
{:gmtoff => -36000, :isdst => true, :abbrev => '-10'},
|
794
|
+
{:gmtoff => 50400, :isdst => true, :abbrev => '+14'},
|
795
|
+
{:gmtoff => 46800, :isdst => false, :abbrev => '+13'}]
|
796
|
+
|
797
|
+
transitions = [
|
798
|
+
{:at => Time.utc(2011, 4, 2, 14, 0, 0), :offset_index => 1},
|
799
|
+
{:at => Time.utc(2011, 9, 24, 14, 0, 0), :offset_index => 2},
|
800
|
+
{:at => Time.utc(2011, 12, 30, 10, 0, 0), :offset_index => 3},
|
801
|
+
{:at => Time.utc(2012, 3, 31, 14, 0, 0), :offset_index => 4}]
|
802
|
+
|
803
|
+
tzif_test(offsets, transitions) do |path, format|
|
804
|
+
info = ZoneinfoTimezoneInfo.new('Test/Pacific/Apia', path)
|
805
|
+
assert_equal('Test/Pacific/Apia', info.identifier)
|
806
|
+
|
807
|
+
assert_period( :LMT, 45184, 0, false, nil, Time.utc(2011, 4, 2, 14, 0, 0), info)
|
808
|
+
assert_period(:'-11', -39600, 0, false, Time.utc(2011, 4, 2, 14, 0, 0), Time.utc(2011, 9, 24, 14, 0, 0), info)
|
809
|
+
assert_period(:'-10', -39600, 3600, true, Time.utc(2011, 9, 24, 14, 0, 0), Time.utc(2011, 12, 30, 10, 0, 0), info)
|
810
|
+
assert_period(:'+14', 46800, 3600, true, Time.utc(2011, 12, 30, 10, 0, 0), Time.utc(2012, 3, 31, 14, 0, 0), info)
|
811
|
+
assert_period(:'+13', 46800, 0, false, Time.utc(2012, 3, 31, 14, 0, 0), nil, info)
|
812
|
+
end
|
813
|
+
end
|
814
|
+
|
815
|
+
def test_load_offset_split_for_different_utc_offset
|
816
|
+
# The zoneinfo files don't include the offset from standard time, so this
|
817
|
+
# has to be derived by looking at changes in the total UTC offset.
|
818
|
+
|
819
|
+
offsets = [
|
820
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
821
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST1'},
|
822
|
+
{:gmtoff => 7200, :isdst => false, :abbrev => 'XST2'},
|
823
|
+
{:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}]
|
824
|
+
|
825
|
+
transitions = [
|
826
|
+
{:at => Time.utc(2000, 1, 1), :offset_index => 1},
|
827
|
+
{:at => Time.utc(2000, 2, 1), :offset_index => 3},
|
828
|
+
{:at => Time.utc(2000, 3, 1), :offset_index => 1},
|
829
|
+
{:at => Time.utc(2000, 4, 1), :offset_index => 2},
|
830
|
+
{:at => Time.utc(2000, 5, 1), :offset_index => 3},
|
831
|
+
{:at => Time.utc(2000, 6, 1), :offset_index => 2},
|
832
|
+
{:at => Time.utc(2000, 7, 1), :offset_index => 1},
|
833
|
+
{:at => Time.utc(2000, 8, 1), :offset_index => 3},
|
834
|
+
{:at => Time.utc(2000, 9, 1), :offset_index => 1},
|
835
|
+
{:at => Time.utc(2000, 10, 1), :offset_index => 2},
|
836
|
+
{:at => Time.utc(2000, 11, 1), :offset_index => 3},
|
837
|
+
{:at => Time.utc(2000, 12, 1), :offset_index => 2}]
|
838
|
+
|
839
|
+
# XDT will be split and defined according to its surrounding standard time
|
840
|
+
# offsets.
|
841
|
+
|
842
|
+
tzif_test(offsets, transitions) do |path, format|
|
843
|
+
info = ZoneinfoTimezoneInfo.new('Zone/SplitUtcOffset', path)
|
844
|
+
assert_equal('Zone/SplitUtcOffset', info.identifier)
|
845
|
+
|
846
|
+
assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
|
847
|
+
assert_period(:XST1, 3600, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
|
848
|
+
assert_period( :XDT, 3600, 7200, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
|
849
|
+
assert_period(:XST1, 3600, 0, false, Time.utc(2000, 3, 1), Time.utc(2000, 4, 1), info)
|
850
|
+
assert_period(:XST2, 7200, 0, false, Time.utc(2000, 4, 1), Time.utc(2000, 5, 1), info)
|
851
|
+
assert_period( :XDT, 7200, 3600, true, Time.utc(2000, 5, 1), Time.utc(2000, 6, 1), info)
|
852
|
+
assert_period(:XST2, 7200, 0, false, Time.utc(2000, 6, 1), Time.utc(2000, 7, 1), info)
|
853
|
+
assert_period(:XST1, 3600, 0, false, Time.utc(2000, 7, 1), Time.utc(2000, 8, 1), info)
|
854
|
+
assert_period( :XDT, 3600, 7200, true, Time.utc(2000, 8, 1), Time.utc(2000, 9, 1), info)
|
855
|
+
assert_period(:XST1, 3600, 0, false, Time.utc(2000, 9, 1), Time.utc(2000, 10, 1), info)
|
856
|
+
assert_period(:XST2, 7200, 0, false, Time.utc(2000, 10, 1), Time.utc(2000, 11, 1), info)
|
857
|
+
assert_period( :XDT, 7200, 3600, true, Time.utc(2000, 11, 1), Time.utc(2000, 12, 1), info)
|
858
|
+
assert_period(:XST2, 7200, 0, false, Time.utc(2000, 12, 1), nil, info)
|
859
|
+
|
860
|
+
1.upto(6) do |i|
|
861
|
+
assert_same(info.period_for_utc(Time.utc(2000, i, 1)).offset, info.period_for_utc(Time.utc(2000, i + 6, 1)).offset)
|
862
|
+
end
|
863
|
+
end
|
864
|
+
end
|
865
|
+
|
866
|
+
def test_load_offset_utc_offset_taken_from_minimum_difference_minimum_after
|
867
|
+
# The zoneinfo files don't include the offset from standard time, so this
|
868
|
+
# has to be derived by looking at changes in the total UTC offset.
|
869
|
+
|
870
|
+
offsets = [
|
871
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
872
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST1'},
|
873
|
+
{:gmtoff => 7200, :isdst => false, :abbrev => 'XST2'},
|
874
|
+
{:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}]
|
875
|
+
|
876
|
+
transitions = [
|
877
|
+
{:at => Time.utc(2000, 1, 1), :offset_index => 1},
|
878
|
+
{:at => Time.utc(2000, 2, 1), :offset_index => 3},
|
879
|
+
{:at => Time.utc(2000, 3, 1), :offset_index => 2}]
|
880
|
+
|
881
|
+
# XDT should use the closest utc_offset (7200) (and not an equivalent
|
882
|
+
# utc_offset of 3600 and std_offset of 7200).
|
883
|
+
|
884
|
+
tzif_test(offsets, transitions) do |path, format|
|
885
|
+
info = ZoneinfoTimezoneInfo.new('Zone/MinimumUtcOffset', path)
|
886
|
+
assert_equal('Zone/MinimumUtcOffset', info.identifier)
|
887
|
+
|
888
|
+
assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
|
889
|
+
assert_period(:XST1, 3600, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
|
890
|
+
assert_period( :XDT, 7200, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
|
891
|
+
assert_period(:XST2, 7200, 0, false, Time.utc(2000, 3, 1), nil, info)
|
892
|
+
end
|
893
|
+
end
|
894
|
+
|
895
|
+
def test_load_offset_utc_offset_taken_from_minimum_difference_minimum_before
|
896
|
+
# The zoneinfo files don't include the offset from standard time, so this
|
897
|
+
# has to be derived by looking at changes in the total UTC offset.
|
898
|
+
|
899
|
+
offsets = [
|
900
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
901
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST1'},
|
902
|
+
{:gmtoff => 7200, :isdst => false, :abbrev => 'XST2'},
|
903
|
+
{:gmtoff => 10800, :isdst => true, :abbrev => 'XDT'}]
|
904
|
+
|
905
|
+
transitions = [
|
906
|
+
{:at => Time.utc(2000, 1, 1), :offset_index => 2},
|
907
|
+
{:at => Time.utc(2000, 2, 1), :offset_index => 3},
|
908
|
+
{:at => Time.utc(2000, 3, 1), :offset_index => 1}]
|
909
|
+
|
910
|
+
# XDT should use the closest utc_offset (7200) (and not an equivalent
|
911
|
+
# utc_offset of 3600 and std_offset of 7200).
|
912
|
+
|
913
|
+
tzif_test(offsets, transitions) do |path, format|
|
914
|
+
info = ZoneinfoTimezoneInfo.new('Zone/MinimumUtcOffset', path)
|
915
|
+
assert_equal('Zone/MinimumUtcOffset', info.identifier)
|
916
|
+
|
917
|
+
assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
|
918
|
+
assert_period(:XST2, 7200, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
|
919
|
+
assert_period( :XDT, 7200, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
|
920
|
+
assert_period(:XST1, 3600, 0, false, Time.utc(2000, 3, 1), nil, info)
|
921
|
+
end
|
922
|
+
end
|
923
|
+
|
924
|
+
def test_load_offset_does_not_use_equal_utc_total_offset_equal_after
|
925
|
+
# The zoneinfo files don't include the offset from standard time, so this
|
926
|
+
# has to be derived by looking at changes in the total UTC offset.
|
927
|
+
|
928
|
+
offsets = [
|
929
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
930
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST1'},
|
931
|
+
{:gmtoff => 7200, :isdst => false, :abbrev => 'XST2'},
|
932
|
+
{:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'}]
|
933
|
+
|
934
|
+
transitions = [
|
935
|
+
{:at => Time.utc(2000, 1, 1), :offset_index => 1},
|
936
|
+
{:at => Time.utc(2000, 2, 1), :offset_index => 3},
|
937
|
+
{:at => Time.utc(2000, 3, 1), :offset_index => 2}]
|
938
|
+
|
939
|
+
# XDT will be based on the utc_offset of XST1 even though XST2 has an
|
940
|
+
# equivalent (or greater) utc_total_offset.
|
941
|
+
|
942
|
+
tzif_test(offsets, transitions) do |path, format|
|
943
|
+
info = ZoneinfoTimezoneInfo.new('Zone/UtcOffsetEqual', path)
|
944
|
+
assert_equal('Zone/UtcOffsetEqual', info.identifier)
|
945
|
+
|
946
|
+
assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
|
947
|
+
assert_period(:XST1, 3600, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
|
948
|
+
assert_period( :XDT, 3600, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
|
949
|
+
assert_period(:XST2, 7200, 0, false, Time.utc(2000, 3, 1), nil, info)
|
950
|
+
end
|
951
|
+
end
|
952
|
+
|
953
|
+
def test_load_offset_does_not_use_equal_utc_total_offset_equal_before
|
954
|
+
# The zoneinfo files don't include the offset from standard time, so this
|
955
|
+
# has to be derived by looking at changes in the total UTC offset.
|
956
|
+
|
957
|
+
offsets = [
|
958
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
959
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST1'},
|
960
|
+
{:gmtoff => 7200, :isdst => false, :abbrev => 'XST2'},
|
961
|
+
{:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'}]
|
962
|
+
|
963
|
+
transitions = [
|
964
|
+
{:at => Time.utc(2000, 1, 1), :offset_index => 2},
|
965
|
+
{:at => Time.utc(2000, 2, 1), :offset_index => 3},
|
966
|
+
{:at => Time.utc(2000, 3, 1), :offset_index => 1}]
|
967
|
+
|
968
|
+
# XDT will be based on the utc_offset of XST1 even though XST2 has an
|
969
|
+
# equivalent (or greater) utc_total_offset.
|
970
|
+
|
971
|
+
tzif_test(offsets, transitions) do |path, format|
|
972
|
+
info = ZoneinfoTimezoneInfo.new('Zone/UtcOffsetEqual', path)
|
973
|
+
assert_equal('Zone/UtcOffsetEqual', info.identifier)
|
974
|
+
|
975
|
+
assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
|
976
|
+
assert_period(:XST2, 7200, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
|
977
|
+
assert_period( :XDT, 3600, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
|
978
|
+
assert_period(:XST1, 3600, 0, false, Time.utc(2000, 3, 1), nil, info)
|
979
|
+
end
|
980
|
+
end
|
981
|
+
|
982
|
+
def test_load_offset_both_adjacent_non_dst_equal_utc_total_offset
|
983
|
+
# The zoneinfo files don't include the offset from standard time, so this
|
984
|
+
# has to be derived by looking at changes in the total UTC offset.
|
985
|
+
|
986
|
+
offsets = [
|
987
|
+
{:gmtoff => 7142, :isdst => false, :abbrev => 'LMT'},
|
988
|
+
{:gmtoff => 7200, :isdst => false, :abbrev => 'XST'},
|
989
|
+
{:gmtoff => 7200, :isdst => true, :abbrev => 'XDT'}]
|
990
|
+
|
991
|
+
transitions = [
|
992
|
+
{:at => Time.utc(2000, 1, 1), :offset_index => 1},
|
993
|
+
{:at => Time.utc(2000, 2, 1), :offset_index => 2},
|
994
|
+
{:at => Time.utc(2000, 3, 1), :offset_index => 1}]
|
995
|
+
|
996
|
+
# XDT will just assume an std_offset of +1 hour and calculate the utc_offset
|
997
|
+
# from utc_total_offset - std_offset.
|
998
|
+
|
999
|
+
tzif_test(offsets, transitions) do |path, format|
|
1000
|
+
info = ZoneinfoTimezoneInfo.new('Zone/AdjacentEqual', path)
|
1001
|
+
assert_equal('Zone/AdjacentEqual', info.identifier)
|
1002
|
+
|
1003
|
+
assert_period(:LMT, 7142, 0, false, nil, Time.utc(2000, 1, 1), info)
|
1004
|
+
assert_period(:XST, 7200, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
|
1005
|
+
assert_period(:XDT, 3600, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
|
1006
|
+
assert_period(:XST, 7200, 0, false, Time.utc(2000, 3, 1), nil, info)
|
1007
|
+
end
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
def test_load_offset_utc_offset_preserved_from_next
|
1011
|
+
# The zoneinfo files don't include the offset from standard time, so this
|
1012
|
+
# has to be derived by looking at changes in the total UTC offset.
|
1013
|
+
|
1014
|
+
offsets = [
|
1015
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
1016
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST1'},
|
1017
|
+
{:gmtoff => 7200, :isdst => false, :abbrev => 'XST2'},
|
1018
|
+
{:gmtoff => 10800, :isdst => true, :abbrev => 'XDT1'},
|
1019
|
+
{:gmtoff => 10800, :isdst => true, :abbrev => 'XDT2'}]
|
1020
|
+
|
1021
|
+
transitions = [
|
1022
|
+
{:at => Time.utc(2000, 1, 1), :offset_index => 1},
|
1023
|
+
{:at => Time.utc(2000, 2, 1), :offset_index => 3},
|
1024
|
+
{:at => Time.utc(2000, 3, 1), :offset_index => 4},
|
1025
|
+
{:at => Time.utc(2000, 4, 1), :offset_index => 2}]
|
1026
|
+
|
1027
|
+
# Both XDT1 and XDT2 should both use the closest utc_offset (7200) (and not
|
1028
|
+
# an equivalent utc_offset of 3600 and std_offset of 7200).
|
1029
|
+
|
1030
|
+
tzif_test(offsets, transitions) do |path, format|
|
1031
|
+
info = ZoneinfoTimezoneInfo.new('Zone/UtcOffsetPreserved', path)
|
1032
|
+
assert_equal('Zone/UtcOffsetPreserved', info.identifier)
|
1033
|
+
|
1034
|
+
assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
|
1035
|
+
assert_period(:XST1, 3600, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
|
1036
|
+
assert_period(:XDT1, 7200, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
|
1037
|
+
assert_period(:XDT2, 7200, 3600, true, Time.utc(2000, 3, 1), Time.utc(2000, 4, 1), info)
|
1038
|
+
assert_period(:XST2, 7200, 0, false, Time.utc(2000, 4, 1), nil, info)
|
1039
|
+
end
|
1040
|
+
end
|
1041
|
+
|
1042
|
+
def test_load_offset_utc_offset_preserved_from_previous
|
1043
|
+
# The zoneinfo files don't include the offset from standard time, so this
|
1044
|
+
# has to be derived by looking at changes in the total UTC offset.
|
1045
|
+
|
1046
|
+
offsets = [
|
1047
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
1048
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST1'},
|
1049
|
+
{:gmtoff => 7200, :isdst => false, :abbrev => 'XST2'},
|
1050
|
+
{:gmtoff => 10800, :isdst => true, :abbrev => 'XDT1'},
|
1051
|
+
{:gmtoff => 10800, :isdst => true, :abbrev => 'XDT2'}]
|
1052
|
+
|
1053
|
+
transitions = [
|
1054
|
+
{:at => Time.utc(2000, 1, 1), :offset_index => 2},
|
1055
|
+
{:at => Time.utc(2000, 2, 1), :offset_index => 3},
|
1056
|
+
{:at => Time.utc(2000, 3, 1), :offset_index => 4},
|
1057
|
+
{:at => Time.utc(2000, 4, 1), :offset_index => 1}]
|
1058
|
+
|
1059
|
+
# Both XDT1 and XDT2 should both use the closest utc_offset (7200) (and not
|
1060
|
+
# an equivalent utc_offset of 3600 and std_offset of 7200).
|
1061
|
+
|
1062
|
+
tzif_test(offsets, transitions) do |path, format|
|
1063
|
+
info = ZoneinfoTimezoneInfo.new('Zone/UtcOffsetPreserved', path)
|
1064
|
+
assert_equal('Zone/UtcOffsetPreserved', info.identifier)
|
1065
|
+
|
1066
|
+
assert_period( :LMT, 3542, 0, false, nil, Time.utc(2000, 1, 1), info)
|
1067
|
+
assert_period(:XST2, 7200, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
|
1068
|
+
assert_period(:XDT1, 7200, 3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
|
1069
|
+
assert_period(:XDT2, 7200, 3600, true, Time.utc(2000, 3, 1), Time.utc(2000, 4, 1), info)
|
1070
|
+
assert_period(:XST1, 3600, 0, false, Time.utc(2000, 4, 1), nil, info)
|
1071
|
+
end
|
1072
|
+
end
|
1073
|
+
|
1074
|
+
def test_read_offset_negative_std_offset_dst
|
1075
|
+
# The zoneinfo files don't include the offset from standard time, so this
|
1076
|
+
# has to be derived by looking at changes in the total UTC offset.
|
1077
|
+
|
1078
|
+
offsets = [
|
1079
|
+
{:gmtoff => -100, :isdst => false, :abbrev => 'LMT'},
|
1080
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
|
1081
|
+
{:gmtoff => 0, :isdst => true, :abbrev => 'XWT'}]
|
1082
|
+
|
1083
|
+
transitions = [
|
1084
|
+
{:at => Time.utc(2000, 1, 1), :offset_index => 1},
|
1085
|
+
{:at => Time.utc(2000, 2, 1), :offset_index => 2},
|
1086
|
+
{:at => Time.utc(2000, 3, 1), :offset_index => 1},
|
1087
|
+
{:at => Time.utc(2000, 4, 1), :offset_index => 2},
|
1088
|
+
{:at => Time.utc(2000, 5, 1), :offset_index => 1}]
|
1089
|
+
|
1090
|
+
tzif_test(offsets, transitions) do |path, format|
|
1091
|
+
info = ZoneinfoTimezoneInfo.new('Zone/NegativeStdOffsetDst', path)
|
1092
|
+
assert_equal('Zone/NegativeStdOffsetDst', info.identifier)
|
1093
|
+
|
1094
|
+
assert_period(:LMT, -100, 0, false, nil, Time.utc(2000, 1, 1), info)
|
1095
|
+
assert_period(:XST, 3600, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
|
1096
|
+
assert_period(:XWT, 3600, -3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
|
1097
|
+
assert_period(:XST, 3600, 0, false, Time.utc(2000, 3, 1), Time.utc(2000, 4, 1), info)
|
1098
|
+
assert_period(:XWT, 3600, -3600, true, Time.utc(2000, 4, 1), Time.utc(2000, 5, 1), info)
|
1099
|
+
assert_period(:XST, 3600, 0, false, Time.utc(2000, 5, 1), nil, info)
|
1100
|
+
end
|
1101
|
+
end
|
1102
|
+
|
1103
|
+
def test_read_offset_negative_std_offset_dst_initial_dst
|
1104
|
+
# The zoneinfo files don't include the offset from standard time, so this
|
1105
|
+
# has to be derived by looking at changes in the total UTC offset.
|
1106
|
+
|
1107
|
+
offsets = [
|
1108
|
+
{:gmtoff => -100, :isdst => false, :abbrev => 'LMT'},
|
1109
|
+
{:gmtoff => 0, :isdst => true, :abbrev => 'XWT'},
|
1110
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST'}]
|
1111
|
+
|
1112
|
+
transitions = [
|
1113
|
+
{:at => Time.utc(2000, 1, 1), :offset_index => 1},
|
1114
|
+
{:at => Time.utc(2000, 2, 1), :offset_index => 2},
|
1115
|
+
{:at => Time.utc(2000, 3, 1), :offset_index => 1},
|
1116
|
+
{:at => Time.utc(2000, 4, 1), :offset_index => 2},
|
1117
|
+
{:at => Time.utc(2000, 5, 1), :offset_index => 1}]
|
1118
|
+
|
1119
|
+
tzif_test(offsets, transitions) do |path, format|
|
1120
|
+
info = ZoneinfoTimezoneInfo.new('Zone/NegativeStdOffsetDstInitialDst', path)
|
1121
|
+
assert_equal('Zone/NegativeStdOffsetDstInitialDst', info.identifier)
|
1122
|
+
|
1123
|
+
assert_period(:LMT, -100, 0, false, nil, Time.utc(2000, 1, 1), info)
|
1124
|
+
assert_period(:XWT, 3600, -3600, true, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
|
1125
|
+
assert_period(:XST, 3600, 0, false, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
|
1126
|
+
assert_period(:XWT, 3600, -3600, true, Time.utc(2000, 3, 1), Time.utc(2000, 4, 1), info)
|
1127
|
+
assert_period(:XST, 3600, 0, false, Time.utc(2000, 4, 1), Time.utc(2000, 5, 1), info)
|
1128
|
+
assert_period(:XWT, 3600, -3600, true, Time.utc(2000, 5, 1), nil, info)
|
1129
|
+
end
|
1130
|
+
end
|
1131
|
+
|
1132
|
+
def test_read_offset_prefer_base_offset_moves_to_dst_not_hour
|
1133
|
+
offsets = [
|
1134
|
+
{:gmtoff => -100, :isdst => false, :abbrev => 'LMT'},
|
1135
|
+
{:gmtoff => 0, :isdst => false, :abbrev => 'XST'},
|
1136
|
+
{:gmtoff => 1800, :isdst => true, :abbrev => 'XDT'},
|
1137
|
+
{:gmtoff => 1800, :isdst => false, :abbrev => 'XST'}]
|
1138
|
+
|
1139
|
+
transitions = [
|
1140
|
+
{:at => Time.utc(2000, 1, 1), :offset_index => 1},
|
1141
|
+
{:at => Time.utc(2000, 2, 1), :offset_index => 2},
|
1142
|
+
{:at => Time.utc(2000, 3, 1), :offset_index => 3}]
|
1143
|
+
|
1144
|
+
tzif_test(offsets, transitions) do |path, format|
|
1145
|
+
info = ZoneinfoTimezoneInfo.new('Zone/BaseOffsetMovesToDstNotHour', path)
|
1146
|
+
assert_equal('Zone/BaseOffsetMovesToDstNotHour', info.identifier)
|
1147
|
+
|
1148
|
+
assert_period(:LMT, -100, 0, false, nil, Time.utc(2000, 1, 1), info)
|
1149
|
+
assert_period(:XST, 0, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
|
1150
|
+
assert_period(:XDT, 0, 1800, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
|
1151
|
+
assert_period(:XST, 1800, 0, false, Time.utc(2000, 3, 1), nil, info)
|
1152
|
+
end
|
1153
|
+
end
|
1154
|
+
|
1155
|
+
def test_read_offset_prefer_base_offset_moves_from_dst_not_hour
|
1156
|
+
offsets = [
|
1157
|
+
{:gmtoff => -100, :isdst => false, :abbrev => 'LMT'},
|
1158
|
+
{:gmtoff => 1800, :isdst => false, :abbrev => 'XST'},
|
1159
|
+
{:gmtoff => 1800, :isdst => true, :abbrev => 'XDT'},
|
1160
|
+
{:gmtoff => 0, :isdst => false, :abbrev => 'XST'}]
|
1161
|
+
|
1162
|
+
transitions = [
|
1163
|
+
{:at => Time.utc(2000, 1, 1), :offset_index => 1},
|
1164
|
+
{:at => Time.utc(2000, 2, 1), :offset_index => 2},
|
1165
|
+
{:at => Time.utc(2000, 3, 1), :offset_index => 3}]
|
1166
|
+
|
1167
|
+
tzif_test(offsets, transitions) do |path, format|
|
1168
|
+
info = ZoneinfoTimezoneInfo.new('Zone/BaseOffsetMovesFromDstNotHour', path)
|
1169
|
+
assert_equal('Zone/BaseOffsetMovesFromDstNotHour', info.identifier)
|
1170
|
+
|
1171
|
+
assert_period(:LMT, -100, 0, false, nil, Time.utc(2000, 1, 1), info)
|
1172
|
+
assert_period(:XST, 1800, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
|
1173
|
+
assert_period(:XDT, 0, 1800, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
|
1174
|
+
assert_period(:XST, 0, 0, false, Time.utc(2000, 3, 1), nil, info)
|
1175
|
+
end
|
1176
|
+
end
|
1177
|
+
|
1178
|
+
def test_load_in_safe_mode
|
1179
|
+
offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
|
1180
|
+
|
1181
|
+
tzif_test(offsets, []) do |path, format|
|
1182
|
+
# untaint only required for Ruby 1.9.2
|
1183
|
+
path.untaint
|
1184
|
+
|
1185
|
+
safe_test do
|
1186
|
+
info = ZoneinfoTimezoneInfo.new('Zone/three', path)
|
1187
|
+
assert_equal('Zone/three', info.identifier)
|
1188
|
+
|
1189
|
+
assert_period(:LT, -12094, 0, false, nil, nil, info)
|
1190
|
+
end
|
1191
|
+
end
|
1192
|
+
end
|
1193
|
+
|
1194
|
+
def test_load_encoding
|
1195
|
+
# tzfile.5 doesn't specify an encoding, but the source data is in ASCII.
|
1196
|
+
# ZoneinfoTimezoneInfo will load as UTF-8 (a superset of ASCII).
|
1197
|
+
|
1198
|
+
offsets = [
|
1199
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
1200
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST©'}]
|
1201
|
+
|
1202
|
+
transitions = [
|
1203
|
+
{:at => Time.utc(1971, 1, 2), :offset_index => 1}]
|
1204
|
+
|
1205
|
+
tzif_test(offsets, transitions) do |path, format|
|
1206
|
+
info = ZoneinfoTimezoneInfo.new('Zone/One', path)
|
1207
|
+
assert_equal('Zone/One', info.identifier)
|
1208
|
+
|
1209
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.utc(1971, 1, 2), info)
|
1210
|
+
assert_period(:"XST©", 3600, 0, false, Time.utc(1971, 1, 2), nil, info)
|
1211
|
+
end
|
1212
|
+
end
|
1213
|
+
|
1214
|
+
def test_load_binmode
|
1215
|
+
offsets = [
|
1216
|
+
{:gmtoff => 3542, :isdst => false, :abbrev => 'LMT'},
|
1217
|
+
{:gmtoff => 3600, :isdst => false, :abbrev => 'XST'}]
|
1218
|
+
|
1219
|
+
# Transition time that includes CRLF (4EFF0D0A).
|
1220
|
+
# Test that this doesn't get corrupted by translating CRLF to LF.
|
1221
|
+
transitions = [
|
1222
|
+
{:at => Time.utc(2011, 12, 31, 13, 24, 26), :offset_index => 1}]
|
1223
|
+
|
1224
|
+
tzif_test(offsets, transitions) do |path, format|
|
1225
|
+
info = ZoneinfoTimezoneInfo.new('Zone/One', path)
|
1226
|
+
assert_equal('Zone/One', info.identifier)
|
1227
|
+
|
1228
|
+
assert_period(:LMT, 3542, 0, false, nil, Time.utc(2011, 12, 31, 13, 24, 26), info)
|
1229
|
+
assert_period(:XST, 3600, 0, false, Time.utc(2011, 12, 31, 13, 24, 26), nil, info)
|
1230
|
+
end
|
1231
|
+
end
|
1232
|
+
end
|