tzinfo 1.2.10 → 2.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.yardopts +3 -0
- data/CHANGES.md +573 -391
- data/LICENSE +12 -12
- data/README.md +368 -114
- data/lib/tzinfo/annual_rules.rb +32 -12
- data/lib/tzinfo/country.rb +141 -129
- data/lib/tzinfo/country_timezone.rb +70 -112
- data/lib/tzinfo/data_source.rb +400 -144
- data/lib/tzinfo/data_sources/constant_offset_data_timezone_info.rb +56 -0
- data/lib/tzinfo/data_sources/country_info.rb +42 -0
- data/lib/tzinfo/data_sources/data_timezone_info.rb +91 -0
- data/lib/tzinfo/data_sources/linked_timezone_info.rb +33 -0
- data/lib/tzinfo/data_sources/posix_time_zone_parser.rb +181 -0
- data/lib/tzinfo/data_sources/ruby_data_source.rb +145 -0
- data/lib/tzinfo/data_sources/timezone_info.rb +47 -0
- data/lib/tzinfo/data_sources/transitions_data_timezone_info.rb +214 -0
- data/lib/tzinfo/data_sources/zoneinfo_data_source.rb +596 -0
- data/lib/tzinfo/data_sources/zoneinfo_reader.rb +486 -0
- data/lib/tzinfo/data_sources.rb +8 -0
- data/lib/tzinfo/data_timezone.rb +33 -47
- data/lib/tzinfo/datetime_with_offset.rb +153 -0
- data/lib/tzinfo/format1/country_definer.rb +17 -0
- data/lib/tzinfo/format1/country_index_definition.rb +64 -0
- data/lib/tzinfo/format1/timezone_definer.rb +64 -0
- data/lib/tzinfo/format1/timezone_definition.rb +39 -0
- data/lib/tzinfo/format1/timezone_index_definition.rb +77 -0
- data/lib/tzinfo/format1.rb +10 -0
- data/lib/tzinfo/format2/country_definer.rb +68 -0
- data/lib/tzinfo/format2/country_index_definer.rb +68 -0
- data/lib/tzinfo/format2/country_index_definition.rb +46 -0
- data/lib/tzinfo/format2/timezone_definer.rb +94 -0
- data/lib/tzinfo/format2/timezone_definition.rb +73 -0
- data/lib/tzinfo/format2/timezone_index_definer.rb +45 -0
- data/lib/tzinfo/format2/timezone_index_definition.rb +55 -0
- data/lib/tzinfo/format2.rb +10 -0
- data/lib/tzinfo/info_timezone.rb +26 -21
- data/lib/tzinfo/linked_timezone.rb +33 -52
- data/lib/tzinfo/offset_timezone_period.rb +42 -0
- data/lib/tzinfo/string_deduper.rb +118 -0
- data/lib/tzinfo/time_with_offset.rb +154 -0
- data/lib/tzinfo/timestamp.rb +552 -0
- data/lib/tzinfo/timestamp_with_offset.rb +85 -0
- data/lib/tzinfo/timezone.rb +989 -502
- data/lib/tzinfo/timezone_offset.rb +84 -74
- data/lib/tzinfo/timezone_period.rb +151 -217
- data/lib/tzinfo/timezone_proxy.rb +70 -79
- data/lib/tzinfo/timezone_transition.rb +77 -109
- data/lib/tzinfo/transition_rule.rb +207 -77
- data/lib/tzinfo/transitions_timezone_period.rb +63 -0
- data/lib/tzinfo/untaint_ext.rb +18 -0
- data/lib/tzinfo/version.rb +7 -0
- data/lib/tzinfo/with_offset.rb +61 -0
- data/lib/tzinfo.rb +82 -40
- data.tar.gz.sig +0 -0
- metadata +49 -104
- metadata.gz.sig +0 -0
- data/Rakefile +0 -107
- data/lib/tzinfo/country_index_definition.rb +0 -31
- data/lib/tzinfo/country_info.rb +0 -42
- data/lib/tzinfo/data_timezone_info.rb +0 -55
- data/lib/tzinfo/linked_timezone_info.rb +0 -26
- data/lib/tzinfo/offset_rationals.rb +0 -77
- data/lib/tzinfo/posix_time_zone_parser.rb +0 -136
- data/lib/tzinfo/ruby_core_support.rb +0 -169
- data/lib/tzinfo/ruby_country_info.rb +0 -74
- data/lib/tzinfo/ruby_data_source.rb +0 -140
- data/lib/tzinfo/time_or_datetime.rb +0 -351
- data/lib/tzinfo/timezone_definition.rb +0 -36
- data/lib/tzinfo/timezone_index_definition.rb +0 -54
- data/lib/tzinfo/timezone_info.rb +0 -30
- data/lib/tzinfo/timezone_transition_definition.rb +0 -104
- data/lib/tzinfo/transition_data_timezone_info.rb +0 -274
- data/lib/tzinfo/zoneinfo_country_info.rb +0 -37
- data/lib/tzinfo/zoneinfo_data_source.rb +0 -512
- data/lib/tzinfo/zoneinfo_timezone_info.rb +0 -520
- data/test/assets/payload.rb +0 -1
- data/test/tc_annual_rules.rb +0 -95
- data/test/tc_country.rb +0 -238
- data/test/tc_country_index_definition.rb +0 -69
- data/test/tc_country_info.rb +0 -16
- data/test/tc_country_timezone.rb +0 -173
- data/test/tc_data_source.rb +0 -218
- data/test/tc_data_timezone.rb +0 -99
- data/test/tc_data_timezone_info.rb +0 -18
- data/test/tc_info_timezone.rb +0 -34
- data/test/tc_linked_timezone.rb +0 -155
- data/test/tc_linked_timezone_info.rb +0 -23
- data/test/tc_offset_rationals.rb +0 -23
- data/test/tc_posix_time_zone_parser.rb +0 -261
- data/test/tc_ruby_core_support.rb +0 -168
- data/test/tc_ruby_country_info.rb +0 -110
- data/test/tc_ruby_data_source.rb +0 -173
- data/test/tc_time_or_datetime.rb +0 -674
- data/test/tc_timezone.rb +0 -1361
- data/test/tc_timezone_definition.rb +0 -113
- data/test/tc_timezone_index_definition.rb +0 -73
- data/test/tc_timezone_info.rb +0 -11
- data/test/tc_timezone_london.rb +0 -143
- data/test/tc_timezone_melbourne.rb +0 -142
- data/test/tc_timezone_new_york.rb +0 -142
- data/test/tc_timezone_offset.rb +0 -126
- data/test/tc_timezone_period.rb +0 -555
- data/test/tc_timezone_proxy.rb +0 -136
- data/test/tc_timezone_transition.rb +0 -366
- data/test/tc_timezone_transition_definition.rb +0 -295
- data/test/tc_timezone_utc.rb +0 -27
- data/test/tc_transition_data_timezone_info.rb +0 -433
- data/test/tc_transition_rule.rb +0 -663
- data/test/tc_zoneinfo_country_info.rb +0 -78
- data/test/tc_zoneinfo_data_source.rb +0 -1223
- data/test/tc_zoneinfo_timezone_info.rb +0 -2153
- data/test/test_utils.rb +0 -208
- data/test/ts_all.rb +0 -7
- data/test/ts_all_ruby.rb +0 -5
- data/test/ts_all_zoneinfo.rb +0 -9
- data/test/tzinfo-data/tzinfo/data/definitions/America/Argentina/Buenos_Aires.rb +0 -89
- data/test/tzinfo-data/tzinfo/data/definitions/America/New_York.rb +0 -327
- data/test/tzinfo-data/tzinfo/data/definitions/Australia/Melbourne.rb +0 -230
- data/test/tzinfo-data/tzinfo/data/definitions/EST.rb +0 -19
- data/test/tzinfo-data/tzinfo/data/definitions/Etc/GMT__m__1.rb +0 -21
- data/test/tzinfo-data/tzinfo/data/definitions/Etc/GMT__p__1.rb +0 -21
- data/test/tzinfo-data/tzinfo/data/definitions/Etc/UTC.rb +0 -21
- data/test/tzinfo-data/tzinfo/data/definitions/Europe/Amsterdam.rb +0 -273
- data/test/tzinfo-data/tzinfo/data/definitions/Europe/Andorra.rb +0 -198
- data/test/tzinfo-data/tzinfo/data/definitions/Europe/London.rb +0 -333
- data/test/tzinfo-data/tzinfo/data/definitions/Europe/Paris.rb +0 -277
- data/test/tzinfo-data/tzinfo/data/definitions/Europe/Prague.rb +0 -235
- data/test/tzinfo-data/tzinfo/data/definitions/UTC.rb +0 -16
- data/test/tzinfo-data/tzinfo/data/indexes/countries.rb +0 -940
- data/test/tzinfo-data/tzinfo/data/indexes/timezones.rb +0 -609
- data/test/tzinfo-data/tzinfo/data/version.rb +0 -20
- data/test/tzinfo-data/tzinfo/data.rb +0 -8
- 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 +0 -274
- data/test/zoneinfo/leapseconds +0 -78
- 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 +0 -452
- data/test/zoneinfo/zone1970.tab +0 -384
- data/tzinfo.gemspec +0 -21
@@ -1,79 +1,96 @@
|
|
1
|
-
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module TZInfo
|
4
5
|
# Base class for rules definining the transition between standard and daylight
|
5
6
|
# savings time.
|
7
|
+
#
|
8
|
+
# @abstract
|
9
|
+
# @private
|
6
10
|
class TransitionRule #:nodoc:
|
7
11
|
# Returns the number of seconds after midnight local time on the day
|
8
12
|
# identified by the rule at which the transition occurs. Can be negative to
|
9
13
|
# denote a time on the prior day. Can be greater than or equal to 86,400 to
|
10
14
|
# denote a time of the following day.
|
15
|
+
#
|
16
|
+
# @return [Integer] the time in seconds after midnight local time at which
|
17
|
+
# the transition occurs.
|
11
18
|
attr_reader :transition_at
|
12
19
|
|
13
|
-
# Initializes a new TransitionRule.
|
20
|
+
# Initializes a new {TransitionRule}.
|
21
|
+
#
|
22
|
+
# @param transition_at [Integer] the time in seconds after midnight local
|
23
|
+
# time at which the transition occurs.
|
24
|
+
# @raise [ArgumentError] if `transition_at` is not an `Integer`.
|
14
25
|
def initialize(transition_at)
|
15
26
|
raise ArgumentError, 'Invalid transition_at' unless transition_at.kind_of?(Integer)
|
16
27
|
@transition_at = transition_at
|
17
28
|
end
|
18
29
|
|
19
|
-
# Calculates the
|
20
|
-
#
|
30
|
+
# Calculates the time of the transition from a given offset on a given year.
|
31
|
+
#
|
32
|
+
# @param offset [TimezoneOffset] the current offset at the time the rule
|
33
|
+
# will transition.
|
34
|
+
# @param year [Integer] the year in which the transition occurs (local
|
35
|
+
# time).
|
36
|
+
# @return [TimestampWithOffset] the time at which the transition occurs.
|
21
37
|
def at(offset, year)
|
22
|
-
day = get_day(year)
|
23
|
-
|
38
|
+
day = get_day(offset, year)
|
39
|
+
TimestampWithOffset.set_timezone_offset(Timestamp.for(day + @transition_at), offset)
|
24
40
|
end
|
25
41
|
|
26
|
-
# Determines if this TransitionRule is equal to another instance.
|
42
|
+
# Determines if this {TransitionRule} is equal to another instance.
|
43
|
+
#
|
44
|
+
# @param r [Object] the instance to test for equality.
|
45
|
+
# @return [Boolean] `true` if `r` is a {TransitionRule} with the same
|
46
|
+
# {transition_at} as this {TransitionRule}, otherwise `false`.
|
27
47
|
def ==(r)
|
28
48
|
r.kind_of?(TransitionRule) && @transition_at == r.transition_at
|
29
49
|
end
|
30
50
|
alias eql? ==
|
31
51
|
|
32
|
-
#
|
52
|
+
# @return [Integer] a hash based on {hash_args} (defaulting to
|
53
|
+
# {transition_at}).
|
33
54
|
def hash
|
34
55
|
hash_args.hash
|
35
56
|
end
|
36
57
|
|
37
58
|
protected
|
38
59
|
|
39
|
-
#
|
60
|
+
# @return [Array] an `Array` of parameters that will influence the output of
|
61
|
+
# {hash}.
|
40
62
|
def hash_args
|
41
63
|
[@transition_at]
|
42
64
|
end
|
43
|
-
|
44
|
-
def new_time_or_datetime(year, month = 1, day = 1)
|
45
|
-
result = if ((year >= 2039 || (year == 2038 && (month >= 2 || (month == 1 && day >= 20)))) && !RubyCoreSupport.time_supports_64bit) ||
|
46
|
-
(year < 1970 && !RubyCoreSupport.time_supports_negative)
|
47
|
-
|
48
|
-
# Time handles 29 February on a non-leap year as 1 March.
|
49
|
-
# DateTime rejects. Advance manually.
|
50
|
-
if month == 2 && day == 29 && !Date.gregorian_leap?(year)
|
51
|
-
month = 3
|
52
|
-
day = 1
|
53
|
-
end
|
54
|
-
|
55
|
-
RubyCoreSupport.datetime_new(year, month, day)
|
56
|
-
else
|
57
|
-
Time.utc(year, month, day)
|
58
|
-
end
|
59
|
-
|
60
|
-
TimeOrDateTime.wrap(result)
|
61
|
-
end
|
62
65
|
end
|
66
|
+
private_constant :TransitionRule
|
63
67
|
|
64
68
|
# A base class for transition rules that activate based on an integer day of
|
65
69
|
# the year.
|
66
70
|
#
|
71
|
+
# @abstract
|
67
72
|
# @private
|
68
73
|
class DayOfYearTransitionRule < TransitionRule #:nodoc:
|
69
|
-
# Initializes a new DayOfYearTransitionRule.
|
74
|
+
# Initializes a new {DayOfYearTransitionRule}.
|
75
|
+
#
|
76
|
+
# @param day [Integer] the day of the year on which the transition occurs.
|
77
|
+
# The precise meaning is defined by subclasses.
|
78
|
+
# @param transition_at [Integer] the time in seconds after midnight local
|
79
|
+
# time at which the transition occurs.
|
80
|
+
# @raise [ArgumentError] if `transition_at` is not an `Integer`.
|
81
|
+
# @raise [ArgumentError] if `day` is not an `Integer`.
|
70
82
|
def initialize(day, transition_at)
|
71
83
|
super(transition_at)
|
72
84
|
raise ArgumentError, 'Invalid day' unless day.kind_of?(Integer)
|
73
85
|
@seconds = day * 86400
|
74
86
|
end
|
75
87
|
|
76
|
-
# Determines if this DayOfYearTransitionRule is equal to another instance.
|
88
|
+
# Determines if this {DayOfYearTransitionRule} is equal to another instance.
|
89
|
+
#
|
90
|
+
# @param r [Object] the instance to test for equality.
|
91
|
+
# @return [Boolean] `true` if `r` is a {DayOfYearTransitionRule} with the
|
92
|
+
# same {transition_at} and day as this {DayOfYearTransitionRule},
|
93
|
+
# otherwise `false`.
|
77
94
|
def ==(r)
|
78
95
|
super(r) && r.kind_of?(DayOfYearTransitionRule) && @seconds == r.seconds
|
79
96
|
end
|
@@ -84,11 +101,12 @@ module TZInfo
|
|
84
101
|
# @return [Integer] the day multipled by the number of seconds in a day.
|
85
102
|
attr_reader :seconds
|
86
103
|
|
87
|
-
#
|
104
|
+
# (see TransitionRule#hash_args)
|
88
105
|
def hash_args
|
89
106
|
[@seconds] + super
|
90
107
|
end
|
91
108
|
end
|
109
|
+
private_constant :DayOfYearTransitionRule
|
92
110
|
|
93
111
|
# Defines transitions that occur on the zero-based nth day of the year.
|
94
112
|
#
|
@@ -100,25 +118,38 @@ module TZInfo
|
|
100
118
|
#
|
101
119
|
# @private
|
102
120
|
class AbsoluteDayOfYearTransitionRule < DayOfYearTransitionRule #:nodoc:
|
103
|
-
# Initializes a new AbsoluteDayOfYearTransitionRule.
|
121
|
+
# Initializes a new {AbsoluteDayOfYearTransitionRule}.
|
122
|
+
#
|
123
|
+
# @param day [Integer] the zero-based day of the year on which the
|
124
|
+
# transition occurs (0 to 365 inclusive).
|
125
|
+
# @param transition_at [Integer] the time in seconds after midnight local
|
126
|
+
# time at which the transition occurs.
|
127
|
+
# @raise [ArgumentError] if `transition_at` is not an `Integer`.
|
128
|
+
# @raise [ArgumentError] if `day` is not an `Integer`.
|
129
|
+
# @raise [ArgumentError] if `day` is less than 0 or greater than 365.
|
104
130
|
def initialize(day, transition_at = 0)
|
105
131
|
super(day, transition_at)
|
106
132
|
raise ArgumentError, 'Invalid day' unless day >= 0 && day <= 365
|
107
133
|
end
|
108
134
|
|
109
|
-
#
|
110
|
-
# year (a day number of 0), otherwise false
|
135
|
+
# @return [Boolean] `true` if the day specified by this transition is the
|
136
|
+
# first in the year (a day number of 0), otherwise `false`.
|
111
137
|
def is_always_first_day_of_year?
|
112
138
|
seconds == 0
|
113
139
|
end
|
114
140
|
|
115
|
-
# @
|
141
|
+
# @return [Boolean] `false`.
|
116
142
|
def is_always_last_day_of_year?
|
117
143
|
false
|
118
144
|
end
|
119
145
|
|
120
|
-
# Determines if this AbsoluteDayOfYearTransitionRule is equal to another
|
146
|
+
# Determines if this {AbsoluteDayOfYearTransitionRule} is equal to another
|
121
147
|
# instance.
|
148
|
+
#
|
149
|
+
# @param r [Object] the instance to test for equality.
|
150
|
+
# @return [Boolean] `true` if `r` is a {AbsoluteDayOfYearTransitionRule}
|
151
|
+
# with the same {transition_at} and day as this
|
152
|
+
# {AbsoluteDayOfYearTransitionRule}, otherwise `false`.
|
122
153
|
def ==(r)
|
123
154
|
super(r) && r.kind_of?(AbsoluteDayOfYearTransitionRule)
|
124
155
|
end
|
@@ -126,13 +157,19 @@ module TZInfo
|
|
126
157
|
|
127
158
|
protected
|
128
159
|
|
129
|
-
# Returns a
|
130
|
-
#
|
131
|
-
|
132
|
-
|
160
|
+
# Returns a `Time` representing midnight local time on the day specified by
|
161
|
+
# the rule for the given offset and year.
|
162
|
+
#
|
163
|
+
# @param offset [TimezoneOffset] the current offset at the time of the
|
164
|
+
# transition.
|
165
|
+
# @param year [Integer] the year in which the transition occurs.
|
166
|
+
# @return [Time] midnight local time on the day specified by the rule for
|
167
|
+
# the given offset and year.
|
168
|
+
def get_day(offset, year)
|
169
|
+
Time.new(year, 1, 1, 0, 0, 0, offset.observed_utc_offset) + seconds
|
133
170
|
end
|
134
171
|
|
135
|
-
#
|
172
|
+
# (see TransitionRule#hash_args)
|
136
173
|
def hash_args
|
137
174
|
[AbsoluteDayOfYearTransitionRule] + super
|
138
175
|
end
|
@@ -147,30 +184,45 @@ module TZInfo
|
|
147
184
|
class JulianDayOfYearTransitionRule < DayOfYearTransitionRule #:nodoc:
|
148
185
|
# The 60 days in seconds.
|
149
186
|
LEAP = 60 * 86400
|
187
|
+
private_constant :LEAP
|
150
188
|
|
151
189
|
# The length of a non-leap year in seconds.
|
152
190
|
YEAR = 365 * 86400
|
153
|
-
|
154
|
-
|
191
|
+
private_constant :YEAR
|
192
|
+
|
193
|
+
# Initializes a new {JulianDayOfYearTransitionRule}.
|
194
|
+
#
|
195
|
+
# @param day [Integer] the one-based Julian day of the year on which the
|
196
|
+
# transition occurs (1 to 365 inclusive).
|
197
|
+
# @param transition_at [Integer] the time in seconds after midnight local
|
198
|
+
# time at which the transition occurs.
|
199
|
+
# @raise [ArgumentError] if `transition_at` is not an `Integer`.
|
200
|
+
# @raise [ArgumentError] if `day` is not an `Integer`.
|
201
|
+
# @raise [ArgumentError] if `day` is less than 1 or greater than 365.
|
155
202
|
def initialize(day, transition_at = 0)
|
156
203
|
super(day, transition_at)
|
157
204
|
raise ArgumentError, 'Invalid day' unless day >= 1 && day <= 365
|
158
205
|
end
|
159
206
|
|
160
|
-
#
|
161
|
-
# year (a day number of 1), otherwise false
|
207
|
+
# @return [Boolean] `true` if the day specified by this transition is the
|
208
|
+
# first in the year (a day number of 1), otherwise `false`.
|
162
209
|
def is_always_first_day_of_year?
|
163
210
|
seconds == 86400
|
164
211
|
end
|
165
212
|
|
166
|
-
#
|
167
|
-
# year (a day number of 365), otherwise false
|
213
|
+
# @return [Boolean] `true` if the day specified by this transition is the
|
214
|
+
# last in the year (a day number of 365), otherwise `false`.
|
168
215
|
def is_always_last_day_of_year?
|
169
216
|
seconds == YEAR
|
170
217
|
end
|
171
218
|
|
172
|
-
# Determines if this JulianDayOfYearTransitionRule is equal to another
|
219
|
+
# Determines if this {JulianDayOfYearTransitionRule} is equal to another
|
173
220
|
# instance.
|
221
|
+
#
|
222
|
+
# @param r [Object] the instance to test for equality.
|
223
|
+
# @return [Boolean] `true` if `r` is a {JulianDayOfYearTransitionRule} with
|
224
|
+
# the same {transition_at} and day as this
|
225
|
+
# {JulianDayOfYearTransitionRule}, otherwise `false`.
|
174
226
|
def ==(r)
|
175
227
|
super(r) && r.kind_of?(JulianDayOfYearTransitionRule)
|
176
228
|
end
|
@@ -178,28 +230,47 @@ module TZInfo
|
|
178
230
|
|
179
231
|
protected
|
180
232
|
|
181
|
-
# Returns a
|
182
|
-
#
|
183
|
-
|
233
|
+
# Returns a `Time` representing midnight local time on the day specified by
|
234
|
+
# the rule for the given offset and year.
|
235
|
+
#
|
236
|
+
# @param offset [TimezoneOffset] the current offset at the time of the
|
237
|
+
# transition.
|
238
|
+
# @param year [Integer] the year in which the transition occurs.
|
239
|
+
# @return [Time] midnight local time on the day specified by the rule for
|
240
|
+
# the given offset and year.
|
241
|
+
def get_day(offset, year)
|
184
242
|
# Returns 1 March on non-leap years.
|
185
|
-
leap =
|
243
|
+
leap = Time.new(year, 2, 29, 0, 0, 0, offset.observed_utc_offset)
|
186
244
|
diff = seconds - LEAP
|
187
245
|
diff += 86400 if diff >= 0 && leap.mday == 29
|
188
|
-
leap
|
246
|
+
leap + diff
|
189
247
|
end
|
190
248
|
|
191
|
-
#
|
249
|
+
# (see TransitionRule#hash_args)
|
192
250
|
def hash_args
|
193
251
|
[JulianDayOfYearTransitionRule] + super
|
194
252
|
end
|
195
253
|
end
|
254
|
+
private_constant :JulianDayOfYearTransitionRule
|
196
255
|
|
197
256
|
# A base class for rules that transition on a particular day of week of a
|
198
257
|
# given week (subclasses specify which week of the month).
|
199
258
|
#
|
259
|
+
# @abstract
|
200
260
|
# @private
|
201
261
|
class DayOfWeekTransitionRule < TransitionRule #:nodoc:
|
202
|
-
# Initializes a new DayOfWeekTransitionRule.
|
262
|
+
# Initializes a new {DayOfWeekTransitionRule}.
|
263
|
+
#
|
264
|
+
# @param month [Integer] the month of the year when the transition occurs.
|
265
|
+
# @param day_of_week [Integer] the day of the week when the transition
|
266
|
+
# occurs. 0 is Sunday, 6 is Saturday.
|
267
|
+
# @param transition_at [Integer] the time in seconds after midnight local
|
268
|
+
# time at which the transition occurs.
|
269
|
+
# @raise [ArgumentError] if `transition_at` is not an `Integer`.
|
270
|
+
# @raise [ArgumentError] if `month` is not an `Integer`.
|
271
|
+
# @raise [ArgumentError] if `month` is less than 1 or greater than 12.
|
272
|
+
# @raise [ArgumentError] if `day_of_week` is not an `Integer`.
|
273
|
+
# @raise [ArgumentError] if `day_of_week` is less than 0 or greater than 6.
|
203
274
|
def initialize(month, day_of_week, transition_at)
|
204
275
|
super(transition_at)
|
205
276
|
raise ArgumentError, 'Invalid month' unless month.kind_of?(Integer) && month >= 1 && month <= 12
|
@@ -208,17 +279,23 @@ module TZInfo
|
|
208
279
|
@day_of_week = day_of_week
|
209
280
|
end
|
210
281
|
|
211
|
-
#
|
282
|
+
# @return [Boolean] `false`.
|
212
283
|
def is_always_first_day_of_year?
|
213
284
|
false
|
214
285
|
end
|
215
286
|
|
216
|
-
#
|
287
|
+
# @return [Boolean] `false`.
|
217
288
|
def is_always_last_day_of_year?
|
218
289
|
false
|
219
290
|
end
|
220
291
|
|
221
|
-
# Determines if this DayOfWeekTransitionRule is equal to another
|
292
|
+
# Determines if this {DayOfWeekTransitionRule} is equal to another
|
293
|
+
# instance.
|
294
|
+
#
|
295
|
+
# @param r [Object] the instance to test for equality.
|
296
|
+
# @return [Boolean] `true` if `r` is a {DayOfWeekTransitionRule} with the
|
297
|
+
# same {transition_at}, month and day of week as this
|
298
|
+
# {DayOfWeekTransitionRule}, otherwise `false`.
|
222
299
|
def ==(r)
|
223
300
|
super(r) && r.kind_of?(DayOfWeekTransitionRule) && @month == r.month && @day_of_week == r.day_of_week
|
224
301
|
end
|
@@ -226,31 +303,53 @@ module TZInfo
|
|
226
303
|
|
227
304
|
protected
|
228
305
|
|
229
|
-
#
|
306
|
+
# @return [Integer] the month of the year (1 to 12).
|
230
307
|
attr_reader :month
|
231
308
|
|
232
|
-
#
|
309
|
+
# @return [Integer] the day of the week (0 to 6 for Sunday to Monday).
|
233
310
|
attr_reader :day_of_week
|
234
311
|
|
235
|
-
#
|
312
|
+
# (see TransitionRule#hash_args)
|
236
313
|
def hash_args
|
237
314
|
[@month, @day_of_week] + super
|
238
315
|
end
|
239
316
|
end
|
317
|
+
private_constant :DayOfWeekTransitionRule
|
240
318
|
|
241
319
|
# A rule that transitions on the nth occurrence of a particular day of week
|
242
320
|
# of a calendar month.
|
243
321
|
#
|
244
322
|
# @private
|
245
323
|
class DayOfMonthTransitionRule < DayOfWeekTransitionRule #:nodoc:
|
246
|
-
# Initializes a new DayOfMonthTransitionRule.
|
324
|
+
# Initializes a new {DayOfMonthTransitionRule}.
|
325
|
+
#
|
326
|
+
# @param month [Integer] the month of the year when the transition occurs.
|
327
|
+
# @param week [Integer] the week of the month when the transition occurs (1
|
328
|
+
# to 4).
|
329
|
+
# @param day_of_week [Integer] the day of the week when the transition
|
330
|
+
# occurs. 0 is Sunday, 6 is Saturday.
|
331
|
+
# @param transition_at [Integer] the time in seconds after midnight local
|
332
|
+
# time at which the transition occurs.
|
333
|
+
# @raise [ArgumentError] if `transition_at` is not an `Integer`.
|
334
|
+
# @raise [ArgumentError] if `month` is not an `Integer`.
|
335
|
+
# @raise [ArgumentError] if `month` is less than 1 or greater than 12.
|
336
|
+
# @raise [ArgumentError] if `week` is not an `Integer`.
|
337
|
+
# @raise [ArgumentError] if `week` is less than 1 or greater than 4.
|
338
|
+
# @raise [ArgumentError] if `day_of_week` is not an `Integer`.
|
339
|
+
# @raise [ArgumentError] if `day_of_week` is less than 0 or greater than 6.
|
247
340
|
def initialize(month, week, day_of_week, transition_at = 0)
|
248
341
|
super(month, day_of_week, transition_at)
|
249
342
|
raise ArgumentError, 'Invalid week' unless week.kind_of?(Integer) && week >= 1 && week <= 4
|
250
343
|
@offset_start = (week - 1) * 7 + 1
|
251
344
|
end
|
252
345
|
|
253
|
-
# Determines if this DayOfMonthTransitionRule is equal to another
|
346
|
+
# Determines if this {DayOfMonthTransitionRule} is equal to another
|
347
|
+
# instance.
|
348
|
+
#
|
349
|
+
# @param r [Object] the instance to test for equality.
|
350
|
+
# @return [Boolean] `true` if `r` is a {DayOfMonthTransitionRule} with the
|
351
|
+
# same {transition_at}, month, week and day of week as this
|
352
|
+
# {DayOfMonthTransitionRule}, otherwise `false`.
|
254
353
|
def ==(r)
|
255
354
|
super(r) && r.kind_of?(DayOfMonthTransitionRule) && @offset_start == r.offset_start
|
256
355
|
end
|
@@ -258,42 +357,66 @@ module TZInfo
|
|
258
357
|
|
259
358
|
protected
|
260
359
|
|
261
|
-
#
|
360
|
+
# @return [Integer] the day the week starts on for a month starting on a
|
361
|
+
# Sunday.
|
262
362
|
attr_reader :offset_start
|
263
363
|
|
264
|
-
# Returns a
|
265
|
-
#
|
266
|
-
|
267
|
-
|
364
|
+
# Returns a `Time` representing midnight local time on the day specified by
|
365
|
+
# the rule for the given offset and year.
|
366
|
+
#
|
367
|
+
# @param offset [TimezoneOffset] the current offset at the time of the
|
368
|
+
# transition.
|
369
|
+
# @param year [Integer] the year in which the transition occurs.
|
370
|
+
# @return [Time] midnight local time on the day specified by the rule for
|
371
|
+
# the given offset and year.
|
372
|
+
def get_day(offset, year)
|
373
|
+
candidate = Time.new(year, month, @offset_start, 0, 0, 0, offset.observed_utc_offset)
|
268
374
|
diff = day_of_week - candidate.wday
|
269
375
|
|
270
376
|
if diff < 0
|
271
|
-
candidate
|
377
|
+
candidate + (7 + diff) * 86400
|
272
378
|
elsif diff > 0
|
273
|
-
candidate
|
379
|
+
candidate + diff * 86400
|
274
380
|
else
|
275
381
|
candidate
|
276
382
|
end
|
277
383
|
end
|
278
384
|
|
279
|
-
#
|
385
|
+
# (see TransitionRule#hash_args)
|
280
386
|
def hash_args
|
281
387
|
[@offset_start] + super
|
282
388
|
end
|
283
389
|
end
|
390
|
+
private_constant :DayOfMonthTransitionRule
|
284
391
|
|
285
392
|
# A rule that transitions on the last occurrence of a particular day of week
|
286
393
|
# of a calendar month.
|
287
394
|
#
|
288
395
|
# @private
|
289
396
|
class LastDayOfMonthTransitionRule < DayOfWeekTransitionRule #:nodoc:
|
290
|
-
# Initializes a new LastDayOfMonthTransitionRule.
|
397
|
+
# Initializes a new {LastDayOfMonthTransitionRule}.
|
398
|
+
#
|
399
|
+
# @param month [Integer] the month of the year when the transition occurs.
|
400
|
+
# @param day_of_week [Integer] the day of the week when the transition
|
401
|
+
# occurs. 0 is Sunday, 6 is Saturday.
|
402
|
+
# @param transition_at [Integer] the time in seconds after midnight local
|
403
|
+
# time at which the transition occurs.
|
404
|
+
# @raise [ArgumentError] if `transition_at` is not an `Integer`.
|
405
|
+
# @raise [ArgumentError] if `month` is not an `Integer`.
|
406
|
+
# @raise [ArgumentError] if `month` is less than 1 or greater than 12.
|
407
|
+
# @raise [ArgumentError] if `day_of_week` is not an `Integer`.
|
408
|
+
# @raise [ArgumentError] if `day_of_week` is less than 0 or greater than 6.
|
291
409
|
def initialize(month, day_of_week, transition_at = 0)
|
292
410
|
super(month, day_of_week, transition_at)
|
293
411
|
end
|
294
412
|
|
295
|
-
# Determines if this LastDayOfMonthTransitionRule is equal to another
|
413
|
+
# Determines if this {LastDayOfMonthTransitionRule} is equal to another
|
296
414
|
# instance.
|
415
|
+
#
|
416
|
+
# @param r [Object] the instance to test for equality.
|
417
|
+
# @return [Boolean] `true` if `r` is a {LastDayOfMonthTransitionRule} with
|
418
|
+
# the same {transition_at}, month and day of week as this
|
419
|
+
# {LastDayOfMonthTransitionRule}, otherwise `false`.
|
297
420
|
def ==(r)
|
298
421
|
super(r) && r.kind_of?(LastDayOfMonthTransitionRule)
|
299
422
|
end
|
@@ -301,16 +424,22 @@ module TZInfo
|
|
301
424
|
|
302
425
|
protected
|
303
426
|
|
304
|
-
# Returns a
|
305
|
-
#
|
306
|
-
|
427
|
+
# Returns a `Time` representing midnight local time on the day specified by
|
428
|
+
# the rule for the given offset and year.
|
429
|
+
#
|
430
|
+
# @param offset [TimezoneOffset] the current offset at the time of the
|
431
|
+
# transition.
|
432
|
+
# @param year [Integer] the year in which the transition occurs.
|
433
|
+
# @return [Time] midnight local time on the day specified by the rule for
|
434
|
+
# the given offset and year.
|
435
|
+
def get_day(offset, year)
|
307
436
|
next_month = month + 1
|
308
437
|
if next_month == 13
|
309
438
|
year += 1
|
310
439
|
next_month = 1
|
311
440
|
end
|
312
441
|
|
313
|
-
candidate =
|
442
|
+
candidate = Time.new(year, next_month, 1, 0, 0, 0, offset.observed_utc_offset) - 86400
|
314
443
|
diff = candidate.wday - day_of_week
|
315
444
|
|
316
445
|
if diff < 0
|
@@ -322,4 +451,5 @@ module TZInfo
|
|
322
451
|
end
|
323
452
|
end
|
324
453
|
end
|
454
|
+
private_constant :LastDayOfMonthTransitionRule
|
325
455
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module TZInfo
|
5
|
+
# Represents a period of time in a time zone where the same offset from UTC
|
6
|
+
# applies. The period of time is bounded at at least one end, either having a
|
7
|
+
# start transition, end transition or both start and end transitions.
|
8
|
+
class TransitionsTimezonePeriod < TimezonePeriod
|
9
|
+
# @return [TimezoneTransition] the transition that defines the start of this
|
10
|
+
# {TimezonePeriod} (`nil` if the start is unbounded).
|
11
|
+
attr_reader :start_transition
|
12
|
+
|
13
|
+
# @return [TimezoneTransition] the transition that defines the end of this
|
14
|
+
# {TimezonePeriod} (`nil` if the end is unbounded).
|
15
|
+
attr_reader :end_transition
|
16
|
+
|
17
|
+
# Initializes a {TransitionsTimezonePeriod}.
|
18
|
+
#
|
19
|
+
# At least one of `start_transition` and `end_transition` must be specified.
|
20
|
+
#
|
21
|
+
# @param start_transition [TimezoneTransition] the transition that defines
|
22
|
+
# the start of the period, or `nil` if the start is unbounded.
|
23
|
+
# @param end_transition [TimezoneTransition] the transition that defines the
|
24
|
+
# end of the period, or `nil` if the end is unbounded.
|
25
|
+
# @raise [ArgumentError] if both `start_transition` and `end_transition` are
|
26
|
+
# `nil`.
|
27
|
+
def initialize(start_transition, end_transition)
|
28
|
+
if start_transition
|
29
|
+
super(start_transition.offset)
|
30
|
+
elsif end_transition
|
31
|
+
super(end_transition.previous_offset)
|
32
|
+
else
|
33
|
+
raise ArgumentError, 'At least one of start_transition and end_transition must be specified'
|
34
|
+
end
|
35
|
+
|
36
|
+
@start_transition = start_transition
|
37
|
+
@end_transition = end_transition
|
38
|
+
end
|
39
|
+
|
40
|
+
# Determines if this {TransitionsTimezonePeriod} is equal to another
|
41
|
+
# instance.
|
42
|
+
#
|
43
|
+
# @param p [Object] the instance to test for equality.
|
44
|
+
# @return [Boolean] `true` if `p` is a {TransitionsTimezonePeriod} with the
|
45
|
+
# same {offset}, {start_transition} and {end_transition}, otherwise
|
46
|
+
# `false`.
|
47
|
+
def ==(p)
|
48
|
+
p.kind_of?(TransitionsTimezonePeriod) && start_transition == p.start_transition && end_transition == p.end_transition
|
49
|
+
end
|
50
|
+
alias eql? ==
|
51
|
+
|
52
|
+
# @return [Integer] a hash based on {start_transition} and {end_transition}.
|
53
|
+
def hash
|
54
|
+
[@start_transition, @end_transition].hash
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return [String] the internal object state as a programmer-readable
|
58
|
+
# `String`.
|
59
|
+
def inspect
|
60
|
+
"#<#{self.class}: @start_transition=#{@start_transition.inspect}, @end_transition=#{@end_transition.inspect}>"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module TZInfo
|
5
|
+
# Object#untaint is deprecated in Ruby >= 2.7 and will be removed in 3.2.
|
6
|
+
# UntaintExt adds a refinement to make Object#untaint a no-op and avoid the
|
7
|
+
# warning.
|
8
|
+
#
|
9
|
+
# @private
|
10
|
+
module UntaintExt # :nodoc:
|
11
|
+
refine Object do
|
12
|
+
def untaint
|
13
|
+
self
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
private_constant :UntaintExt
|
18
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module TZInfo
|
5
|
+
# The {WithOffset} module is included in {TimeWithOffset},
|
6
|
+
# {DateTimeWithOffset} and {TimestampWithOffset}. It provides an override for
|
7
|
+
# the {strftime} method that handles expanding the `%Z` directive according to
|
8
|
+
# the {TimezoneOffset#abbreviation abbreviation} of the {TimezoneOffset}
|
9
|
+
# associated with a local time.
|
10
|
+
module WithOffset
|
11
|
+
# Overrides the `Time`, `DateTime` or {Timestamp} version of `strftime`,
|
12
|
+
# replacing `%Z` with the {TimezoneOffset#abbreviation abbreviation} of the
|
13
|
+
# associated {TimezoneOffset}. If there is no associated offset, `%Z` is
|
14
|
+
# expanded by the base class instead.
|
15
|
+
#
|
16
|
+
# All the format directives handled by the base class are supported.
|
17
|
+
#
|
18
|
+
# @param format [String] the format string.
|
19
|
+
# @return [String] the formatted time.
|
20
|
+
# @raise [ArgumentError] if `format` is `nil`.
|
21
|
+
def strftime(format)
|
22
|
+
raise ArgumentError, 'format must be specified' unless format
|
23
|
+
|
24
|
+
if_timezone_offset do |o|
|
25
|
+
abbreviation = nil
|
26
|
+
|
27
|
+
format = format.gsub(/%(%*)Z/) do
|
28
|
+
if $1.length.odd?
|
29
|
+
# Return %%Z so the real strftime treats it as a literal %Z too.
|
30
|
+
"#$1%Z"
|
31
|
+
else
|
32
|
+
"#$1#{abbreviation ||= o.abbreviation.gsub(/%/, '%%')}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
# Performs a calculation if there is an associated {TimezoneOffset}.
|
43
|
+
#
|
44
|
+
# @param result [Object] a result value that can be manipulated by the block
|
45
|
+
# if there is an associated {TimezoneOffset}.
|
46
|
+
# @yield [period, result] if there is an associated {TimezoneOffset}, the
|
47
|
+
# block is yielded to in order to calculate the method result.
|
48
|
+
# @yieldparam period [TimezoneOffset] the associated {TimezoneOffset}.
|
49
|
+
# @yieldparam result [Object] the `result` parameter.
|
50
|
+
# @yieldreturn [Object] the result of the calculation performed if there is
|
51
|
+
# an associated {TimezoneOffset}.
|
52
|
+
# @return [Object] the result of the block if there is an associated
|
53
|
+
# {TimezoneOffset}, otherwise the `result` parameter.
|
54
|
+
#
|
55
|
+
# @private
|
56
|
+
def if_timezone_offset(result = nil) #:nodoc:
|
57
|
+
to = timezone_offset
|
58
|
+
to ? yield(to, result) : result
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|