tzinfo 1.2.4 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 22c796619ab55ca7900b6a7e0d8425d60ed8fad9
4
- data.tar.gz: f927925f60e7df68cd3564d372d4c5265692b699
2
+ SHA256:
3
+ metadata.gz: ff316f9ef3e063d02096d2d1841b832491e315d78610d8751b09115632794e9f
4
+ data.tar.gz: b695fca6cdc7af5cd356dbb592aacc81c861d64e05375a5c6238c9ae924fe8be
5
5
  SHA512:
6
- metadata.gz: 91388068fe7de3fbc4914581ecd0dd1f33fb3c823c4c935a1da11dc9f6fb8dbccd3efed7c9e9d6052cf4414e24c42656cd7685d0899b18e040be1980fdb771c3
7
- data.tar.gz: e7fe2fd2dafb218bf3cb2020359853f4571c0b99abd0ff11880e6102cb010d9dda847408dd4c26b571aa3109a565b8fec9fcfb2e6dc405a17992579c81892ec7
6
+ metadata.gz: 6ab8e7340dd1eafa73c385e388d49c2bf07203e855b3410c6302abc9b5e5b9992f1cfdb9aa5dc5dc59664f713618e25eac7489b7be5209a5987162e90cfe48d9
7
+ data.tar.gz: 5db4b130ed3db4b07d350b6acb020781d6538c9f9295d478b297fe994c2ac4220dbd76097ed2c5a26219cdf6ec10bb18df6816f904cdd0c5ac1193782730785c
Binary file
data.tar.gz.sig CHANGED
Binary file
data/CHANGES.md CHANGED
@@ -1,3 +1,12 @@
1
+ Version 1.2.5 - 4-Feb-2018
2
+ --------------------------
3
+
4
+ * Support recursively (deep) freezing Country and Timezone instances. #80.
5
+ * Allow negative daylight savings time offsets to be derived when reading from
6
+ zoneinfo files. The utc_offset and std_offset are now derived correctly for
7
+ Europe/Dublin in the 2018a and 2018b releases of the Time Zone Database.
8
+
9
+
1
10
  Version 1.2.4 - 26-Oct-2017
2
11
  ---------------------------
3
12
 
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2005-2017 Philip Ross
1
+ Copyright (c) 2005-2018 Philip Ross
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of
4
4
  this software and associated documentation files (the "Software"), to deal in
@@ -79,7 +79,13 @@ module TZInfo
79
79
  # calculated multiple times in concurrently executing threads. It is not
80
80
  # worth the overhead of locking to ensure that @latitude is only
81
81
  # calculated once.
82
- @latitude ||= RubyCoreSupport.rational_new!(@latitude_numerator, @latitude_denominator)
82
+ unless @latitude
83
+ result = RubyCoreSupport.rational_new!(@latitude_numerator, @latitude_denominator)
84
+ return result if frozen?
85
+ @latitude = result
86
+ end
87
+
88
+ @latitude
83
89
  end
84
90
 
85
91
  # The longitude of this timezone in degrees as a Rational.
@@ -88,7 +94,13 @@ module TZInfo
88
94
  # calculated multiple times in concurrently executing threads. It is not
89
95
  # worth the overhead of locking to ensure that @longitude is only
90
96
  # calculated once.
91
- @longitude ||= RubyCoreSupport.rational_new!(@longitude_numerator, @longitude_denominator)
97
+ unless @longitude
98
+ result = RubyCoreSupport.rational_new!(@longitude_numerator, @longitude_denominator)
99
+ return result if frozen?
100
+ @longitude = result
101
+ end
102
+
103
+ @longitude
92
104
  end
93
105
 
94
106
  # Returns true if and only if the given CountryTimezone is equal to the
@@ -22,7 +22,9 @@ module TZInfo
22
22
  # calculated once.
23
23
 
24
24
  unless @zone_identifiers
25
- @zone_identifiers = zones.collect {|zone| zone.identifier}.freeze
25
+ result = zones.collect {|zone| zone.identifier}.freeze
26
+ return result if frozen?
27
+ @zone_identifiers = result
26
28
  end
27
29
 
28
30
  @zone_identifiers
@@ -40,8 +42,10 @@ module TZInfo
40
42
  unless @zones
41
43
  zones = Zones.new
42
44
  @block.call(zones) if @block
45
+ result = zones.list.freeze
46
+ return result if frozen?
43
47
  @block = nil
44
- @zones = zones.list.freeze
48
+ @zones = result
45
49
  end
46
50
 
47
51
  @zones
@@ -54,11 +54,14 @@ module TZInfo
54
54
  # calculated once.
55
55
 
56
56
  unless @time
57
- if @timestamp
58
- @time = Time.at(@timestamp).utc
57
+ result = if @timestamp
58
+ Time.at(@timestamp).utc
59
59
  else
60
- @time = Time.utc(year, mon, mday, hour, min, sec, usec)
60
+ Time.utc(year, mon, mday, hour, min, sec, usec)
61
61
  end
62
+
63
+ return result if frozen?
64
+ @time = result
62
65
  end
63
66
 
64
67
  @time
@@ -78,7 +81,9 @@ module TZInfo
78
81
  # Avoid using Rational unless necessary.
79
82
  u = usec
80
83
  s = u == 0 ? sec : Rational(sec * 1000000 + u, 1000000)
81
- @datetime = RubyCoreSupport.datetime_new(year, mon, mday, hour, min, s)
84
+ result = RubyCoreSupport.datetime_new(year, mon, mday, hour, min, s)
85
+ return result if frozen?
86
+ @datetime = result
82
87
  end
83
88
 
84
89
  @datetime
@@ -92,7 +97,9 @@ module TZInfo
92
97
  # calculated once.
93
98
 
94
99
  unless @timestamp
95
- @timestamp = to_time.to_i
100
+ result = to_time.to_i
101
+ return result if frozen?
102
+ @timestamp = result
96
103
  end
97
104
 
98
105
  @timestamp
@@ -1,11 +1,34 @@
1
1
  module TZInfo
2
2
  # Represents an offset defined in a Timezone data file.
3
3
  class TimezoneOffset
4
- # The base offset of the timezone from UTC in seconds.
4
+ # The base offset of the timezone from UTC in seconds. This does not include
5
+ # any adjustment made for daylight savings time and will typically remain
6
+ # constant throughout the year.
7
+ #
8
+ # To obtain the currently observed offset from UTC, including the effect of
9
+ # daylight savings time, use utc_total_offset instead.
10
+ #
11
+ # Note that zoneinfo files only include the value of utc_total_offset and a
12
+ # DST flag. When using ZoneinfoDataSource, the utc_offset will be derived
13
+ # from changes to the UTC total offset and the DST flag. As a consequence,
14
+ # utc_total_offset will always be correct, but utc_offset may be inaccurate.
15
+ #
16
+ # If you require utc_offset to be accurate, install the tzinfo-data gem and
17
+ # set RubyDataSource as the DataSource.
5
18
  attr_reader :utc_offset
6
19
 
7
- # The offset from standard time for the zone in seconds (i.e. non-zero if
8
- # daylight savings is being observed).
20
+ # The offset from the time zone's standard time in seconds. Zero
21
+ # when daylight savings time is not in effect. Non-zero (usually 3600 = 1
22
+ # hour) if daylight savings is being observed.
23
+ #
24
+ # Note that zoneinfo files only include the value of utc_total_offset and
25
+ # a DST flag. When using DataSources::ZoneinfoDataSource, the std_offset
26
+ # will be derived from changes to the UTC total offset and the DST flag. As
27
+ # a consequence, utc_total_offset will always be correct, but std_offset
28
+ # may be inaccurate.
29
+ #
30
+ # If you require std_offset to be accurate, install the tzinfo-data gem
31
+ # and set RubyDataSource as the DataSource.
9
32
  attr_reader :std_offset
10
33
 
11
34
  # The total offset of this observance from UTC in seconds
@@ -38,14 +38,36 @@ module TZInfo
38
38
  @utc_total_offset_rational = nil
39
39
  end
40
40
 
41
- # Base offset of the timezone from UTC (seconds).
41
+ # The base offset of the timezone from UTC in seconds. This does not include
42
+ # any adjustment made for daylight savings time and will typically remain
43
+ # constant throughout the year.
44
+ #
45
+ # To obtain the currently observed offset from UTC, including the effect of
46
+ # daylight savings time, use utc_total_offset instead.
47
+ #
48
+ # Note that zoneinfo files only include the value of utc_total_offset and a
49
+ # DST flag. When using ZoneinfoDataSource, the utc_offset will be derived
50
+ # from changes to the UTC total offset and the DST flag. As a consequence,
51
+ # utc_total_offset will always be correct, but utc_offset may be inaccurate.
52
+ #
53
+ # If you require utc_offset to be accurate, install the tzinfo-data gem and
54
+ # set RubyDataSource as the DataSource.
42
55
  def utc_offset
43
56
  @offset.utc_offset
44
57
  end
45
58
 
46
- # Offset from the local time where daylight savings is in effect (seconds).
47
- # E.g.: utc_offset could be -5 hours. Normally, std_offset would be 0.
48
- # During daylight savings, std_offset would typically become +1 hours.
59
+ # The offset from the time zone's standard time in seconds. Zero
60
+ # when daylight savings time is not in effect. Non-zero (usually 3600 = 1
61
+ # hour) if daylight savings is being observed.
62
+ #
63
+ # Note that zoneinfo files only include the value of utc_total_offset and
64
+ # a DST flag. When using DataSources::ZoneinfoDataSource, the std_offset
65
+ # will be derived from changes to the UTC total offset and the DST flag. As
66
+ # a consequence, utc_total_offset will always be correct, but std_offset
67
+ # may be inaccurate.
68
+ #
69
+ # If you require std_offset to be accurate, install the tzinfo-data gem
70
+ # and set RubyDataSource as the DataSource.
49
71
  def std_offset
50
72
  @offset.std_offset
51
73
  end
@@ -71,7 +93,9 @@ module TZInfo
71
93
  # to ensure that @zone_identifiers is only calculated once.
72
94
 
73
95
  unless @utc_total_offset_rational
74
- @utc_total_offset_rational = OffsetRationals.rational_for_offset(utc_total_offset)
96
+ result = OffsetRationals.rational_for_offset(utc_total_offset)
97
+ return result if frozen?
98
+ @utc_total_offset_rational = result
75
99
  end
76
100
  @utc_total_offset_rational
77
101
  end
@@ -93,7 +93,13 @@ module TZInfo
93
93
  # calculated multiple times in concurrently executing threads. It is not
94
94
  # worth the overhead of locking to ensure that @real_timezone is only
95
95
  # calculated once.
96
- @real_timezone ||= Timezone.get(@identifier)
96
+ unless @real_timezone
97
+ result = Timezone.get(@identifier)
98
+ return result if frozen?
99
+ @real_timezone = result
100
+ end
101
+
102
+ @real_timezone
97
103
  end
98
104
  end
99
105
  end
@@ -43,7 +43,12 @@ module TZInfo
43
43
  # worth the overhead of locking to ensure that @local_end_at is only
44
44
  # calculated once.
45
45
 
46
- @local_end_at = at.add_with_convert(@previous_offset.utc_total_offset) unless @local_end_at
46
+ unless @local_end_at
47
+ result = at.add_with_convert(@previous_offset.utc_total_offset)
48
+ return result if frozen?
49
+ @local_end_at = result
50
+ end
51
+
47
52
  @local_end_at
48
53
  end
49
54
 
@@ -67,7 +72,12 @@ module TZInfo
67
72
  # worth the overhead of locking to ensure that @local_start_at is only
68
73
  # calculated once.
69
74
 
70
- @local_start_at = at.add_with_convert(@offset.utc_total_offset) unless @local_start_at
75
+ unless @local_start_at
76
+ result = at.add_with_convert(@offset.utc_total_offset)
77
+ return result if frozen?
78
+ @local_start_at = result
79
+ end
80
+
71
81
  @local_start_at
72
82
  end
73
83
 
@@ -71,13 +71,16 @@ module TZInfo
71
71
  # overhead of locking to ensure that @at is only calculated once.
72
72
 
73
73
  unless @at
74
- unless @denominator
75
- @at = TimeOrDateTime.new(@numerator_or_time)
74
+ result = unless @denominator
75
+ TimeOrDateTime.new(@numerator_or_time)
76
76
  else
77
77
  r = RubyCoreSupport.rational_new!(@numerator_or_time, @denominator)
78
78
  dt = RubyCoreSupport.datetime_new!(r, 0, Date::ITALY)
79
- @at = TimeOrDateTime.new(dt)
79
+ TimeOrDateTime.new(dt)
80
80
  end
81
+
82
+ return result if frozen?
83
+ @at = result
81
84
  end
82
85
 
83
86
  @at
@@ -20,7 +20,9 @@ module TZInfo
20
20
  # calculated once.
21
21
 
22
22
  unless @zone_identifiers
23
- @zone_identifiers = zones.collect {|zone| zone.identifier}.freeze
23
+ result = zones.collect {|zone| zone.identifier}.freeze
24
+ return result if frozen?
25
+ @zone_identifiers = result
24
26
  end
25
27
 
26
28
  @zone_identifiers
@@ -93,19 +93,21 @@ module TZInfo
93
93
  if offset[:is_dst]
94
94
  utc_offset_from_next = transition[:utc_offset_from_next]
95
95
 
96
- difference_to_previous = utc_total_offset - (utc_offset_from_previous || utc_total_offset)
97
- difference_to_next = utc_total_offset - (utc_offset_from_next || utc_total_offset)
96
+ difference_to_previous = (utc_total_offset - (utc_offset_from_previous || utc_total_offset)).abs
97
+ difference_to_next = (utc_total_offset - (utc_offset_from_next || utc_total_offset)).abs
98
98
 
99
- utc_offset = if difference_to_previous > 0 && difference_to_next > 0
99
+ utc_offset = if difference_to_previous == 3600
100
+ utc_offset_from_previous
101
+ elsif difference_to_next == 3600
102
+ utc_offset_from_next
103
+ elsif difference_to_previous > 0 && difference_to_next > 0
100
104
  difference_to_previous < difference_to_next ? utc_offset_from_previous : utc_offset_from_next
101
105
  elsif difference_to_previous > 0
102
106
  utc_offset_from_previous
103
107
  elsif difference_to_next > 0
104
108
  utc_offset_from_next
105
- else # difference_to_previous <= 0 && difference_to_next <= 0
106
- # DST, but the either the offset has stayed the same or decreased
107
- # relative to both the previous and next used base utc offset, or
108
- # there are no non-DST offsets. Assume a 1 hour offset from base.
109
+ else
110
+ # No difference, assume a 1 hour offset from standard time.
109
111
  utc_total_offset - 3600
110
112
  end
111
113
 
@@ -190,7 +190,6 @@ class TCCountry < Minitest::Test
190
190
  # If country gets reloaded for some reason, it needs to force a reload of
191
191
  # the country index.
192
192
 
193
- c = Country.get('US')
194
193
  assert_equal('US', Country.get('US').code)
195
194
 
196
195
  # Suppress redefined method warnings.
@@ -198,7 +197,6 @@ class TCCountry < Minitest::Test
198
197
  load 'tzinfo/country.rb'
199
198
  end
200
199
 
201
- c = Country.get('US')
202
200
  assert_equal('US', Country.get('US').code)
203
201
  end
204
202
 
@@ -17,6 +17,12 @@ class TCCountryTimezone < Minitest::Test
17
17
  ct = CountryTimezone.new!('Europe/London', 2059, 40, -5, 16)
18
18
  assert_equal(Rational(2059, 40), ct.latitude)
19
19
  end
20
+
21
+ def test_latitude_after_freeze_new!
22
+ ct = CountryTimezone.new!('Europe/London', 2059, 40, -5, 16)
23
+ ct.freeze
24
+ assert_equal(Rational(2059, 40), ct.latitude)
25
+ end
20
26
 
21
27
  def test_latitude_new
22
28
  ct = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-5, 16))
@@ -27,6 +33,12 @@ class TCCountryTimezone < Minitest::Test
27
33
  ct = CountryTimezone.new!('Europe/London', 2059, 40, -5, 16)
28
34
  assert_equal(Rational(-5, 16), ct.longitude)
29
35
  end
36
+
37
+ def test_longitude_after_freeze_new!
38
+ ct = CountryTimezone.new!('Europe/London', 2059, 40, -5, 16)
39
+ ct.freeze
40
+ assert_equal(Rational(-5, 16), ct.longitude)
41
+ end
30
42
 
31
43
  def test_longitude_new
32
44
  ct = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-5, 16))
@@ -37,6 +37,19 @@ class TCRubyCountryInfo < Minitest::Test
37
37
  assert_equal(['ZZ/TimezoneB', 'ZZ/TimezoneA', 'ZZ/TimezoneC', 'ZZ/TimezoneD'], ci.zone_identifiers)
38
38
  assert(ci.zone_identifiers.frozen?)
39
39
  end
40
+
41
+ def test_zone_identifiers_after_freeze
42
+ ci = RubyCountryInfo.new('ZZ', 'Zzz') do |c|
43
+ c.timezone('ZZ/TimezoneB', 1, 2, 1, 2, 'Timezone B')
44
+ c.timezone('ZZ/TimezoneA', 1, 4, 1, 4, 'Timezone A')
45
+ c.timezone('ZZ/TimezoneC', -10, 3, -20, 7, 'C')
46
+ c.timezone('ZZ/TimezoneD', -10, 3, -20, 7)
47
+ end
48
+
49
+ ci.freeze
50
+
51
+ assert_equal(['ZZ/TimezoneB', 'ZZ/TimezoneA', 'ZZ/TimezoneC', 'ZZ/TimezoneD'], ci.zone_identifiers)
52
+ end
40
53
 
41
54
  def test_zones_empty
42
55
  ci = RubyCountryInfo.new('ZZ', 'Zzz') {|c| }
@@ -65,6 +78,23 @@ class TCRubyCountryInfo < Minitest::Test
65
78
  ci.zones)
66
79
  assert(ci.zones.frozen?)
67
80
  end
81
+
82
+ def test_zones_after_freeze
83
+ ci = RubyCountryInfo.new('ZZ', 'Zzz') do |c|
84
+ c.timezone('ZZ/TimezoneB', 1, 2, 1, 2, 'Timezone B')
85
+ c.timezone('ZZ/TimezoneA', 1, 4, 1, 4, 'Timezone A')
86
+ c.timezone('ZZ/TimezoneC', -10, 3, -20, 7, 'C')
87
+ c.timezone('ZZ/TimezoneD', -10, 3, -20, 7)
88
+ end
89
+
90
+ ci.freeze
91
+
92
+ assert_equal([CountryTimezone.new!('ZZ/TimezoneB', 1, 2, 1, 2, 'Timezone B'),
93
+ CountryTimezone.new!('ZZ/TimezoneA', 1, 4, 1, 4, 'Timezone A'),
94
+ CountryTimezone.new!('ZZ/TimezoneC', -10, 3, -20, 7, 'C'),
95
+ CountryTimezone.new!('ZZ/TimezoneD', -10, 3, -20, 7)],
96
+ ci.zones)
97
+ end
68
98
 
69
99
  def test_deferred_evaluate
70
100
  block_called = false
@@ -128,6 +128,11 @@ class TCTimeOrDateTime < Minitest::Test
128
128
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 3, 721123),
129
129
  TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(7211239, 10000000))).to_time)
130
130
  end
131
+
132
+ def test_to_time_after_freeze
133
+ assert_equal(Time.utc(2006, 3, 24, 15, 32, 3), TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3)).freeze.to_time)
134
+ assert_equal(Time.utc(2006, 3, 24, 15, 32, 3), TimeOrDateTime.new(1143214323).freeze.to_time)
135
+ end
131
136
 
132
137
  def test_to_datetime
133
138
  assert_equal(DateTime.new(2006, 3, 24, 15, 32, 3),
@@ -157,6 +162,11 @@ class TCTimeOrDateTime < Minitest::Test
157
162
  assert_equal(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721123, 1000000)),
158
163
  TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3, 721123 + Rational(9, 10))).to_datetime)
159
164
  end
165
+
166
+ def test_to_datetime_after_freeze
167
+ assert_equal(DateTime.new(2006, 3, 24, 15, 32, 3), TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3)).freeze.to_datetime)
168
+ assert_equal(DateTime.new(2006, 3, 24, 15, 32, 3), TimeOrDateTime.new(1143214323).freeze.to_datetime)
169
+ end
160
170
 
161
171
  def test_to_i
162
172
  assert_equal(1143214323,
@@ -172,6 +182,11 @@ class TCTimeOrDateTime < Minitest::Test
172
182
  assert_equal(1143214323,
173
183
  TimeOrDateTime.new('1143214323').to_i)
174
184
  end
185
+
186
+ def test_to_i_after_freeze
187
+ assert_equal(1143214323, TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3)).freeze.to_i)
188
+ assert_equal(1143214323, TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3)).freeze.to_i)
189
+ end
175
190
 
176
191
  def test_to_orig
177
192
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 3),
@@ -149,6 +149,13 @@ class TCTimezonePeriod < Minitest::Test
149
149
  assert_nil(p.local_end)
150
150
  assert_nil(p.local_end_time)
151
151
  end
152
+
153
+ def test_utc_total_offset_rational_after_freeze
154
+ o = TimezoneOffset.new(3600, 0, :TEST)
155
+ p = TimezonePeriod.new(nil, nil, o)
156
+ p.freeze
157
+ assert_equal(Rational(1, 24), p.utc_total_offset_rational)
158
+ end
152
159
 
153
160
  def test_dst
154
161
  p1 = TimezonePeriod.new(nil, nil, TimezoneOffset.new(-14400, 3600, :TEST))
@@ -88,6 +88,15 @@ class TCTimezoneProxy < Minitest::Test
88
88
  assert_same(Timezone.get('UTC'), proxy.canonical_zone)
89
89
  end
90
90
  end
91
+
92
+ def test_after_freeze
93
+ proxy = TimezoneProxy.new('Europe/London')
94
+ real = Timezone.get('Europe/London')
95
+ t = Time.utc(2017, 6, 1)
96
+ proxy.freeze
97
+ assert_equal('Europe/London', proxy.identifier)
98
+ assert_equal(real.utc_to_local(t), proxy.utc_to_local(t))
99
+ end
91
100
 
92
101
  def test_equals
93
102
  assert_equal(true, TimezoneProxy.new('Europe/London') == TimezoneProxy.new('Europe/London'))
@@ -68,6 +68,13 @@ class TCTimezoneTransition < Minitest::Test
68
68
  assert(TimeOrDateTime.new(DateTime.new(2006, 5, 30, 1, 31, 20)).eql?(t2.local_end_at))
69
69
  assert(TimeOrDateTime.new(Time.utc(2006, 5, 30, 1, 31, 20)).eql?(t3.local_end_at))
70
70
  end
71
+
72
+ def test_local_end_at_after_freeze
73
+ t = TestTimezoneTransition.new(TimezoneOffset.new(3600, 3600, :TDT),
74
+ TimezoneOffset.new(3600, 0, :TST), 1148949080)
75
+ t.freeze
76
+ assert(TimeOrDateTime.new(1148952680).eql?(t.local_end_at))
77
+ end
71
78
 
72
79
  def test_local_end
73
80
  t1 = TestTimezoneTransition.new(TimezoneOffset.new(3600, 3600, :TDT),
@@ -107,6 +114,13 @@ class TCTimezoneTransition < Minitest::Test
107
114
  assert(TimeOrDateTime.new(DateTime.new(2006, 5, 30, 2, 31, 20)).eql?(t2.local_start_at))
108
115
  assert(TimeOrDateTime.new(Time.utc(2006, 5, 30, 2, 31, 20)).eql?(t3.local_start_at))
109
116
  end
117
+
118
+ def test_local_start_at_after_freeze
119
+ t = TestTimezoneTransition.new(TimezoneOffset.new(3600, 3600, :TDT),
120
+ TimezoneOffset.new(3600, 0, :TST), 1148949080)
121
+ t.freeze
122
+ assert(TimeOrDateTime.new(1148956280).eql?(t.local_start_at))
123
+ end
110
124
 
111
125
  def test_local_start
112
126
  t1 = TestTimezoneTransition.new(TimezoneOffset.new(3600, 3600, :TDT),
@@ -70,6 +70,17 @@ class TCTimezoneTransitionDefinition < Minitest::Test
70
70
  assert(TimeOrDateTime.new(DateTime.new(2038, 1, 19, 3, 14, 8)).eql?(t.at))
71
71
  end
72
72
  end
73
+
74
+ def test_at_after_freeze
75
+ t1 = TimezoneTransitionDefinition.new(TimezoneOffset.new(3600, 3600, :TDT),
76
+ TimezoneOffset.new(3600, 0, :TST), 1148949080)
77
+ t2 = TimezoneTransitionDefinition.new(TimezoneOffset.new(3600, 3600, :TDT),
78
+ TimezoneOffset.new(3600, 0, :TST), 5300392727, 2160)
79
+ t1.freeze
80
+ t2.freeze
81
+ assert(TimeOrDateTime.new(1148949080).eql?(t1.at))
82
+ assert(TimeOrDateTime.new(DateTime.new(2006, 5, 30, 0, 31, 20)).eql?(t2.at))
83
+ end
73
84
 
74
85
  def test_eql_timestamp
75
86
  t1 = TimezoneTransitionDefinition.new(TimezoneOffset.new(3600, 3600, :TDT),
@@ -35,6 +35,20 @@ class TCZoneinfoCountryInfo < Minitest::Test
35
35
  assert(!ci.zones.equal?(zones))
36
36
  assert(!zones.frozen?)
37
37
  end
38
+
39
+ def test_zone_identifiers_after_freeze
40
+ zones = [
41
+ CountryTimezone.new('ZZ/TimezoneB', Rational(1, 2), Rational(1, 2), 'Timezone B'),
42
+ CountryTimezone.new('ZZ/TimezoneA', Rational(1, 4), Rational(1, 4), 'Timezone A'),
43
+ CountryTimezone.new('ZZ/TimezoneC', Rational(-10, 3), Rational(-20, 7), 'C'),
44
+ CountryTimezone.new('ZZ/TimezoneD', Rational(-10, 3), Rational(-20, 7))
45
+ ]
46
+
47
+ ci = ZoneinfoCountryInfo.new('ZZ', 'Zzz', zones)
48
+ ci.freeze
49
+
50
+ assert_equal(['ZZ/TimezoneB', 'ZZ/TimezoneA', 'ZZ/TimezoneC', 'ZZ/TimezoneD'], ci.zone_identifiers)
51
+ end
38
52
 
39
53
  def test_zones_empty
40
54
  ci = ZoneinfoCountryInfo.new('ZZ', 'Zzz', [])
@@ -1070,6 +1070,110 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
1070
1070
  assert_period(:XST1, 3600, 0, false, Time.utc(2000, 4, 1), nil, info)
1071
1071
  end
1072
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
1073
1177
 
1074
1178
  def test_load_in_safe_mode
1075
1179
  offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
@@ -60,8 +60,37 @@ module Kernel
60
60
 
61
61
  if available || options[:unavailable] != :skip
62
62
  thread = Thread.new do
63
- $SAFE = options[:level] || 1 if available
64
- yield
63
+ orig_diff = Minitest::Assertions.diff
64
+
65
+ if available
66
+ orig_safe = $SAFE
67
+ $SAFE = options[:level] || 1
68
+ end
69
+ begin
70
+ # Disable the use of external diff tools during safe mode tests (since
71
+ # safe mode will prevent their use). The initial value is retrieved
72
+ # before activating safe mode because the first time
73
+ # Minitest::Assertions.diff is called, it will attempt to find a diff
74
+ # tool. Finding the diff tool will also fail in safe mode.
75
+ Minitest::Assertions.diff = nil
76
+ begin
77
+ yield
78
+ ensure
79
+ Minitest::Assertions.diff = orig_diff
80
+ end
81
+ ensure
82
+ if available
83
+ # On Ruby < 2.6, setting $SAFE affects only the current thread
84
+ # and the $SAFE level cannot be downgraded. Catch and ignore the
85
+ # SecurityError.
86
+ # On Ruby >= 2.6, setting $SAFE is global, and the $SAFE level
87
+ # can be downgraded. Restore $SAFE back to the original level.
88
+ begin
89
+ $SAFE = orig_safe
90
+ rescue SecurityError
91
+ end
92
+ end
93
+ end
65
94
  end
66
95
 
67
96
  thread.join
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'tzinfo'
3
- s.version = '1.2.4'
3
+ s.version = '1.2.5'
4
4
  s.summary = 'Daylight savings aware timezone library'
5
5
  s.description = 'TZInfo provides daylight savings aware transformations between times in different time zones.'
6
6
  s.author = 'Philip Ross'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tzinfo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.4
4
+ version: 1.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Philip Ross
@@ -30,7 +30,7 @@ cert_chain:
30
30
  YbX/8MDD3wwHu+knVnVsGNVuu/leNr+hJGgTUGXgcsu6nqYc4QVD+Amj1rI8D6at
31
31
  IYlrSPqJ7q3pK9kchFKrrktRA6yVf+fR
32
32
  -----END CERTIFICATE-----
33
- date: 2017-10-26 00:00:00.000000000 Z
33
+ date: 2018-02-04 00:00:00.000000000 Z
34
34
  dependencies:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: thread_safe
@@ -186,7 +186,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
186
186
  version: '0'
187
187
  requirements: []
188
188
  rubyforge_project:
189
- rubygems_version: 2.6.14
189
+ rubygems_version: 2.7.4
190
190
  signing_key:
191
191
  specification_version: 4
192
192
  summary: Daylight savings aware timezone library
metadata.gz.sig CHANGED
Binary file