tzinfo 1.2.5 → 1.2.9

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

Potentially problematic release.


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

Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +3 -3
  3. data.tar.gz.sig +0 -0
  4. data/CHANGES.md +86 -48
  5. data/LICENSE +1 -1
  6. data/README.md +9 -8
  7. data/lib/tzinfo.rb +3 -0
  8. data/lib/tzinfo/annual_rules.rb +51 -0
  9. data/lib/tzinfo/data_source.rb +1 -1
  10. data/lib/tzinfo/posix_time_zone_parser.rb +136 -0
  11. data/lib/tzinfo/ruby_core_support.rb +24 -1
  12. data/lib/tzinfo/ruby_data_source.rb +24 -20
  13. data/lib/tzinfo/time_or_datetime.rb +11 -0
  14. data/lib/tzinfo/timezone.rb +10 -6
  15. data/lib/tzinfo/transition_rule.rb +325 -0
  16. data/lib/tzinfo/zoneinfo_data_source.rb +10 -1
  17. data/lib/tzinfo/zoneinfo_timezone_info.rb +264 -40
  18. data/test/tc_annual_rules.rb +95 -0
  19. data/test/tc_country.rb +6 -2
  20. data/test/tc_posix_time_zone_parser.rb +261 -0
  21. data/test/tc_ruby_data_source.rb +26 -2
  22. data/test/tc_time_or_datetime.rb +26 -6
  23. data/test/tc_timezone.rb +13 -2
  24. data/test/tc_transition_data_timezone_info.rb +11 -1
  25. data/test/tc_transition_rule.rb +663 -0
  26. data/test/tc_zoneinfo_data_source.rb +11 -2
  27. data/test/tc_zoneinfo_timezone_info.rb +1034 -113
  28. data/test/test_utils.rb +32 -3
  29. data/test/ts_all_zoneinfo.rb +3 -1
  30. data/test/tzinfo-data/tzinfo/data/definitions/America/Argentina/Buenos_Aires.rb +5 -5
  31. data/test/tzinfo-data/tzinfo/data/definitions/America/New_York.rb +13 -1
  32. data/test/tzinfo-data/tzinfo/data/definitions/Australia/Melbourne.rb +13 -1
  33. data/test/tzinfo-data/tzinfo/data/definitions/EST.rb +1 -1
  34. data/test/tzinfo-data/tzinfo/data/definitions/Etc/GMT__m__1.rb +2 -2
  35. data/test/tzinfo-data/tzinfo/data/definitions/Etc/GMT__p__1.rb +2 -2
  36. data/test/tzinfo-data/tzinfo/data/definitions/Etc/UTC.rb +1 -1
  37. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Amsterdam.rb +15 -3
  38. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Andorra.rb +13 -1
  39. data/test/tzinfo-data/tzinfo/data/definitions/Europe/London.rb +13 -1
  40. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Paris.rb +15 -3
  41. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Prague.rb +19 -4
  42. data/test/tzinfo-data/tzinfo/data/definitions/UTC.rb +1 -1
  43. data/test/tzinfo-data/tzinfo/data/indexes/countries.rb +197 -184
  44. data/test/tzinfo-data/tzinfo/data/indexes/timezones.rb +60 -47
  45. data/test/tzinfo-data/tzinfo/data/version.rb +9 -3
  46. data/test/zoneinfo/America/Argentina/Buenos_Aires +0 -0
  47. data/test/zoneinfo/America/New_York +0 -0
  48. data/test/zoneinfo/Australia/Melbourne +0 -0
  49. data/test/zoneinfo/EST +0 -0
  50. data/test/zoneinfo/Etc/UTC +0 -0
  51. data/test/zoneinfo/Europe/Amsterdam +0 -0
  52. data/test/zoneinfo/Europe/Andorra +0 -0
  53. data/test/zoneinfo/Europe/London +0 -0
  54. data/test/zoneinfo/Europe/Paris +0 -0
  55. data/test/zoneinfo/Europe/Prague +0 -0
  56. data/test/zoneinfo/Factory +0 -0
  57. data/test/zoneinfo/iso3166.tab +13 -14
  58. data/test/zoneinfo/leapseconds +38 -21
  59. data/test/zoneinfo/posix/Europe/London +0 -0
  60. data/test/zoneinfo/posixrules +0 -0
  61. data/test/zoneinfo/right/Europe/London +0 -0
  62. data/test/zoneinfo/zone.tab +172 -159
  63. data/test/zoneinfo/zone1970.tab +185 -170
  64. data/tzinfo.gemspec +2 -2
  65. metadata +28 -24
  66. metadata.gz.sig +0 -0
@@ -0,0 +1,95 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), 'test_utils')
2
+
3
+ include TZInfo
4
+
5
+ class TCAnnualRules < Minitest::Test
6
+
7
+ def test_initialize
8
+ std_offset = TimezoneOffset.new(0, 0, 'GMT')
9
+ dst_offset = TimezoneOffset.new(0, 3600, 'BST')
10
+ dst_start_rule = FakeAlwaysDateAdjustmentRule.new(3, 1)
11
+ dst_end_rule = FakeAlwaysDateAdjustmentRule.new(10, 1)
12
+
13
+ rules = AnnualRules.new(std_offset, dst_offset, dst_start_rule, dst_end_rule)
14
+ assert_same(std_offset, rules.std_offset)
15
+ assert_same(dst_offset, rules.dst_offset)
16
+ assert_same(dst_start_rule, rules.dst_start_rule)
17
+ assert_same(dst_end_rule, rules.dst_end_rule)
18
+ end
19
+
20
+ [2020, 2021].each do |year|
21
+ define_method "test_transitions_for_dst_mid_year_#{year}" do
22
+ std_offset = TimezoneOffset.new(3600, 0, 'TEST')
23
+ dst_offset = TimezoneOffset.new(3600, 3600, 'TESTS')
24
+
25
+ rules = AnnualRules.new(
26
+ std_offset,
27
+ dst_offset,
28
+ FakeAlwaysDateAdjustmentRule.new(3, 21),
29
+ FakeAlwaysDateAdjustmentRule.new(10, 22)
30
+ )
31
+
32
+ result = rules.transitions(year)
33
+
34
+ expected = [
35
+ AnnualRules::Transition.new(dst_offset, std_offset, TimeOrDateTime.wrap(Time.utc(year, 3, 21, 0, 0, 0) - 3600)),
36
+ AnnualRules::Transition.new(std_offset, dst_offset, TimeOrDateTime.wrap(Time.utc(year, 10, 22, 0, 0, 0) - 7200))
37
+ ]
38
+
39
+ assert_equal(expected, result)
40
+ end
41
+
42
+ define_method "test_transitions_for_dst_start_and_end_of_year_#{year}" do
43
+ std_offset = TimezoneOffset.new(3600, 0, 'TEST')
44
+ dst_offset = TimezoneOffset.new(3600, 3600, 'TESTS')
45
+
46
+ rules = AnnualRules.new(
47
+ std_offset,
48
+ dst_offset,
49
+ FakeAlwaysDateAdjustmentRule.new(10, 22),
50
+ FakeAlwaysDateAdjustmentRule.new(3, 21)
51
+ )
52
+
53
+ result = rules.transitions(year)
54
+
55
+ expected = [
56
+ AnnualRules::Transition.new(std_offset, dst_offset, TimeOrDateTime.wrap(Time.utc(year, 3, 21, 0, 0, 0) - 7200)),
57
+ AnnualRules::Transition.new(dst_offset, std_offset, TimeOrDateTime.wrap(Time.utc(year, 10, 22, 0, 0, 0) - 3600))
58
+ ]
59
+
60
+ assert_equal(expected, result)
61
+ end
62
+
63
+ define_method "test_transitions_for_negative_dst_start_and_end_of_year_#{year}" do
64
+ std_offset = TimezoneOffset.new(7200, 0, 'TEST')
65
+ dst_offset = TimezoneOffset.new(7200, -3600, 'TESTW')
66
+
67
+ rules = AnnualRules.new(
68
+ std_offset,
69
+ dst_offset,
70
+ FakeAlwaysDateAdjustmentRule.new(10, 22),
71
+ FakeAlwaysDateAdjustmentRule.new(3, 21)
72
+ )
73
+
74
+ result = rules.transitions(year)
75
+
76
+ expected = [
77
+ AnnualRules::Transition.new(std_offset, dst_offset, TimeOrDateTime.wrap(Time.utc(year, 3, 21, 0, 0, 0) - 3600)),
78
+ AnnualRules::Transition.new(dst_offset, std_offset, TimeOrDateTime.wrap(Time.utc(year, 10, 22, 0, 0, 0) - 7200))
79
+ ]
80
+
81
+ assert_equal(expected, result)
82
+ end
83
+ end
84
+
85
+ class FakeAlwaysDateAdjustmentRule
86
+ def initialize(month, day)
87
+ @month = month
88
+ @day = day
89
+ end
90
+
91
+ def at(offset, year)
92
+ TimeOrDateTime.wrap(Time.utc(year, @month, @day, 0, 0, 0) - offset.utc_total_offset)
93
+ end
94
+ end
95
+ end
data/test/tc_country.rb CHANGED
@@ -2,6 +2,10 @@ require File.join(File.expand_path(File.dirname(__FILE__)), 'test_utils')
2
2
 
3
3
  include TZInfo
4
4
 
5
+ # Use send as a workaround for erroneous 'wrong number of arguments' errors with
6
+ # JRuby 9.0.5.0 when calling methods with Java implementations. See #114.
7
+ send(:using, TaintExt) if Module.const_defined?(:TaintExt)
8
+
5
9
  class TCCountry < Minitest::Test
6
10
  def setup
7
11
  @orig_data_source = DataSource.get
@@ -46,7 +50,7 @@ class TCCountry < Minitest::Test
46
50
  def test_get_tainted_loaded
47
51
  Country.get('GB')
48
52
 
49
- safe_test do
53
+ safe_test(:unavailable => :skip) do
50
54
  code = 'GB'.dup.taint
51
55
  assert(code.tainted?)
52
56
  country = Country.get(code)
@@ -65,7 +69,7 @@ class TCCountry < Minitest::Test
65
69
  end
66
70
 
67
71
  def test_get_tainted_not_previously_loaded
68
- safe_test do
72
+ safe_test(:unavailable => :skip) do
69
73
  code = 'GB'.dup.taint
70
74
  assert(code.tainted?)
71
75
  country = Country.get(code)
@@ -0,0 +1,261 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), 'test_utils')
2
+
3
+ include TZInfo
4
+
5
+ class TCPosixTimeZoneParser < Minitest::Test
6
+ HOUR = 3600
7
+ MINUTE = 60
8
+
9
+ class << self
10
+ private
11
+
12
+ def append_time_to_rule(day_rule, time)
13
+ time ? "#{day_rule}/#{time}" : day_rule
14
+ end
15
+
16
+ def define_invalid_dst_rule_tests(type, rule)
17
+ define_method "test_#{type}_dst_start_rule_for_invalid_#{rule}" do
18
+ tz_string = "STD-1DST,#{rule},300"
19
+ assert_raises(InvalidPosixTimeZone) { @parser.parse(tz_string) }
20
+ end
21
+
22
+ define_method "test_#{type}_dst_end_rule_for_invalid_#{rule}" do
23
+ tz_string = "STD-1DST,60,#{rule}"
24
+ assert_raises(InvalidPosixTimeZone) { @parser.parse(tz_string) }
25
+ end
26
+ end
27
+ end
28
+
29
+ def setup
30
+ @parser = PosixTimeZoneParser.new
31
+ end
32
+
33
+ def test_empty_rule_returns_nil
34
+ result = @parser.parse('')
35
+ assert_nil(result)
36
+ end
37
+
38
+ ABBREVIATIONS_WITH_OFFSETS = [
39
+ ['UTC0', :UTC, 0],
40
+ ['U0', :U, 0],
41
+ ['West1', :West, -HOUR],
42
+ ['East-1', :East, HOUR],
43
+ ['<-05>5', :'-05', -5 * HOUR],
44
+ ['<+12>-12', :'+12', 12 * HOUR],
45
+ ['HMM2:30', :HMM, -(2 * HOUR + 30 * MINUTE)],
46
+ ['HHMM02:30', :HHMM, -(2 * HOUR + 30 * MINUTE)],
47
+ ['HHMM+02:30', :HHMM, -(2 * HOUR + 30 * MINUTE)],
48
+ ['HHMSS-12:5:50', :HHMSS, 12 * HOUR + 5 * MINUTE + 50],
49
+ ['HHMMSS-12:05:50', :HHMMSS, 12 * HOUR + 5 * MINUTE + 50],
50
+ ['HHMMS-12:05:7', :HHMMS, 12 * HOUR + 5 * MINUTE + 7]
51
+ ]
52
+
53
+ ABBREVIATIONS_WITH_OFFSETS.each do |(tz_string, expected_abbrev, expected_base_offset)|
54
+ define_method "test_std_only_returns_std_offset_#{tz_string}" do
55
+ result = @parser.parse(tz_string)
56
+ expected = TimezoneOffset.new(expected_base_offset, 0, expected_abbrev)
57
+ assert_equal(expected, result)
58
+ end
59
+ end
60
+
61
+ ABBREVIATIONS_WITH_OFFSETS.each do |(abbrev_and_offset, expected_abbrev, expected_base_offset)|
62
+ define_method "test_std_offset_#{abbrev_and_offset}" do
63
+ result = @parser.parse(abbrev_and_offset + 'DST,60,300')
64
+ expected_std_offset = TimezoneOffset.new(expected_base_offset, 0, expected_abbrev)
65
+ assert_equal(expected_std_offset, result.std_offset)
66
+ end
67
+ end
68
+
69
+ [
70
+ ['Zero0One-1', :One, 0, HOUR],
71
+ ['Zero0One', :One, 0, HOUR],
72
+ ['Z0O', :O, 0, HOUR],
73
+ ['West1WestS0', :WestS, -HOUR, HOUR],
74
+ ['West1WestS', :WestS, -HOUR, HOUR],
75
+ ['East-1EastS-2', :EastS, HOUR, HOUR],
76
+ ['East-1EastS', :EastS, HOUR, HOUR],
77
+ ['Neg2NegS3', :NegS, -2 * HOUR, -HOUR],
78
+ ['<-05>5<-04>4', :'-04', -5 * HOUR, HOUR],
79
+ ['STD5<-04>4', :'-04', -5 * HOUR, HOUR],
80
+ ['<+12>-12<+13>-13', :'+13', 12 * HOUR, HOUR],
81
+ ['STD-12<+13>-13', :'+13', 12 * HOUR, HOUR],
82
+ ['HMM2:30SHMM1:15', :SHMM, -(2 * HOUR + 30 * MINUTE), HOUR + 15 * MINUTE],
83
+ ['HHMM02:30SHHMM01:15', :SHHMM, -(2 * HOUR + 30 * MINUTE), HOUR + 15 * MINUTE],
84
+ ['HHMM+02:30SHHMM+01:15', :SHHMM, -(2 * HOUR + 30 * MINUTE), HOUR + 15 * MINUTE],
85
+ ['HHMSS-12:5:50SHHMSS-13:4:30', :SHHMSS, 12 * HOUR + 5 * MINUTE + 50, 58 * MINUTE + 40],
86
+ ['HHMMSS-12:05:50SHHMMSS-13:04:30', :SHHMMSS, 12 * HOUR + 5 * MINUTE + 50, 58 * MINUTE + 40],
87
+ ['HHMMS-12:05:7SHHMMSS-13:06:8', :SHHMMSS, 12 * HOUR + 5 * MINUTE + 7, HOUR + MINUTE + 1],
88
+ ].each do |(abbrevs_and_offsets, expected_abbrev, expected_base_offset, expected_std_offset)|
89
+ define_method "test_dst_offset_#{abbrevs_and_offsets}" do
90
+ result = @parser.parse(abbrevs_and_offsets + ',60,300')
91
+ expected_dst_offset = TimezoneOffset.new(expected_base_offset, expected_std_offset, expected_abbrev)
92
+ assert_equal(expected_dst_offset, result.dst_offset)
93
+ end
94
+ end
95
+
96
+ ['<M-1>01:-1', '<M60>01:60', '<S-1>01:00:-1', '<S60>01:00:60'].each do |abbrev_and_offset|
97
+ ['', 'DST,60,300'].each do |dst_suffix|
98
+ tz_string = abbrev_and_offset + dst_suffix
99
+ define_method "test_std_offset_invalid_#{tz_string}" do
100
+ assert_raises(InvalidPosixTimeZone) { @parser.parse(tz_string) }
101
+ end
102
+ end
103
+
104
+ tz_string = "STD1#{abbrev_and_offset},60,300"
105
+ define_method "test_dst_offset_invalid_#{tz_string}" do
106
+ assert_raises(InvalidPosixTimeZone) { @parser.parse(tz_string) }
107
+ end
108
+ end
109
+
110
+ [
111
+ [nil, 2 * HOUR],
112
+ ['2', 2 * HOUR],
113
+ ['+2', 2 * HOUR],
114
+ ['-2', -2 * HOUR],
115
+ ['2:3:4', 2 * HOUR + 3 * MINUTE + 4],
116
+ ['02:03:04', 2 * HOUR + 3 * MINUTE + 4],
117
+ ['-2:3:4', -2 * HOUR + 3 * MINUTE + 4], # 22:03:04 on the day prior to the one specified
118
+ ['-02:03:04', -2 * HOUR + 3 * MINUTE + 4],
119
+ ['167', 167 * HOUR],
120
+ ['-167', -167 * HOUR]
121
+ ].each do |(time, expected_offset_from_midnight)|
122
+ [
123
+ ['J1', 1],
124
+ ['J365', 365]
125
+ ].each do |(julian_day_rule, expected_julian_day)|
126
+ rule = append_time_to_rule(julian_day_rule, time)
127
+
128
+ define_method "test_julian_day_dst_start_rule_for_#{rule}" do
129
+ result = @parser.parse("STD-1DST,#{rule},300")
130
+ expected_dst_start_rule = JulianDayOfYearTransitionRule.new(expected_julian_day, expected_offset_from_midnight)
131
+ assert_equal(expected_dst_start_rule, result.dst_start_rule)
132
+ end
133
+
134
+ define_method "test_julian_day_dst_end_rule_for_#{rule}" do
135
+ result = @parser.parse("STD-1DST,60,#{rule}")
136
+ expected_dst_end_rule = JulianDayOfYearTransitionRule.new(expected_julian_day, expected_offset_from_midnight)
137
+ assert_equal(expected_dst_end_rule, result.dst_end_rule)
138
+ end
139
+ end
140
+
141
+ [
142
+ ['0', 0],
143
+ ['365', 365]
144
+ ].each do |(absolute_day_rule, expected_day)|
145
+ rule = append_time_to_rule(absolute_day_rule, time)
146
+
147
+ define_method "test_absolute_day_dst_start_rule_for_#{rule}" do
148
+ result = @parser.parse("STD-1DST,#{rule},J300")
149
+ expected_dst_start_rule = AbsoluteDayOfYearTransitionRule.new(expected_day, expected_offset_from_midnight)
150
+ assert_equal(expected_dst_start_rule, result.dst_start_rule)
151
+ end
152
+
153
+ define_method "test_absolute_day_dst_end_rule_for_#{rule}" do
154
+ result = @parser.parse("STD-1DST,J60,#{rule}")
155
+ expected_dst_end_rule = AbsoluteDayOfYearTransitionRule.new(expected_day, expected_offset_from_midnight)
156
+ assert_equal(expected_dst_end_rule, result.dst_end_rule)
157
+ end
158
+ end
159
+
160
+ [
161
+ ['M1.1.0', 1, 1, 0],
162
+ ['M12.4.6', 12, 4, 6]
163
+ ].each do |(day_of_month_rule, expected_month, expected_week, expected_day_of_week)|
164
+ rule = append_time_to_rule(day_of_month_rule, time)
165
+
166
+ define_method "test_day_of_month_dst_start_rule_for_#{rule}" do
167
+ result = @parser.parse("STD-1DST,#{rule},300")
168
+ expected_dst_start_rule = DayOfMonthTransitionRule.new(expected_month, expected_week, expected_day_of_week, expected_offset_from_midnight)
169
+ assert_equal(expected_dst_start_rule, result.dst_start_rule)
170
+ end
171
+
172
+ define_method "test_day_of_month_dst_end_rule_for_#{rule}" do
173
+ result = @parser.parse("STD-1DST,60,#{rule}")
174
+ expected_dst_end_rule = DayOfMonthTransitionRule.new(expected_month, expected_week, expected_day_of_week, expected_offset_from_midnight)
175
+ assert_equal(expected_dst_end_rule, result.dst_end_rule)
176
+ end
177
+ end
178
+
179
+ [
180
+ ['M1.5.0', 1, 0],
181
+ ['M12.5.6', 12, 6]
182
+ ].each do |(last_day_of_month_rule, expected_month, expected_day_of_week)|
183
+ rule = append_time_to_rule(last_day_of_month_rule, time)
184
+
185
+ define_method "test_last_day_of_month_dst_start_rule_for_#{rule}" do
186
+ result = @parser.parse("STD-1DST,#{rule},300")
187
+ expected_dst_start_rule = LastDayOfMonthTransitionRule.new(expected_month, expected_day_of_week, expected_offset_from_midnight)
188
+ assert_equal(expected_dst_start_rule, result.dst_start_rule)
189
+ end
190
+
191
+ define_method "test_last_day_of_month_dst_end_rule_for_#{rule}" do
192
+ result = @parser.parse("STD-1DST,60,#{rule}")
193
+ expected_dst_end_rule = LastDayOfMonthTransitionRule.new(expected_month, expected_day_of_week, expected_offset_from_midnight)
194
+ assert_equal(expected_dst_end_rule, result.dst_end_rule)
195
+ end
196
+ end
197
+ end
198
+
199
+ ['J0', 'J366'].each do |julian_day_rule|
200
+ define_invalid_dst_rule_tests('julian_day', julian_day_rule)
201
+ end
202
+
203
+ ['-1', '366'].each do |absolute_day_rule|
204
+ define_invalid_dst_rule_tests('absolute_day', absolute_day_rule)
205
+ end
206
+
207
+ ['M0,1,0', 'M13,1,0', 'M6,0,0', 'M6,6,0', 'M6,1,-1', 'M6,1,7'].each do |day_of_month_rule|
208
+ define_invalid_dst_rule_tests('day_of_month', day_of_month_rule)
209
+ end
210
+
211
+ ['M0,5,0', 'M13,5,0', 'M6,5,-1', 'M6,5,7'].each do |last_day_of_month_rule|
212
+ define_invalid_dst_rule_tests('last_day_of_month', last_day_of_month_rule)
213
+ end
214
+
215
+ def test_invalid_dst_start_rule
216
+ assert_raises(InvalidPosixTimeZone) { @parser.parse('STD1DST,X60,300') }
217
+ end
218
+
219
+ def test_invalid_dst_end_rule
220
+ assert_raises(InvalidPosixTimeZone) { @parser.parse('STD1DST,60,X300') }
221
+ end
222
+
223
+ [
224
+ ['STD5DST,0/0,J365/25', :DST, -5 * HOUR, HOUR],
225
+ ['STD-5DST,0/0,J365/25', :DST, 5 * HOUR, HOUR],
226
+ ['STD5DST3,0/0,J365/26', :DST, -5 * HOUR, 2 * HOUR],
227
+ ['STD5DST6,0/0,J365/23', :DST, -5 * HOUR, -HOUR],
228
+ ['STD5DST,J1/0,J365/25', :DST, -5 * HOUR, HOUR],
229
+ ['Winter5Summer,0/0,J365/25', :Summer, -5 * HOUR, HOUR],
230
+ ['<-05>5<-06>,0/0,J365/25', :'-06', -5 * HOUR, HOUR]
231
+ ].each do |(tz_string, expected_abbrev, expected_base_offset, expected_std_offset)|
232
+ define_method "test_dst_only_returns_continuous_offset_for_#{tz_string}" do
233
+ result = @parser.parse(tz_string)
234
+ expected = TimezoneOffset.new(expected_base_offset, expected_std_offset, expected_abbrev)
235
+ assert_equal(expected, result)
236
+ end
237
+ end
238
+
239
+ def test_parses_tainted_string_in_safe_mode_and_returns_untainted_abbreviations
240
+ safe_test(:unavailable => :skip) do
241
+ result = @parser.parse('STD1DST,60,300'.dup.taint)
242
+
243
+ assert_equal(:STD, result.std_offset.abbreviation)
244
+ assert_equal(:DST, result.dst_offset.abbreviation)
245
+ end
246
+ end
247
+
248
+ ['STD1', 'STD1DST,60,300'].each do |tz_string|
249
+ tz_string += "-"
250
+ define_method "test_content_after_end_for_#{tz_string}" do
251
+ error = assert_raises(InvalidPosixTimeZone) { @parser.parse(tz_string) }
252
+ assert_equal("Expected the end of a POSIX-style time zone string but found '-'.", error.message)
253
+ end
254
+ end
255
+
256
+ ['X', 0].each do |invalid_tz_string|
257
+ define_method "test_invalid_tz_string_#{invalid_tz_string}" do
258
+ assert_raises(InvalidPosixTimeZone) { @parser.parse(invalid_tz_string) }
259
+ end
260
+ end
261
+ end
@@ -2,11 +2,31 @@ require File.join(File.expand_path(File.dirname(__FILE__)), 'test_utils')
2
2
 
3
3
  include TZInfo
4
4
 
5
+ # Use send as a workaround for erroneous 'wrong number of arguments' errors with
6
+ # JRuby 9.0.5.0 when calling methods with Java implementations. See #114.
7
+ send(:using, TaintExt) if Module.const_defined?(:TaintExt)
8
+
5
9
  class TCRubyDataSource < Minitest::Test
6
10
  def setup
7
11
  @data_source = RubyDataSource.new
8
12
  end
9
13
 
14
+ def test_initialize_not_found
15
+ # A failure to load tzinfo/data in initialize will not cause an exception.
16
+ # Attempts to load data files will subsequently fail.
17
+ code = <<-EOF
18
+ begin
19
+ ds = TZInfo::RubyDataSource.new
20
+ puts 'Initialized'
21
+ ds.load_timezone_info('Europe/London')
22
+ rescue Exception => e
23
+ puts e.class
24
+ end
25
+ EOF
26
+
27
+ assert_sub_process_returns(['Initialized', 'TZInfo::InvalidTimezoneIdentifier'], code)
28
+ end
29
+
10
30
  def test_load_timezone_info_data
11
31
  info = @data_source.load_timezone_info('Europe/London')
12
32
  assert_kind_of(DataTimezoneInfo, info)
@@ -55,7 +75,9 @@ class TCRubyDataSource < Minitest::Test
55
75
  end
56
76
 
57
77
  def test_load_timezone_info_tainted
58
- safe_test do
78
+ skip_if_has_bug_14060
79
+
80
+ safe_test(:unavailable => :skip) do
59
81
  identifier = 'Europe/Amsterdam'.dup.taint
60
82
  assert(identifier.tainted?)
61
83
  info = @data_source.load_timezone_info(identifier)
@@ -65,6 +87,8 @@ class TCRubyDataSource < Minitest::Test
65
87
  end
66
88
 
67
89
  def test_load_timezone_info_tainted_and_frozen
90
+ skip_if_has_bug_14060
91
+
68
92
  safe_test do
69
93
  info = @data_source.load_timezone_info('Europe/Amsterdam'.dup.taint.freeze)
70
94
  assert_equal('Europe/Amsterdam', info.identifier)
@@ -119,7 +143,7 @@ class TCRubyDataSource < Minitest::Test
119
143
  end
120
144
 
121
145
  def test_load_country_info_tainted
122
- safe_test do
146
+ safe_test(:unavailable => :skip) do
123
147
  code = 'NL'.dup.taint
124
148
  assert(code.tainted?)
125
149
  info = @data_source.load_country_info(code)
@@ -4,6 +4,12 @@ require 'rational' unless defined?(Rational)
4
4
  include TZInfo
5
5
 
6
6
  class TCTimeOrDateTime < Minitest::Test
7
+ # Ruby 1.8.7 (built with GCC 8.3.0 on Ubuntu 19.04) fails to perform DateTime
8
+ # arithmetic operations correctly when sub-seconds are used. Detect this and
9
+ # disable the affected tests.
10
+ DATETIME_SUBSECOND_ARITHMETIC_IS_BROKEN = (DateTime.new(2019, 12, 22, 15, 0, Rational(1, 1000)) + Rational(1, 86400)).strftime('%Q') != '1577026801001'
11
+ puts "DateTime sub-second arithmetic is broken on this platform" if DATETIME_SUBSECOND_ARITHMETIC_IS_BROKEN
12
+
7
13
  def test_initialize_time
8
14
  assert_nothing_raised do
9
15
  TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3, 721000))
@@ -243,6 +249,20 @@ class TCTimeOrDateTime < Minitest::Test
243
249
  assert_equal(24, TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3)).day)
244
250
  assert_equal(24, TimeOrDateTime.new(1143214323).day)
245
251
  end
252
+
253
+ 19.upto(25).each_with_index do |mday,i|
254
+ define_method "test_wday_time_#{i}" do
255
+ assert_equal(i, TimeOrDateTime.new(Time.utc(2006, 3, mday)).wday)
256
+ end
257
+
258
+ define_method "test_wday_datetime_#{i}" do
259
+ assert_equal(i, TimeOrDateTime.new(DateTime.new(2006, 3, mday)).wday)
260
+ end
261
+
262
+ define_method "test_wday_timestamp_#{i}" do
263
+ assert_equal(i, TimeOrDateTime.new(Time.utc(2006, 3, mday).to_i).wday)
264
+ end
265
+ end
246
266
 
247
267
  def test_hour
248
268
  assert_equal(15, TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3)).hour)
@@ -500,12 +520,12 @@ class TCTimeOrDateTime < Minitest::Test
500
520
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 4), (TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3)) + 1).to_orig)
501
521
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 4, 721000), (TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3, 721000)) + 1).to_orig)
502
522
  assert_equal(DateTime.new(2006, 3, 24, 15, 32, 4), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3)) + 1).to_orig)
503
- assert_equal(DateTime.new(2006, 3, 24, 15, 32, 4 + Rational(721, 1000)), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))) + 1).to_orig)
523
+ assert_equal(DateTime.new(2006, 3, 24, 15, 32, 4 + Rational(721, 1000)), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))) + 1).to_orig) unless DATETIME_SUBSECOND_ARITHMETIC_IS_BROKEN
504
524
  assert_equal(1143214324, (TimeOrDateTime.new(1143214323) + 1).to_orig)
505
525
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 2), (TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3)) + (-1)).to_orig)
506
526
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 2, 721000), (TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3, 721000)) + (-1)).to_orig)
507
527
  assert_equal(DateTime.new(2006, 3, 24, 15, 32, 2), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3)) + (-1)).to_orig)
508
- assert_equal(DateTime.new(2006, 3, 24, 15, 32, 2 + Rational(721, 1000)), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))) + (-1)).to_orig)
528
+ assert_equal(DateTime.new(2006, 3, 24, 15, 32, 2 + Rational(721, 1000)), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))) + (-1)).to_orig) unless DATETIME_SUBSECOND_ARITHMETIC_IS_BROKEN
509
529
  assert_equal(1143214322, (TimeOrDateTime.new(1143214323) + (-1)).to_orig)
510
530
  end
511
531
 
@@ -518,12 +538,12 @@ class TCTimeOrDateTime < Minitest::Test
518
538
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 2), (TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3)) - 1).to_orig)
519
539
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 2, 721000), (TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3, 721000)) - 1).to_orig)
520
540
  assert_equal(DateTime.new(2006, 3, 24, 15, 32, 2), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3)) - 1).to_orig)
521
- assert_equal(DateTime.new(2006, 3, 24, 15, 32, 2 + Rational(721, 1000)), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))) - 1).to_orig)
541
+ assert_equal(DateTime.new(2006, 3, 24, 15, 32, 2 + Rational(721, 1000)), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))) - 1).to_orig) unless DATETIME_SUBSECOND_ARITHMETIC_IS_BROKEN
522
542
  assert_equal(1143214322, (TimeOrDateTime.new(1143214323) - 1).to_orig)
523
543
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 4), (TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3)) - (-1)).to_orig)
524
544
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 4, 721000), (TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3, 721000)) - (-1)).to_orig)
525
545
  assert_equal(DateTime.new(2006, 3, 24, 15, 32, 4), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3)) - (-1)).to_orig)
526
- assert_equal(DateTime.new(2006, 3, 24, 15, 32, 4 + Rational(721, 1000)), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))) - (-1)).to_orig)
546
+ assert_equal(DateTime.new(2006, 3, 24, 15, 32, 4 + Rational(721, 1000)), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))) - (-1)).to_orig) unless DATETIME_SUBSECOND_ARITHMETIC_IS_BROKEN
527
547
  assert_equal(1143214324, (TimeOrDateTime.new(1143214323) - (-1)).to_orig)
528
548
  end
529
549
 
@@ -536,12 +556,12 @@ class TCTimeOrDateTime < Minitest::Test
536
556
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 4), TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3)).add_with_convert(1).to_orig)
537
557
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 4, 721000), TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3, 721000)).add_with_convert(1).to_orig)
538
558
  assert_equal(DateTime.new(2006, 3, 24, 15, 32, 4), TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3)).add_with_convert(1).to_orig)
539
- assert_equal(DateTime.new(2006, 3, 24, 15, 32, 4 + Rational(721, 1000)), TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))).add_with_convert(1).to_orig)
559
+ assert_equal(DateTime.new(2006, 3, 24, 15, 32, 4 + Rational(721, 1000)), TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))).add_with_convert(1).to_orig) unless DATETIME_SUBSECOND_ARITHMETIC_IS_BROKEN
540
560
  assert_equal(1143214324, TimeOrDateTime.new(1143214323).add_with_convert(1).to_orig)
541
561
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 2), TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3)).add_with_convert(-1).to_orig)
542
562
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 2, 721000), TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3, 721000)).add_with_convert(-1).to_orig)
543
563
  assert_equal(DateTime.new(2006, 3, 24, 15, 32, 2), TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3)).add_with_convert(-1).to_orig)
544
- assert_equal(DateTime.new(2006, 3, 24, 15, 32, 2 + Rational(721, 1000)), TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))).add_with_convert(-1).to_orig)
564
+ assert_equal(DateTime.new(2006, 3, 24, 15, 32, 2 + Rational(721, 1000)), TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))).add_with_convert(-1).to_orig) unless DATETIME_SUBSECOND_ARITHMETIC_IS_BROKEN
545
565
  assert_equal(1143214322, TimeOrDateTime.new(1143214323).add_with_convert(-1).to_orig)
546
566
 
547
567
  if RubyCoreSupport.time_supports_negative