tzinfo-data 1.2018.7 → 1.2018.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,13 +11,22 @@ module TZInfo
11
11
  include TimezoneDefinition
12
12
 
13
13
  timezone 'Pacific/Kosrae' do |tz|
14
- tz.offset :o0, 39116, 0, :LMT
15
- tz.offset :o1, 39600, 0, :'+11'
16
- tz.offset :o2, 43200, 0, :'+12'
14
+ tz.offset :o0, -47284, 0, :LMT
15
+ tz.offset :o1, 39116, 0, :LMT
16
+ tz.offset :o2, 39600, 0, :'+11'
17
+ tz.offset :o3, 32400, 0, :'+09'
18
+ tz.offset :o4, 36000, 0, :'+10'
19
+ tz.offset :o5, 43200, 0, :'+12'
17
20
 
18
- tz.transition 1900, 12, :o1, -2177491916, 52172317021, 21600
19
- tz.transition 1969, 9, :o2, -7988400, 58571881, 24
20
- tz.transition 1998, 12, :o1, 915105600
21
+ tz.transition 1844, 12, :o1, -3944631116, 51730532221, 21600
22
+ tz.transition 1900, 12, :o2, -2177491916, 52172317021, 21600
23
+ tz.transition 1914, 9, :o3, -1743678000, 58089745, 24
24
+ tz.transition 1919, 1, :o2, -1606813200, 19375921, 8
25
+ tz.transition 1936, 12, :o4, -1041418800, 58284817, 24
26
+ tz.transition 1941, 3, :o3, -907408800, 29161021, 12
27
+ tz.transition 1945, 7, :o2, -770634000, 19453345, 8
28
+ tz.transition 1969, 9, :o5, -7988400, 58571881, 24
29
+ tz.transition 1998, 12, :o2, 915105600
21
30
  end
22
31
  end
23
32
  end
@@ -13,12 +13,17 @@ module TZInfo
13
13
  timezone 'Pacific/Kwajalein' do |tz|
14
14
  tz.offset :o0, 40160, 0, :LMT
15
15
  tz.offset :o1, 39600, 0, :'+11'
16
- tz.offset :o2, -43200, 0, :'-12'
17
- tz.offset :o3, 43200, 0, :'+12'
16
+ tz.offset :o2, 36000, 0, :'+10'
17
+ tz.offset :o3, 32400, 0, :'+09'
18
+ tz.offset :o4, -43200, 0, :'-12'
19
+ tz.offset :o5, 43200, 0, :'+12'
18
20
 
19
21
  tz.transition 1900, 12, :o1, -2177492960, 1304307919, 540
20
- tz.transition 1969, 9, :o2, -7988400, 58571881, 24
21
- tz.transition 1993, 8, :o3, 745848000
22
+ tz.transition 1936, 12, :o2, -1041418800, 58284817, 24
23
+ tz.transition 1941, 3, :o3, -907408800, 29161021, 12
24
+ tz.transition 1944, 2, :o1, -817462800, 19449009, 8
25
+ tz.transition 1969, 9, :o4, -7988400, 58571881, 24
26
+ tz.transition 1993, 8, :o5, 745934400
22
27
  end
23
28
  end
24
29
  end
@@ -13,10 +13,17 @@ module TZInfo
13
13
  timezone 'Pacific/Majuro' do |tz|
14
14
  tz.offset :o0, 41088, 0, :LMT
15
15
  tz.offset :o1, 39600, 0, :'+11'
16
- tz.offset :o2, 43200, 0, :'+12'
16
+ tz.offset :o2, 32400, 0, :'+09'
17
+ tz.offset :o3, 36000, 0, :'+10'
18
+ tz.offset :o4, 43200, 0, :'+12'
17
19
 
18
20
  tz.transition 1900, 12, :o1, -2177493888, 1086923261, 450
19
- tz.transition 1969, 9, :o2, -7988400, 58571881, 24
21
+ tz.transition 1914, 9, :o2, -1743678000, 58089745, 24
22
+ tz.transition 1919, 1, :o1, -1606813200, 19375921, 8
23
+ tz.transition 1936, 12, :o3, -1041418800, 58284817, 24
24
+ tz.transition 1941, 3, :o2, -907408800, 29161021, 12
25
+ tz.transition 1944, 1, :o1, -818067600, 19448953, 8
26
+ tz.transition 1969, 9, :o4, -7988400, 58571881, 24
20
27
  end
21
28
  end
22
29
  end
@@ -17,9 +17,9 @@ module TZInfo
17
17
  tz.offset :o3, 43200, 0, :'+12'
18
18
 
19
19
  tz.transition 1921, 1, :o1, -1545131260, 10466081437, 4320
20
- tz.transition 1942, 3, :o2, -877347000, 116660785, 48
21
- tz.transition 1944, 8, :o1, -800960400, 19450537, 8
22
- tz.transition 1979, 4, :o3, 294323400
20
+ tz.transition 1942, 8, :o2, -862918200, 116668801, 48
21
+ tz.transition 1945, 9, :o1, -767350800, 19453649, 8
22
+ tz.transition 1979, 2, :o3, 287418600
23
23
  end
24
24
  end
25
25
  end
@@ -11,10 +11,12 @@ module TZInfo
11
11
  include TimezoneDefinition
12
12
 
13
13
  timezone 'Pacific/Palau' do |tz|
14
- tz.offset :o0, 32276, 0, :LMT
15
- tz.offset :o1, 32400, 0, :'+09'
14
+ tz.offset :o0, -54124, 0, :LMT
15
+ tz.offset :o1, 32276, 0, :LMT
16
+ tz.offset :o2, 32400, 0, :'+09'
16
17
 
17
- tz.transition 1900, 12, :o1, -2177485076, 52172318731, 21600
18
+ tz.transition 1844, 12, :o1, -3944624276, 51730533931, 21600
19
+ tz.transition 1900, 12, :o2, -2177485076, 52172318731, 21600
18
20
  end
19
21
  end
20
22
  end
@@ -11,10 +11,19 @@ module TZInfo
11
11
  include TimezoneDefinition
12
12
 
13
13
  timezone 'Pacific/Pohnpei' do |tz|
14
- tz.offset :o0, 37972, 0, :LMT
15
- tz.offset :o1, 39600, 0, :'+11'
14
+ tz.offset :o0, -48428, 0, :LMT
15
+ tz.offset :o1, 37972, 0, :LMT
16
+ tz.offset :o2, 39600, 0, :'+11'
17
+ tz.offset :o3, 32400, 0, :'+09'
18
+ tz.offset :o4, 36000, 0, :'+10'
16
19
 
17
- tz.transition 1900, 12, :o1, -2177490772, 52172317307, 21600
20
+ tz.transition 1844, 12, :o1, -3944629972, 51730532507, 21600
21
+ tz.transition 1900, 12, :o2, -2177490772, 52172317307, 21600
22
+ tz.transition 1914, 9, :o3, -1743678000, 58089745, 24
23
+ tz.transition 1919, 1, :o2, -1606813200, 19375921, 8
24
+ tz.transition 1936, 12, :o4, -1041418800, 58284817, 24
25
+ tz.transition 1941, 3, :o3, -907408800, 29161021, 12
26
+ tz.transition 1945, 7, :o2, -770634000, 19453345, 8
18
27
  end
19
28
  end
20
29
  end
@@ -473,6 +473,7 @@ module TZInfo
473
473
  country 'KZ', 'Kazakhstan' do |c|
474
474
  c.timezone 'Asia/Almaty', 173, 4, 1539, 20, 'Kazakhstan (most areas)'
475
475
  c.timezone 'Asia/Qyzylorda', 224, 5, 982, 15, 'Qyzylorda/Kyzylorda/Kzyl-Orda'
476
+ c.timezone 'Asia/Qostanay', 266, 5, 3817, 60, 'Qostanay/Kostanay/Kustanay'
476
477
  c.timezone 'Asia/Aqtobe', 3017, 60, 343, 6, 'Aqtöbe/Aktobe'
477
478
  c.timezone 'Asia/Aqtau', 2671, 60, 754, 15, 'Mangghystaū/Mankistau'
478
479
  c.timezone 'Asia/Atyrau', 2827, 60, 779, 15, 'Atyraū/Atirau/Gur\'yev'
@@ -698,9 +699,9 @@ module TZInfo
698
699
  c.timezone 'Europe/Kaliningrad', 3283, 60, 41, 2, 'MSK-01 - Kaliningrad'
699
700
  c.timezone 'Europe/Moscow', 66907, 1200, 8464, 225, 'MSK+00 - Moscow area'
700
701
  c.timezone 'Europe/Simferopol', 899, 20, 341, 10, 'MSK+00 - Crimea'
701
- c.timezone 'Europe/Volgograd', 731, 15, 533, 12, 'MSK+00 - Volgograd'
702
702
  c.timezone 'Europe/Kirov', 293, 5, 993, 20, 'MSK+00 - Kirov'
703
703
  c.timezone 'Europe/Astrakhan', 927, 20, 961, 20, 'MSK+01 - Astrakhan'
704
+ c.timezone 'Europe/Volgograd', 731, 15, 533, 12, 'MSK+01 - Volgograd'
704
705
  c.timezone 'Europe/Saratov', 1547, 30, 1381, 30, 'MSK+01 - Saratov'
705
706
  c.timezone 'Europe/Ulyanovsk', 163, 3, 242, 5, 'MSK+01 - Ulyanovsk'
706
707
  c.timezone 'Europe/Samara', 266, 5, 1003, 20, 'MSK+01 - Samara, Udmurtia'
@@ -310,6 +310,7 @@ module TZInfo
310
310
  timezone 'Asia/Pontianak'
311
311
  timezone 'Asia/Pyongyang'
312
312
  timezone 'Asia/Qatar'
313
+ timezone 'Asia/Qostanay'
313
314
  timezone 'Asia/Qyzylorda'
314
315
  linked_timezone 'Asia/Rangoon'
315
316
  timezone 'Asia/Riyadh'
@@ -3,7 +3,7 @@ require 'fileutils'
3
3
 
4
4
  module TZInfo
5
5
  module Data
6
-
6
+
7
7
  # Utility methods used by TZDataParser and associated classes.
8
8
  #
9
9
  # @private
@@ -20,11 +20,11 @@ module TZInfo
20
20
  File.open(file_name, mode, opts, &block)
21
21
  end
22
22
  end
23
-
23
+
24
24
  private :open_file
25
-
25
+
26
26
  private
27
-
27
+
28
28
  # Parses a month specified in the tz data and converts it to a number
29
29
  # between 1 and 12 representing January to December.
30
30
  def parse_month(month)
@@ -57,17 +57,17 @@ module TZInfo
57
57
  raise "Invalid month: #{month}"
58
58
  end
59
59
  end
60
-
60
+
61
61
  # Parses an offset string [-]h:m:s (minutes and seconds are optional). Returns
62
62
  # the offset in seconds.
63
63
  def parse_offset(offset)
64
64
  raise "Invalid time: #{offset}" if offset !~ /^(-)?(?:([0-9]+)(?::([0-9]+)(?::([0-9]+))?)?)?$/
65
-
66
- negative = !$1.nil?
65
+
66
+ negative = !$1.nil?
67
67
  hour = $2.nil? ? 0 : $2.to_i
68
68
  minute = $3.nil? ? 0 : $3.to_i
69
69
  second = $4.nil? ? 0 : $4.to_i
70
-
70
+
71
71
  seconds = hour
72
72
  seconds = seconds * 60
73
73
  seconds = seconds + minute
@@ -76,52 +76,52 @@ module TZInfo
76
76
  seconds = -seconds if negative
77
77
  seconds
78
78
  end
79
-
79
+
80
80
  # Encloses the string in single quotes and escapes any single quotes in
81
81
  # the content.
82
82
  def quote_str(str)
83
83
  "'#{str.gsub('\'', '\\\\\'')}'"
84
84
  end
85
- end
86
-
87
- # Parses Time Zone Data from the IANA Time Zone Database and transforms it
85
+ end
86
+
87
+ # Parses Time Zone Data from the IANA Time Zone Database and transforms it
88
88
  # into a set of Ruby modules that can be used with TZInfo.
89
- #
90
- # Normally, this class wouldn't be used. It is only run to update the
89
+ #
90
+ # Normally, this class wouldn't be used. It is only run to update the
91
91
  # timezone data and index modules.
92
92
  class TZDataParser
93
93
  include TZDataParserUtils
94
-
94
+
95
95
  # Default earliest year that will be considered.
96
96
  DEFAULT_MIN_YEAR = 1800
97
-
98
- # Default number of future years data to generate (not including the
97
+
98
+ # Default number of future years data to generate (not including the
99
99
  # current year).
100
100
  DEFAULT_FUTURE_YEARS = 50
101
-
101
+
102
102
  # Earliest year that will be considered. Defaults to DEFAULT_MIN_YEAR.
103
103
  attr_accessor :min_year
104
-
104
+
105
105
  # Latest year that will be considered. Defaults to the current year plus
106
106
  # FUTURE_YEARS.
107
107
  attr_accessor :max_year
108
-
108
+
109
109
  # Whether to generate zone definitions (set to false to stop zones being
110
- # generated).
110
+ # generated).
111
111
  attr_accessor :generate_zones
112
-
112
+
113
113
  # Whether to generate country definitions (set to false to stop countries
114
114
  # being generated).
115
115
  attr_accessor :generate_countries
116
-
116
+
117
117
  # Limit the set of zones to generate (set to an array containing zone
118
118
  # identifiers).
119
119
  attr_accessor :only_zones
120
-
120
+
121
121
  # Zones to exclude from generation when not using only_zones (set to an
122
122
  # array containing zone identifiers).
123
123
  attr_accessor :exclude_zones
124
-
124
+
125
125
  # Initializes a new TZDataParser. input_dir must contain the extracted
126
126
  # tzdata tarball. output_dir is the location to output the modules
127
127
  # (in definitions and indexes directories).
@@ -140,7 +140,7 @@ module TZInfo
140
140
  @only_zones = []
141
141
  @exclude_zones = []
142
142
  end
143
-
143
+
144
144
  # Reads the tzdata source and generates the classes. Progress information
145
145
  # is written to standard out.
146
146
  def execute
@@ -150,20 +150,20 @@ module TZInfo
150
150
  # install its entries by default.
151
151
 
152
152
  files = Dir.entries(@input_dir).select do |file|
153
- file =~ /\A[^\.]+\z/ &&
153
+ file =~ /\A[^\.]+\z/ &&
154
154
  !%w(backzone calendars leapseconds CONTRIBUTING LICENSE Makefile NEWS README SOURCE Theory version).include?(file) &&
155
155
  File.file?(File.join(@input_dir, file))
156
156
  end
157
-
157
+
158
158
  files.each {|file| load_rules(file) }
159
159
  files.each {|file| load_zones(file) }
160
160
  files.each {|file| load_links(file) }
161
-
161
+
162
162
  load_countries
163
-
163
+
164
164
  if @generate_zones
165
165
  modules = []
166
-
166
+
167
167
  if @only_zones.nil? || @only_zones.empty?
168
168
  @zones.each_value {|zone|
169
169
  zone.write_module(@output_dir) unless @exclude_zones.include?(zone.name)
@@ -171,45 +171,45 @@ module TZInfo
171
171
  else
172
172
  @only_zones.each {|id|
173
173
  zone = @zones[id]
174
- zone.write_module(@output_dir)
175
- }
174
+ zone.write_module(@output_dir)
175
+ }
176
176
  end
177
-
177
+
178
178
  write_timezones_index
179
179
  end
180
-
181
- if @generate_countries
180
+
181
+ if @generate_countries
182
182
  write_countries_index
183
183
  end
184
184
  end
185
-
186
- private
185
+
186
+ private
187
187
  # Loads all the Rule definitions from the tz data and stores them in
188
188
  # the rule_sets instance variable.
189
189
  def load_rules(file)
190
190
  puts 'load_rules: ' + file
191
-
191
+
192
192
  # Files are in ASCII, but may change to UTF-8 (a superset of ASCII)
193
193
  # in the future.
194
194
  open_file(File.join(@input_dir, file), 'r', :external_encoding => 'UTF-8', :internal_encoding => 'UTF-8') do |file|
195
195
  file.each_line do |line|
196
196
  line = line.gsub(/#.*$/, '')
197
197
  line = line.gsub(/\s+$/, '')
198
-
198
+
199
199
  if line =~ /^Rule\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)/
200
-
201
- name = $1
202
-
203
- if @rule_sets[name].nil?
204
- @rule_sets[name] = TZDataRuleSet.new(name)
200
+
201
+ name = $1
202
+
203
+ if @rule_sets[name].nil?
204
+ @rule_sets[name] = TZDataRuleSet.new(name)
205
205
  end
206
-
206
+
207
207
  @rule_sets[name].add_rule(TZDataRule.new($2, $3, $4, $5, $6, $7, $8, $9))
208
- end
208
+ end
209
209
  end
210
210
  end
211
211
  end
212
-
212
+
213
213
  # Gets a rules object for the given reference. Might be a named rule set,
214
214
  # a fixed offset or an empty ruleset.
215
215
  def get_rules(ref)
@@ -219,80 +219,80 @@ module TZInfo
219
219
  TZDataFixedOffsetRules.new(parse_offset(ref))
220
220
  else
221
221
  rule_set = @rule_sets[ref]
222
- raise "Ruleset not found: #{ref}" if rule_set.nil?
222
+ raise "Ruleset not found: #{ref}" if rule_set.nil?
223
223
  rule_set
224
- end
224
+ end
225
225
  end
226
-
226
+
227
227
  # Loads in the Zone definitions from the tz data and stores them in @zones.
228
228
  def load_zones(file)
229
229
  puts 'load_zones: ' + file
230
-
230
+
231
231
  in_zone = nil
232
-
232
+
233
233
  # Files are in ASCII, but may change to UTF-8 (a superset of ASCII)
234
234
  # in the future.
235
235
  open_file(File.join(@input_dir, file), 'r', :external_encoding => 'UTF-8', :internal_encoding => 'UTF-8') do |file|
236
236
  file.each_line do |line|
237
237
  line = line.gsub(/#.*$/, '')
238
238
  line = line.gsub(/\s+$/, '')
239
-
239
+
240
240
  if in_zone
241
- if line =~ /^\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)(\s+([0-9]+(\s+.*)?))?$/
242
-
241
+ if line =~ /^\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)(\s+([0-9]+(\s+.*)?))?$/
242
+
243
243
  in_zone.add_observance(TZDataObservance.new($1, get_rules($2), $3, $5))
244
-
245
- in_zone = nil if $4.nil?
244
+
245
+ in_zone = nil if $4.nil?
246
246
  end
247
247
  else
248
- if line =~ /^Zone\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)(\s+([0-9]+(\s+.*)?))?$/
248
+ if line =~ /^Zone\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)(\s+([0-9]+(\s+.*)?))?$/
249
249
  name = $1
250
-
251
- if @zones[name].nil?
250
+
251
+ if @zones[name].nil?
252
252
  @zones[name] = TZDataZone.new(name, @min_year..@max_year)
253
- end
254
-
253
+ end
254
+
255
255
  @zones[name].add_observance(TZDataObservance.new($2, get_rules($3), $4, $6))
256
-
256
+
257
257
  in_zone = @zones[name] if !$5.nil?
258
258
  end
259
259
  end
260
260
  end
261
261
  end
262
262
  end
263
-
263
+
264
264
  # Loads in the links and stores them in @zones.
265
265
  def load_links(file)
266
266
  puts 'load_links: ' + file
267
-
267
+
268
268
  # Files are in ASCII, but may change to UTF-8 (a superset of ASCII)
269
269
  # in the future.
270
270
  open_file(File.join(@input_dir, file), 'r', :external_encoding => 'UTF-8', :internal_encoding => 'UTF-8') do |file|
271
271
  file.each_line do |line|
272
272
  line = line.gsub(/#.*$/, '')
273
273
  line = line.gsub(/\s+$/, '')
274
-
275
- if line =~ /^Link\s+([^\s]+)\s+([^\s]+)/
276
- name = $2
274
+
275
+ if line =~ /^Link\s+([^\s]+)\s+([^\s]+)/
276
+ name = $2
277
277
  link_to = @zones[$1]
278
278
  raise "Link to zone not found (#{name}->#{link_to})" if link_to.nil?
279
279
  raise "Zone already defined: #{name}" if !@zones[name].nil?
280
280
  @zones[name] = TZDataLink.new(name, link_to)
281
- end
281
+ end
282
282
  end
283
283
  end
284
284
  end
285
-
285
+
286
286
  # Loads countries from iso3166.tab and zone1970.tab and stores the
287
287
  # result in the countries instance variable.
288
288
  def load_countries
289
289
  puts 'load_countries'
290
-
290
+
291
291
  # iso3166.tab is ASCII encoded, but is planned to change to UTF-8 (a
292
292
  # superset of ASCII) in the future.
293
293
  open_file(File.join(@input_dir, 'iso3166.tab'), 'r', :external_encoding => 'UTF-8', :internal_encoding => 'UTF-8') do |file|
294
294
  file.each_line do |line|
295
-
295
+
296
296
  if line =~ /^([A-Z]{2})\t(.*)$/
297
297
  code = $1
298
298
  name = $2
@@ -307,22 +307,22 @@ module TZInfo
307
307
  # zone1970.tab is UTF-8 encoded.
308
308
  open_file(File.join(@input_dir, 'zone1970.tab'), 'r', :external_encoding => 'UTF-8', :internal_encoding => 'UTF-8') do |file|
309
309
  file.each_line do |line|
310
-
311
- line.chomp!
310
+
311
+ line.chomp!
312
312
 
313
313
  if line =~ /^([A-Z]{2}(?:,[A-Z]{2})*)\t([^\t]+)\t([^\t]+)(\t(.*))?$/
314
314
  codes = $1
315
315
  location_str = $2
316
316
  zone_name = $3
317
317
  description = $5
318
-
318
+
319
319
  location = TZDataLocation.new(location_str)
320
-
320
+
321
321
  zone = @zones[zone_name]
322
- raise "Zone not found: #{zone_name}" if zone.nil?
323
-
322
+ raise "Zone not found: #{zone_name}" if zone.nil?
323
+
324
324
  description = nil if description == ''
325
-
325
+
326
326
  country_timezone = TZDataCountryTimezone.new(zone, description, location)
327
327
 
328
328
  codes = codes.split(',')
@@ -347,95 +347,95 @@ module TZInfo
347
347
  end
348
348
  end
349
349
  end
350
-
350
+
351
351
  # Writes a country index file.
352
352
  def write_countries_index
353
353
  dir = File.join(@output_dir, 'indexes')
354
354
  FileUtils.mkdir_p(dir)
355
-
355
+
356
356
  open_file(File.join(dir, 'countries.rb'), 'w', :external_encoding => 'UTF-8', :universal_newline => true) do |file|
357
357
  file.puts('# encoding: UTF-8')
358
358
  file.puts('')
359
359
  file.puts('# This file contains data derived from the IANA Time Zone Database')
360
360
  file.puts('# (http://www.iana.org/time-zones).')
361
361
  file.puts('')
362
-
362
+
363
363
  file.puts('module TZInfo')
364
364
  file.puts(' module Data')
365
365
  file.puts(' module Indexes')
366
366
  file.puts(' module Countries')
367
367
  file.puts(' include CountryIndexDefinition')
368
368
  file.puts('')
369
-
370
- countries = @countries.values.sort {|c1,c2| c1.code <=> c2.code}
369
+
370
+ countries = @countries.values.sort {|c1,c2| c1.code <=> c2.code}
371
371
  countries.each {|country| country.write_index_record(file)}
372
-
373
- file.puts(' end') # end module Countries
372
+
373
+ file.puts(' end') # end module Countries
374
374
  file.puts(' end') # end module Indexes
375
375
  file.puts(' end') # end module Data
376
376
  file.puts('end') # end module TZInfo
377
- end
377
+ end
378
378
  end
379
-
379
+
380
380
  # Writes a timezone index file.
381
381
  def write_timezones_index
382
382
  dir = File.join(@output_dir, 'indexes')
383
383
  FileUtils.mkdir_p(dir)
384
-
384
+
385
385
  open_file(File.join(dir, 'timezones.rb'), 'w', :external_encoding => 'UTF-8', :universal_newline => true) do |file|
386
386
  file.puts('# encoding: UTF-8')
387
387
  file.puts('')
388
388
  file.puts('# This file contains data derived from the IANA Time Zone Database')
389
389
  file.puts('# (http://www.iana.org/time-zones).')
390
390
  file.puts('')
391
-
391
+
392
392
  file.puts('module TZInfo')
393
393
  file.puts(' module Data')
394
394
  file.puts(' module Indexes')
395
395
  file.puts(' module Timezones')
396
396
  file.puts(' include TimezoneIndexDefinition')
397
397
  file.puts('')
398
-
398
+
399
399
  zones = @zones.values.sort {|t1,t2| t1.name <=> t2.name}
400
400
  zones.each {|zone| zone.write_index_record(file)}
401
-
401
+
402
402
  file.puts(' end') # end module Timezones
403
403
  file.puts(' end') # end module Indexes
404
404
  file.puts(' end') # end module Data
405
405
  file.puts('end') # end module TZInfo
406
406
  end
407
-
407
+
408
408
  end
409
409
  end
410
-
410
+
411
411
  # Base class for all rule sets.
412
412
  #
413
413
  # @private
414
414
  class TZDataRules #:nodoc:
415
415
  # Name of the rule set, e.g. EU.
416
416
  attr_reader :name
417
-
417
+
418
418
  def initialize(name)
419
419
  @name = name
420
420
  end
421
-
421
+
422
422
  def count
423
423
  0
424
424
  end
425
425
  end
426
-
426
+
427
427
  # Empty rule set with a fixed daylight savings (std) offset.
428
428
  #
429
429
  # @private
430
430
  class TZDataFixedOffsetRules < TZDataRules #:nodoc:
431
431
  attr_reader :offset
432
-
432
+
433
433
  def initialize(offset)
434
434
  super(offset.to_s)
435
435
  @offset = offset
436
- end
436
+ end
437
437
  end
438
-
438
+
439
439
  # An empty set of rules.
440
440
  #
441
441
  # @private
@@ -444,38 +444,38 @@ module TZInfo
444
444
  super('-')
445
445
  end
446
446
  end
447
-
447
+
448
448
  # A rule set (as defined by Rule name in the tz data).
449
449
  #
450
450
  # @private
451
- class TZDataRuleSet < TZDataRules #:nodoc:
451
+ class TZDataRuleSet < TZDataRules #:nodoc:
452
452
  attr_reader :rules
453
-
453
+
454
454
  def initialize(name)
455
455
  super
456
456
  @rules = []
457
457
  end
458
-
458
+
459
459
  # Adds a new rule to the set.
460
460
  def add_rule(rule)
461
461
  @rules << rule
462
462
  end
463
-
463
+
464
464
  def count
465
465
  @rules.length
466
466
  end
467
-
467
+
468
468
  def each
469
469
  @rules.each {|rule| yield rule}
470
470
  end
471
- end
472
-
471
+ end
472
+
473
473
  # A rule in a RuleSet (a single Rule line in the tz data).
474
474
  #
475
475
  # @private
476
476
  class TZDataRule #:nodoc:
477
477
  include TZDataParserUtils
478
-
478
+
479
479
  attr_reader :from
480
480
  attr_reader :to
481
481
  attr_reader :type
@@ -484,15 +484,15 @@ module TZInfo
484
484
  attr_reader :at_time
485
485
  attr_reader :save
486
486
  attr_reader :letter
487
-
487
+
488
488
  def initialize(from, to, type, in_month, on_day, at_time, save, letter)
489
489
  @from = parse_from(from)
490
490
  @to = parse_to(to)
491
-
491
+
492
492
  # replace a to of :only with the from year
493
493
  raise 'to cannot be only if from is minimum' if @to == :only && @from == :min
494
- @to = @from if @to == :only
495
-
494
+ @to = @from if @to == :only
495
+
496
496
  @type = parse_type(type)
497
497
  @in_month = parse_month(in_month)
498
498
  @on_day = TZDataDayOfMonth.new(on_day)
@@ -500,22 +500,22 @@ module TZInfo
500
500
  @save = parse_offset(save)
501
501
  @letter = parse_letter(letter)
502
502
  end
503
-
503
+
504
504
  def activate(year)
505
505
  # The following test ignores yearistype at present (currently unused in
506
506
  # the data. parse_type currently excepts on encountering a year type.
507
- if (@from == :min || @from <= year) && (@to == :max || @to >= year)
507
+ if (@from == :min || @from <= year) && (@to == :max || @to >= year)
508
508
  TZDataActivatedRule.new(self, year)
509
509
  else
510
510
  nil
511
511
  end
512
512
  end
513
-
513
+
514
514
  def at_utc_time(year, utc_offset, std_offset)
515
515
  @at_time.to_utc(utc_offset, std_offset,
516
516
  year, @in_month, @on_day.to_absolute(year, @in_month))
517
517
  end
518
-
518
+
519
519
  private
520
520
  def parse_from(from)
521
521
  lower = from.downcase
@@ -527,7 +527,7 @@ module TZInfo
527
527
  raise "Invalid from: #{from}"
528
528
  end
529
529
  end
530
-
530
+
531
531
  def parse_to(to)
532
532
  lower = to.downcase
533
533
  if lower =~ /^max/
@@ -540,12 +540,12 @@ module TZInfo
540
540
  raise "Invalid to: #{to}"
541
541
  end
542
542
  end
543
-
543
+
544
544
  def parse_type(type)
545
545
  raise "Unsupported rule type: #{type}" if type != '-'
546
546
  nil
547
- end
548
-
547
+ end
548
+
549
549
  def parse_letter(letter)
550
550
  if letter == '-'
551
551
  nil
@@ -554,40 +554,40 @@ module TZInfo
554
554
  end
555
555
  end
556
556
  end
557
-
557
+
558
558
  # Base class for Zones and Links.
559
559
  #
560
560
  # @private
561
561
  class TZDataDefinition #:nodoc:
562
562
  include TZDataParserUtils
563
-
563
+
564
564
  attr_reader :name
565
565
  attr_reader :name_elements
566
566
  attr_reader :path_elements
567
-
567
+
568
568
  def initialize(name)
569
569
  @name = name
570
-
570
+
571
571
  # + and - aren't allowed in class names
572
572
  @name_elements = name.gsub(/-/, '__m__').gsub(/\+/, '__p__').split(/\//)
573
573
  @path_elements = @name_elements.clone
574
574
  @path_elements.pop
575
- end
576
-
575
+ end
576
+
577
577
  # Creates necessary directories, the file, writes the class header and footer
578
- # and yields to a block to write the content.
579
- def create_file(output_dir)
578
+ # and yields to a block to write the content.
579
+ def create_file(output_dir)
580
580
  dir = File.join(output_dir, 'definitions', @path_elements.join(File::SEPARATOR))
581
581
  FileUtils.mkdir_p(dir)
582
-
582
+
583
583
  open_file(File.join(output_dir, 'definitions', @name_elements.join(File::SEPARATOR)) + '.rb', 'w', :external_encoding => 'UTF-8', :universal_newline => true) do |file|
584
584
 
585
585
  file.instance_variable_set(:@tz_indent, 0)
586
-
586
+
587
587
  def file.indent(by)
588
588
  @tz_indent += by
589
589
  end
590
-
590
+
591
591
  def file.puts(s)
592
592
  super("#{' ' * @tz_indent}#{s}")
593
593
  end
@@ -602,21 +602,21 @@ module TZInfo
602
602
  file.puts('module Data')
603
603
  file.indent(2)
604
604
  file.puts('module Definitions')
605
- file.indent(2)
606
-
607
- @name_elements.each do |part|
605
+ file.indent(2)
606
+
607
+ @name_elements.each do |part|
608
608
  file.puts("module #{part}")
609
609
  file.indent(2)
610
610
  end
611
-
611
+
612
612
  file.puts('include TimezoneDefinition')
613
613
  file.puts('')
614
-
614
+
615
615
  yield file
616
-
616
+
617
617
  @name_elements.each do
618
- file.indent(-2)
619
- file.puts('end')
618
+ file.indent(-2)
619
+ file.puts('end')
620
620
  end
621
621
  file.indent(-2)
622
622
  file.puts('end') # end module Definitions
@@ -625,88 +625,88 @@ module TZInfo
625
625
  file.indent(-2)
626
626
  file.puts('end') # end module TZInfo
627
627
  end
628
- end
628
+ end
629
629
  end
630
-
630
+
631
631
  # A tz data Link.
632
632
  #
633
633
  # @private
634
634
  class TZDataLink < TZDataDefinition #:nodoc:
635
635
  include TZDataParserUtils
636
-
636
+
637
637
  attr_reader :link_to
638
-
638
+
639
639
  def initialize(name, link_to)
640
640
  super(name)
641
641
  @link_to = link_to
642
642
  end
643
-
643
+
644
644
  # Writes a module for this link.
645
645
  def write_module(output_dir)
646
646
  puts "writing link #{name}"
647
-
647
+
648
648
  create_file(output_dir) {|file|
649
- file.puts("linked_timezone #{quote_str(@name)}, #{quote_str(@link_to.name)}")
649
+ file.puts("linked_timezone #{quote_str(@name)}, #{quote_str(@link_to.name)}")
650
650
  }
651
651
  end
652
-
653
- # Writes an index record for this link.
652
+
653
+ # Writes an index record for this link.
654
654
  def write_index_record(file)
655
655
  file.puts(" linked_timezone #{quote_str(@name)}")
656
656
  end
657
657
  end
658
-
658
+
659
659
  # A tz data Zone. Each line from the tz data is loaded as a TZDataObservance.
660
660
  #
661
661
  # @private
662
662
  class TZDataZone < TZDataDefinition #:nodoc:
663
663
  include TZDataParserUtils
664
-
664
+
665
665
  attr_reader :observances
666
-
666
+
667
667
  def initialize(name, years)
668
668
  super(name)
669
669
  @years = years
670
670
  @observances = []
671
671
  end
672
-
673
- def add_observance(observance)
672
+
673
+ def add_observance(observance)
674
674
  @observances << observance
675
- end
676
-
675
+ end
676
+
677
677
  # Writes the module for the zone. Iterates all the periods and asks them
678
678
  # to write all periods in the timezone.
679
- def write_module(output_dir)
679
+ def write_module(output_dir)
680
680
  puts "writing zone #{name}"
681
-
682
- create_file(output_dir) {|file|
683
-
681
+
682
+ create_file(output_dir) {|file|
683
+
684
684
  file.puts("timezone #{quote_str(@name)} do |tz|")
685
685
  file.indent(2)
686
-
686
+
687
687
  transitions = find_transitions
688
688
  transitions.output_module(file)
689
-
689
+
690
690
  file.indent(-2)
691
691
  file.puts('end')
692
- }
692
+ }
693
693
  end
694
-
695
- # Writes an index record for this zone.
694
+
695
+ # Writes an index record for this zone.
696
696
  def write_index_record(file)
697
697
  file.puts(" timezone #{quote_str(@name)}")
698
698
  end
699
-
699
+
700
700
  private
701
701
  def find_transitions
702
702
  transitions = TZDataTransitions.new(@years)
703
-
703
+
704
704
  # algorithm from zic.c outzone
705
-
705
+
706
706
  start_time = nil
707
707
  until_time = nil
708
-
709
-
708
+
709
+
710
710
  @observances.each_with_index {|observance, i|
711
711
  std_offset = 0
712
712
  use_start = i > 0
@@ -715,11 +715,11 @@ module TZInfo
715
715
  start_zone_id = nil
716
716
  start_utc_offset = observance.utc_offset
717
717
  start_std_offset = 0
718
-
718
+
719
719
  if observance.rule_set.count == 0
720
720
  std_offset = observance.std_offset
721
721
  start_zone_id = observance.format.expand(utc_offset, std_offset, nil)
722
-
722
+
723
723
  if use_start
724
724
  transitions << TZDataTransition.new(start_time, utc_offset, std_offset, start_zone_id)
725
725
  use_start = false
@@ -727,38 +727,38 @@ module TZInfo
727
727
  # zic algorithm only outputs this if std_offset is non-zero
728
728
  # to get the initial LMT range, we output this regardless
729
729
  transitions << TZDataTransition.new(nil, utc_offset, std_offset, start_zone_id)
730
- end
730
+ end
731
731
  else
732
732
  @years.each {|year|
733
733
  if use_until && year > observance.valid_until.year
734
734
  break
735
735
  end
736
-
736
+
737
737
  activated_rules = []
738
-
738
+
739
739
  observance.rule_set.each {|rule|
740
740
  activated_rule = rule.activate(year)
741
741
  activated_rules << activated_rule unless activated_rule.nil?
742
742
  }
743
-
744
- while true
743
+
744
+ while true
745
745
  # turn until_time into UTC using the current utc_offset and std_offset
746
746
  until_time = observance.valid_until.to_utc(utc_offset, std_offset) if use_until
747
-
747
+
748
748
  earliest = nil
749
749
 
750
- activated_rules.each {|activated_rule|
750
+ activated_rules.each {|activated_rule|
751
751
  # recalculate the time using the current std_offset
752
- activated_rule.calculate_time(utc_offset, std_offset)
753
- earliest = activated_rule if earliest.nil? || activated_rule.at < earliest.at
752
+ activated_rule.calculate_time(utc_offset, std_offset)
753
+ earliest = activated_rule if earliest.nil? || activated_rule.at < earliest.at
754
754
  }
755
-
756
- break if earliest.nil?
757
- activated_rules.delete(earliest)
758
- break if use_until && earliest.at >= until_time
759
- std_offset = earliest.rule.save
755
+
756
+ break if earliest.nil?
757
+ activated_rules.delete(earliest)
758
+ break if use_until && earliest.at >= until_time
759
+ std_offset = earliest.rule.save
760
760
  use_start = false if use_start && earliest.at == start_time
761
-
761
+
762
762
  if use_start
763
763
  if earliest.at < start_time
764
764
  start_utc_offset = observance.utc_offset
@@ -766,49 +766,49 @@ module TZInfo
766
766
  start_zone_id = observance.format.expand(start_utc_offset, earliest.rule.save, earliest.rule.letter)
767
767
  next
768
768
  end
769
-
769
+
770
770
  if start_zone_id.nil? && start_utc_offset + start_std_offset == observance.utc_offset + std_offset
771
771
  start_zone_id = observance.format.expand(start_utc_offset, earliest.rule.save, earliest.rule.letter)
772
772
  end
773
773
  end
774
-
774
+
775
775
  zone_id = observance.format.expand(observance.utc_offset, earliest.rule.save, earliest.rule.letter)
776
776
  transitions << TZDataTransition.new(earliest.at, observance.utc_offset, earliest.rule.save, zone_id)
777
- end
777
+ end
778
778
  }
779
779
  end
780
-
780
+
781
781
  if use_start
782
782
  start_zone_id = observance.format.expand(nil, nil, nil) if start_zone_id.nil? && observance.format.fixed?
783
- raise 'Could not determine time zone abbreviation to use just after until time' if start_zone_id.nil?
783
+ raise 'Could not determine time zone abbreviation to use just after until time' if start_zone_id.nil?
784
784
  transitions << TZDataTransition.new(start_time, start_utc_offset, start_std_offset, start_zone_id)
785
785
  end
786
-
787
- start_time = observance.valid_until.to_utc(utc_offset, std_offset) if use_until
786
+
787
+ start_time = observance.valid_until.to_utc(utc_offset, std_offset) if use_until
788
788
  }
789
-
789
+
790
790
  transitions
791
791
  end
792
792
  end
793
-
793
+
794
794
  # A observance within a zone (a line within the zone definition).
795
795
  #
796
796
  # @private
797
797
  class TZDataObservance #:nodoc:
798
798
  include TZDataParserUtils
799
-
799
+
800
800
  attr_reader :utc_offset
801
801
  attr_reader :rule_set
802
802
  attr_reader :format
803
803
  attr_reader :valid_until
804
-
804
+
805
805
  def initialize(utc_offset, rule_set, format, valid_until)
806
806
  @utc_offset = parse_offset(utc_offset)
807
- @rule_set = rule_set
807
+ @rule_set = rule_set
808
808
  @format = TZDataFormat.new(format)
809
- @valid_until = valid_until.nil? ? nil : TZDataUntil.new(valid_until)
810
- end
811
-
809
+ @valid_until = valid_until.nil? ? nil : TZDataUntil.new(valid_until)
810
+ end
811
+
812
812
  def std_offset
813
813
  if @rule_set.kind_of?(TZDataFixedOffsetRules)
814
814
  @rule_set.offset
@@ -817,159 +817,159 @@ module TZInfo
817
817
  end
818
818
  end
819
819
  end
820
-
820
+
821
821
  # Collection of TZDataTransition instances used when building a zone class.
822
822
  #
823
823
  # @private
824
824
  class TZDataTransitions #:nodoc:
825
825
  include TZDataParserUtils
826
-
826
+
827
827
  def initialize(years)
828
828
  @years = years
829
829
  @transitions = []
830
830
  end
831
-
831
+
832
832
  def << (transition)
833
833
  @transitions << transition
834
- end
835
-
834
+ end
835
+
836
836
  def output_module(file)
837
837
  optimize
838
-
838
+
839
839
  # Try and end on a transition to std if one happens in the last year.
840
- if @transitions.length > 1 &&
840
+ if @transitions.length > 1 &&
841
841
  @transitions.last.std_offset != 0 &&
842
842
  @transitions[@transitions.length - 2].std_offset == 0 &&
843
843
  @transitions[@transitions.length - 2].at_utc.year == @years.max
844
-
844
+
845
845
  transitions = @transitions[0..@transitions.length - 2]
846
846
  else
847
847
  transitions = @transitions
848
848
  end
849
-
849
+
850
850
  process_offsets(file)
851
851
  file.puts('')
852
-
853
- transitions.each do |t|
852
+
853
+ transitions.each do |t|
854
854
  t.write(file)
855
- end
855
+ end
856
856
  end
857
-
857
+
858
858
  private
859
859
  def optimize
860
860
  @transitions.sort!
861
-
861
+
862
862
  # Optimization logic from zic.c writezone.
863
-
863
+
864
864
  from_i = 0
865
865
  to_i = 0
866
-
866
+
867
867
  while from_i < @transitions.length
868
- if to_i > 1 &&
868
+ if to_i > 1 &&
869
869
  !@transitions[from_i].at_utc.nil? &&
870
870
  !@transitions[to_i - 1].at_utc.nil? &&
871
871
  @transitions[from_i].at_utc + Rational(@transitions[to_i - 1].total_offset, 86400) <=
872
872
  @transitions[to_i - 1].at_utc + Rational(@transitions[to_i - 2].total_offset, 86400)
873
-
874
- @transitions[to_i - 1] = @transitions[from_i].clone_with_at(@transitions[to_i - 1].at_utc)
873
+
874
+ @transitions[to_i - 1] = @transitions[from_i].clone_with_at(@transitions[to_i - 1].at_utc)
875
875
  from_i += 1
876
876
  next
877
877
  end
878
-
879
- # Shuffle transitions up, eliminating any redundant transitions
878
+
879
+ # Shuffle transitions up, eliminating any redundant transitions
880
880
  # along the way.
881
881
  if to_i == 0 ||
882
882
  @transitions[to_i - 1].utc_offset != @transitions[from_i].utc_offset ||
883
883
  @transitions[to_i - 1].std_offset != @transitions[from_i].std_offset ||
884
884
  @transitions[to_i - 1].zone_id != @transitions[from_i].zone_id
885
-
885
+
886
886
  @transitions[to_i] = @transitions[from_i]
887
- to_i += 1
887
+ to_i += 1
888
888
  end
889
-
889
+
890
890
  from_i += 1
891
- end
892
-
891
+ end
892
+
893
893
  if to_i > 0
894
894
  @transitions = @transitions[0..to_i - 1]
895
895
  else
896
896
  @transitions = []
897
- end
897
+ end
898
898
  end
899
-
900
- def quote_zone_id(zone_id)
899
+
900
+ def quote_zone_id(zone_id)
901
901
  if zone_id =~ %r{[\-+']}
902
- ":#{quote_str(zone_id)}"
902
+ ":#{quote_str(zone_id)}"
903
903
  else
904
904
  ":#{zone_id}"
905
905
  end
906
- end
907
-
906
+ end
907
+
908
908
  def process_offsets(file)
909
909
  # A bit of a hack at the moment. The offset used to be output with
910
910
  # each period (pair of transitions). They are now separated from the
911
911
  # transition data. The code should probably be changed at some point to
912
- # setup the offsets at an earlier stage.
913
-
912
+ # setup the offsets at an earlier stage.
913
+
914
914
  # Assume that when this is called, the first transition is the Local
915
915
  # Mean Time initial rule or a transition with no time that defines the
916
916
  # offset for the entire zone.
917
-
917
+
918
918
  offsets = []
919
-
919
+
920
920
  # Find the first std offset. Timezones always start in std.
921
921
  @transitions.each do |t|
922
922
  if t.std_offset == 0
923
- offset = {:utc_offset => t.utc_offset,
923
+ offset = {:utc_offset => t.utc_offset,
924
924
  :std_offset => t.std_offset,
925
925
  :zone_id => t.zone_id,
926
926
  :name => 'o0'}
927
-
927
+
928
928
  offsets << offset
929
929
  break
930
930
  end
931
931
  end
932
-
932
+
933
933
  @transitions.each do |t|
934
- offset = offsets.find do |o|
934
+ offset = offsets.find do |o|
935
935
  o[:utc_offset] == t.utc_offset &&
936
936
  o[:std_offset] == t.std_offset &&
937
937
  o[:zone_id] == t.zone_id
938
938
  end
939
-
939
+
940
940
  unless offset
941
- offset = {:utc_offset => t.utc_offset,
941
+ offset = {:utc_offset => t.utc_offset,
942
942
  :std_offset => t.std_offset,
943
943
  :zone_id => t.zone_id,
944
944
  :name => "o#{offsets.length}"}
945
-
945
+
946
946
  offsets << offset
947
947
  end
948
-
948
+
949
949
  t.offset_name = offset[:name]
950
950
  end
951
-
951
+
952
952
  offsets.each do |offset|
953
953
  file.puts("tz.offset :#{offset[:name]}, #{offset[:utc_offset]}, #{offset[:std_offset]}, #{quote_zone_id(offset[:zone_id])}")
954
954
  end
955
-
955
+
956
956
  end
957
957
  end
958
-
958
+
959
959
  # A transition that will be used to write the periods in a zone class.
960
960
  #
961
961
  # @private
962
962
  class TZDataTransition #:nodoc:
963
963
  include Comparable
964
-
964
+
965
965
  EPOCH = DateTime.new(1970, 1, 1)
966
-
966
+
967
967
  attr_reader :at_utc
968
968
  attr_reader :utc_offset
969
969
  attr_reader :std_offset
970
970
  attr_reader :zone_id
971
971
  attr_accessor :offset_name
972
-
972
+
973
973
  def initialize(at_utc, utc_offset, std_offset, zone_id)
974
974
  @at_utc = at_utc
975
975
  @utc_offset = utc_offset
@@ -977,11 +977,11 @@ module TZInfo
977
977
  @zone_id = zone_id
978
978
  @offset_name = nil
979
979
  end
980
-
980
+
981
981
  def to_s
982
982
  "At #{at_utc} UTC switch to UTC offset #{@utc_offset} with std offset #{@std_offset}, zone id #{@zone_id}"
983
983
  end
984
-
984
+
985
985
  def <=>(transition)
986
986
  if @at_utc == transition.at_utc
987
987
  0
@@ -989,29 +989,29 @@ module TZInfo
989
989
  -1
990
990
  elsif transition.nil?
991
991
  1
992
- else
992
+ else
993
993
  @at_utc - transition.at_utc
994
994
  end
995
995
  end
996
-
996
+
997
997
  def total_offset
998
998
  @utc_offset + @std_offset
999
999
  end
1000
-
1000
+
1001
1001
  def clone_with_at(at_utc)
1002
1002
  TZDataTransition.new(at_utc, @utc_offset, @std_offset, @zone_id)
1003
1003
  end
1004
-
1005
- def write(file)
1004
+
1005
+ def write(file)
1006
1006
  if @at_utc
1007
- file.puts "tz.transition #{@at_utc.year}, #{@at_utc.mon}, :#{@offset_name}, #{timestamp_parameters(@at_utc)}"
1008
- end
1007
+ file.puts "tz.transition #{@at_utc.year}, #{@at_utc.mon}, :#{@offset_name}, #{timestamp_parameters(@at_utc)}"
1008
+ end
1009
1009
  end
1010
-
1010
+
1011
1011
  private
1012
1012
  def timestamp_parameters(datetime)
1013
1013
  timestamp = ((datetime - EPOCH) * 86400).to_i
1014
-
1014
+
1015
1015
  if timestamp < 0 || timestamp > 2147483647
1016
1016
  # Output DateTime parameters as well as a timestamp for platforms
1017
1017
  # where Time doesn't support negative or 64-bit values.
@@ -1021,7 +1021,7 @@ module TZInfo
1021
1021
  end
1022
1022
  end
1023
1023
  end
1024
-
1024
+
1025
1025
  # An instance of a rule for a year.
1026
1026
  #
1027
1027
  # @private
@@ -1029,18 +1029,18 @@ module TZInfo
1029
1029
  attr_reader :rule
1030
1030
  attr_reader :year
1031
1031
  attr_reader :at
1032
-
1032
+
1033
1033
  def initialize(rule, year)
1034
1034
  @rule = rule
1035
1035
  @year = year
1036
1036
  @at = nil
1037
1037
  end
1038
-
1038
+
1039
1039
  def calculate_time(utc_offset, std_offset)
1040
1040
  @at = @rule.at_utc_time(@year, utc_offset, std_offset)
1041
1041
  end
1042
1042
  end
1043
-
1043
+
1044
1044
  # A tz data time definition - a sign (1 or -1), hour, minute, second and
1045
1045
  # reference (:utc, :standard or :wall_clock).
1046
1046
  #
@@ -1051,15 +1051,15 @@ module TZInfo
1051
1051
  attr_reader :minute
1052
1052
  attr_reader :second
1053
1053
  attr_reader :ref
1054
-
1054
+
1055
1055
  def initialize(spec)
1056
1056
  raise "Invalid time: #{spec}" if spec !~ /^(-?)([0-9]+)(:([0-9]+)(:([0-9]+))?)?([wguzs])?$/
1057
-
1057
+
1058
1058
  @sign = $1 == '-' ? -1 : 1
1059
1059
  @hour = $2.to_i
1060
1060
  @minute = $4.nil? ? 0 : $4.to_i
1061
1061
  @second = $6.nil? ? 0 : $6.to_i
1062
-
1062
+
1063
1063
  if $7 == 's'
1064
1064
  @ref = :standard
1065
1065
  elsif $7 == 'g' || $7 == 'u' || $7 == 'z'
@@ -1068,9 +1068,9 @@ module TZInfo
1068
1068
  @ref = :wall_clock
1069
1069
  end
1070
1070
  end
1071
-
1071
+
1072
1072
  # Converts the time to UTC given a utc_offset and std_offset.
1073
- def to_utc(utc_offset, std_offset, year, month, day)
1073
+ def to_utc(utc_offset, std_offset, year, month, day)
1074
1074
  result = if @hour > 24 || @hour == 24 && (@minute > 0 || @second > 0) || @sign != 1
1075
1075
  DateTime.new(year, month, day, 0, 0, 0) + Rational(@sign * (@second + (@minute + @hour * 60) * 60), 86400)
1076
1076
  else
@@ -1078,12 +1078,12 @@ module TZInfo
1078
1078
  end
1079
1079
 
1080
1080
  offset = 0
1081
- offset = offset + utc_offset if @ref == :standard || @ref == :wall_clock
1082
- offset = offset + std_offset if @ref == :wall_clock
1083
- result - Rational(offset, 86400)
1081
+ offset = offset + utc_offset if @ref == :standard || @ref == :wall_clock
1082
+ offset = offset + std_offset if @ref == :wall_clock
1083
+ result - Rational(offset, 86400)
1084
1084
  end
1085
1085
  end
1086
-
1086
+
1087
1087
  # A tz data day of the month reference. Can either be an absolute day,
1088
1088
  # a last week day or a week day >= or <= than a specific day of month.
1089
1089
  #
@@ -1093,10 +1093,10 @@ module TZInfo
1093
1093
  attr_reader :day_of_month
1094
1094
  attr_reader :day_of_week
1095
1095
  attr_reader :operator
1096
-
1096
+
1097
1097
  def initialize(spec)
1098
1098
  raise "Invalid on: #{spec}" if spec !~ /^([0-9]+)|(last([A-Za-z]+))|(([A-Za-z]+)([<>]=)([0-9]+))$/
1099
-
1099
+
1100
1100
  if $1
1101
1101
  @type = :absolute
1102
1102
  @day_of_month = $1.to_i
@@ -1110,21 +1110,21 @@ module TZInfo
1110
1110
  @day_of_month = $7.to_i
1111
1111
  end
1112
1112
  end
1113
-
1113
+
1114
1114
  # Returns the absolute day of month for the given year and month.
1115
1115
  def to_absolute(year, month)
1116
1116
  case @type
1117
1117
  when :last
1118
- last_day_in_month = (Date.new(year, month, 1) >> 1) - 1
1118
+ last_day_in_month = (Date.new(year, month, 1) >> 1) - 1
1119
1119
  offset = last_day_in_month.wday - @day_of_week
1120
1120
  offset = offset + 7 if offset < 0
1121
1121
  (last_day_in_month - offset).day
1122
1122
  when :comparison
1123
- pivot = Date.new(year, month, @day_of_month)
1123
+ pivot = Date.new(year, month, @day_of_month)
1124
1124
  offset = @day_of_week - pivot.wday
1125
1125
  offset = -offset if @operator == :less_equal
1126
1126
  offset = offset + 7 if offset < 0
1127
- offset = -offset if @operator == :less_equal
1127
+ offset = -offset if @operator == :less_equal
1128
1128
  result = pivot + offset
1129
1129
  if result.month != pivot.month
1130
1130
  puts self.inspect
@@ -1132,12 +1132,12 @@ module TZInfo
1132
1132
  puts month
1133
1133
  end
1134
1134
  raise 'No suitable date found' if result.month != pivot.month
1135
- result.day
1135
+ result.day
1136
1136
  else #absolute
1137
1137
  @day_of_month
1138
1138
  end
1139
1139
  end
1140
-
1140
+
1141
1141
  private
1142
1142
  def parse_day_of_week(day_of_week)
1143
1143
  lower = day_of_week.downcase
@@ -1159,7 +1159,7 @@ module TZInfo
1159
1159
  raise "Invalid day of week: #{day_of_week}"
1160
1160
  end
1161
1161
  end
1162
-
1162
+
1163
1163
  def parse_operator(operator)
1164
1164
  if operator == '>='
1165
1165
  :greater_equal
@@ -1169,40 +1169,40 @@ module TZInfo
1169
1169
  raise "Invalid operator: #{operator}"
1170
1170
  end
1171
1171
  end
1172
- end
1173
-
1172
+ end
1173
+
1174
1174
  # A tz data Zone until reference.
1175
1175
  #
1176
1176
  # @private
1177
1177
  class TZDataUntil #:nodoc:
1178
1178
  include TZDataParserUtils
1179
-
1179
+
1180
1180
  attr_reader :year
1181
1181
  attr_reader :month
1182
1182
  attr_reader :day
1183
1183
  attr_reader :time
1184
-
1185
- def initialize(spec)
1186
- parts = spec.split(/\s+/)
1184
+
1185
+ def initialize(spec)
1186
+ parts = spec.split(/\s+/)
1187
1187
  raise "Invalid until: #{spec}" if parts.length < 1
1188
-
1188
+
1189
1189
  @year = parts[0].to_i
1190
1190
  @month = parts.length > 1 ? parse_month(parts[1]) : 1
1191
1191
  @day = TZDataDayOfMonth.new(parts.length > 2 ? parts[2] : '1')
1192
1192
  @time = TZDataTime.new(parts.length > 3 ? parts[3] : '00:00')
1193
1193
  end
1194
-
1194
+
1195
1195
  # Converts the reference to a UTC DateTime.
1196
1196
  def to_utc(utc_offset, std_offset)
1197
- @time.to_utc(utc_offset, std_offset, @year, @month, @day.to_absolute(@year, @month))
1197
+ @time.to_utc(utc_offset, std_offset, @year, @month, @day.to_absolute(@year, @month))
1198
1198
  end
1199
1199
  end
1200
-
1200
+
1201
1201
  # A tz data Zone format string. Either alternate standard/daylight-savings,
1202
1202
  # substitution (%s) format or a fixed string.
1203
1203
  #
1204
1204
  # @private
1205
- class TZDataFormat #:nodoc:
1205
+ class TZDataFormat #:nodoc:
1206
1206
  def initialize(spec)
1207
1207
  if spec =~ /\A([^\/]*)\/(.*)\z/
1208
1208
  @type = :alternate
@@ -1216,7 +1216,7 @@ module TZInfo
1216
1216
  @abbrev = spec
1217
1217
  end
1218
1218
  end
1219
-
1219
+
1220
1220
  # Expands given the base offset to UTC, the current daylight savings
1221
1221
  # offset and rule string.
1222
1222
  def expand(utc_offset, std_offset, rule_string)
@@ -1232,14 +1232,14 @@ module TZInfo
1232
1232
  end
1233
1233
  else
1234
1234
  @abbrev
1235
- end
1235
+ end
1236
1236
  end
1237
-
1237
+
1238
1238
  # True if the format requires substitutions (%s or %z).
1239
1239
  def subst?
1240
1240
  @type == :subst
1241
1241
  end
1242
-
1242
+
1243
1243
  # Is a fixed format string.
1244
1244
  def fixed?
1245
1245
  @type == :fixed
@@ -1277,67 +1277,67 @@ module TZInfo
1277
1277
  end
1278
1278
  end
1279
1279
  end
1280
-
1280
+
1281
1281
  # A location (latitude + longitude)
1282
1282
  #
1283
1283
  # @private
1284
1284
  class TZDataLocation #:nodoc:
1285
1285
  attr_reader :latitude
1286
1286
  attr_reader :longitude
1287
-
1288
- # Constructs a new TZDataLocation from a string in ISO 6709
1289
- # sign-degrees-minutes-seconds format, either +-DDMM+-DDDMM
1290
- # or +-DDMMSS+-DDDMMSS, first latitude (+ is north),
1287
+
1288
+ # Constructs a new TZDataLocation from a string in ISO 6709
1289
+ # sign-degrees-minutes-seconds format, either +-DDMM+-DDDMM
1290
+ # or +-DDMMSS+-DDDMMSS, first latitude (+ is north),
1291
1291
  # then longitude (+ is east).
1292
1292
  def initialize(coordinates)
1293
1293
  if coordinates !~ /^([+\-])([0-9]{2})([0-9]{2})([0-9]{2})?([+\-])([0-9]{3})([0-9]{2})([0-9]{2})?$/
1294
1294
  raise "Invalid coordinates: #{coordinates}"
1295
1295
  end
1296
-
1296
+
1297
1297
  @latitude = Rational($2.to_i) + Rational($3.to_i, 60)
1298
1298
  @latitude += Rational($4.to_i, 3600) unless $4.nil?
1299
1299
  @latitude = -@latitude if $1 == '-'
1300
-
1300
+
1301
1301
  @longitude = Rational($6.to_i) + Rational($7.to_i, 60)
1302
1302
  @longitude += Rational($8.to_i, 3600) unless $8.nil?
1303
1303
  @longitude = -@longitude if $5 == '-'
1304
1304
  end
1305
- end
1305
+ end
1306
1306
 
1307
1307
  # @private
1308
1308
  TZDataCountryTimezone = Struct.new(:timezone, :description, :location) #:nodoc:
1309
-
1309
+
1310
1310
  # An ISO 3166 country.
1311
1311
  #
1312
1312
  # @private
1313
1313
  class TZDataCountry #:nodoc:
1314
1314
  include TZDataParserUtils
1315
-
1315
+
1316
1316
  attr_reader :code
1317
1317
  attr_reader :name
1318
1318
  attr_reader :zones
1319
-
1319
+
1320
1320
  def initialize(code, name)
1321
1321
  @code = code
1322
1322
  @name = name
1323
1323
  @zones = []
1324
1324
  end
1325
-
1325
+
1326
1326
  # Adds a TZDataCountryTimezone
1327
- def add_zone(zone)
1328
- @zones << zone
1329
- end
1330
-
1327
+ def add_zone(zone)
1328
+ @zones << zone
1329
+ end
1330
+
1331
1331
  def write_index_record(file)
1332
- s = " country #{quote_str(@code)}, #{quote_str(@name)}"
1332
+ s = " country #{quote_str(@code)}, #{quote_str(@name)}"
1333
1333
  s << ' do |c|' if @zones.length > 0
1334
-
1334
+
1335
1335
  file.puts s
1336
-
1336
+
1337
1337
  @zones.each do |zone|
1338
- file.puts " c.timezone #{quote_str(zone.timezone.name)}, #{zone.location.latitude.numerator}, #{zone.location.latitude.denominator}, #{zone.location.longitude.numerator}, #{zone.location.longitude.denominator}#{zone.description.nil? ? '' : ', ' + quote_str(zone.description)}"
1338
+ file.puts " c.timezone #{quote_str(zone.timezone.name)}, #{zone.location.latitude.numerator}, #{zone.location.latitude.denominator}, #{zone.location.longitude.numerator}, #{zone.location.longitude.denominator}#{zone.description.nil? ? '' : ', ' + quote_str(zone.description)}"
1339
1339
  end
1340
-
1340
+
1341
1341
  file.puts ' end' if @zones.length > 0
1342
1342
  end
1343
1343
  end