Object
Parses tzdata from elsie.nci.nih.gov/pub/ and transforms it into a set of Ruby modules that can be used through Timezone and Country.
Normally, this class wouldn’t be used. It is only run to update the timezone data and index modules.
Whether to generate zone definitions (set to false to stop zones being generated).
Whether to generate country definitions (set to false to stop countries being generated).
Zones to exclude from generation when not using only_zones (set to an array containing zone identifiers).
Initializes a new TZDataParser. input_dir must contain the extracted tzdata tarball. output_dir is the location to output the modules (in definitions and indexes directories).
# File lib/tzinfo/tzdataparser.rb, line 59
59: def initialize(input_dir, output_dir)
60: super()
61: @input_dir = input_dir
62: @output_dir = output_dir
63: @rule_sets = {}
64: @zones = {}
65: @countries = {}
66: @no_rules = TZDataNoRules.new
67: @generate_zones = true
68: @generate_countries = true
69: @only_zones = []
70: @exclude_zones = []
71: end
Parses a month specified in the tz data and converts it to a number between 1 and 12 representing January to December.
# File lib/tzinfo/tzdataparser.rb, line 114
114: def self.parse_month(month)
115: lower = month.downcase
116: if lower =~ /^jan/
117: @month = 1
118: elsif lower =~ /^feb/
119: @month = 2
120: elsif lower =~ /^mar/
121: @month = 3
122: elsif lower =~ /^apr/
123: @month = 4
124: elsif lower =~ /^may/
125: @month = 5
126: elsif lower =~ /^jun/
127: @month = 6
128: elsif lower =~ /^jul/
129: @month = 7
130: elsif lower =~ /^aug/
131: @month = 8
132: elsif lower =~ /^sep/
133: @month = 9
134: elsif lower =~ /^oct/
135: @month = 10
136: elsif lower =~ /^nov/
137: @month = 11
138: elsif lower =~ /^dec/
139: @month = 12
140: else
141: raise "Invalid month: #{month}"
142: end
143: end
Parses an offset string [-]h:m:s (minutes and seconds are optional). Returns the offset in seconds.
# File lib/tzinfo/tzdataparser.rb, line 147
147: def self.parse_offset(offset)
148: raise "Invalid time: #{offset}" if offset !~ /^(-)?(?:([0-9]+)(?::([0-9]+)(?::([0-9]+))?)?)?$/
149:
150: negative = !$1.nil?
151: hour = $2.nil? ? 0 : $2.to_i
152: minute = $3.nil? ? 0 : $3.to_i
153: second = $4.nil? ? 0 : $4.to_i
154:
155: seconds = hour
156: seconds = seconds * 60
157: seconds = seconds + minute
158: seconds = seconds * 60
159: seconds = seconds + second
160: seconds = -seconds if negative
161: seconds
162: end
Reads the tzdata source and generates the classes. Takes a long time to run. Currently outputs debugging information to standard out.
# File lib/tzinfo/tzdataparser.rb, line 75
75: def execute
76: Dir.foreach(@input_dir) {|file|
77: load_rules(file) if file =~ /^[^\.]+$/
78: }
79:
80: Dir.foreach(@input_dir) {|file|
81: load_zones(file) if file =~ /^[^\.]+$/
82: }
83:
84: Dir.foreach(@input_dir) {|file|
85: load_links(file) if file =~ /^[^\.]+$/
86: }
87:
88: load_countries
89:
90: if @generate_zones
91: modules = []
92:
93: if @only_zones.nil? || @only_zones.empty?
94: @zones.each_value {|zone|
95: zone.write_module(@output_dir) unless @exclude_zones.include?(zone.name)
96: }
97: else
98: @only_zones.each {|id|
99: zone = @zones[id]
100: zone.write_module(@output_dir)
101: }
102: end
103:
104: write_timezones_index
105: end
106:
107: if @generate_countries
108: write_countries_index
109: end
110: end
Gets a rules object for the given reference. Might be a named rule set, a fixed offset or an empty ruleset.
# File lib/tzinfo/tzdataparser.rb, line 195
195: def get_rules(ref)
196: if ref == '-'
197: @no_rules
198: elsif ref =~ /^[0-9]+:[0-9]+$/
199: TZDataFixedOffsetRules.new(TZDataParser.parse_offset(ref))
200: else
201: rule_set = @rule_sets[ref]
202: raise "Ruleset not found: #{ref}" if rule_set.nil?
203: rule_set
204: end
205: end
Loads countries from iso3166.tab and zone.tab and stores the result in @countries.
# File lib/tzinfo/tzdataparser.rb, line 260
260: def load_countries
261: puts 'load_countries'
262:
263: IO.foreach(@input_dir + File::SEPARATOR + 'iso3166.tab') {|line|
264: if line =~ /^([A-Z]{2})\t(.*)$/
265: code = $1
266: name = $2
267: @countries[code] = TZDataCountry.new(code, name)
268: end
269: }
270:
271: IO.foreach(@input_dir + File::SEPARATOR + 'zone.tab') {|line|
272: line.chomp!
273:
274: if line =~ /^([A-Z]{2})\t([^\t]+)\t([^\t]+)(\t(.*))?$/
275: code = $1
276: location_str = $2
277: zone_name = $3
278: description = $5
279:
280: country = @countries[code]
281: raise "Country not found: #{code}" if country.nil?
282:
283: location = TZDataLocation.new(location_str)
284:
285: zone = @zones[zone_name]
286: raise "Zone not found: #{zone_name}" if zone.nil?
287:
288: description = nil if description == ''
289:
290: country.add_zone(TZDataCountryTimezone.new(zone, description, location))
291: end
292: }
293: end
Loads in the links and stores them in @zones.
# File lib/tzinfo/tzdataparser.rb, line 241
241: def load_links(file)
242: puts 'load_links: ' + file
243:
244: IO.foreach(@input_dir + File::SEPARATOR + file) {|line|
245: line = line.gsub(/#.*$/, '')
246: line = line.gsub(/\s+$/, '')
247:
248: if line =~ /^Link\s+([^\s]+)\s+([^\s]+)/
249: name = $2
250: link_to = @zones[$1]
251: raise "Link to zone not found (#{name}->#{link_to})" if link_to.nil?
252: raise "Zone already defined: #{name}" if !@zones[name].nil?
253: @zones[name] = TZDataLink.new(name, link_to)
254: end
255: }
256: end
Loads all the Rule definitions from the tz data and stores them in @rule_sets.
# File lib/tzinfo/tzdataparser.rb, line 173
173: def load_rules(file)
174: puts 'load_rules: ' + file
175:
176: IO.foreach(@input_dir + File::SEPARATOR + file) {|line|
177: line = line.gsub(/#.*$/, '')
178: line = line.gsub(/\s+$/, '')
179:
180: if line =~ /^Rule\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)/
181:
182: name = $1
183:
184: if @rule_sets[name].nil?
185: @rule_sets[name] = TZDataRuleSet.new(name)
186: end
187:
188: @rule_sets[name].add_rule(TZDataRule.new($2, $3, $4, $5, $6, $7, $8, $9))
189: end
190: }
191: end
Loads in the Zone definitions from the tz data and stores them in @zones.
# File lib/tzinfo/tzdataparser.rb, line 208
208: def load_zones(file)
209: puts 'load_zones: ' + file
210:
211: in_zone = nil
212:
213: IO.foreach(@input_dir + File::SEPARATOR + file) {|line|
214: line = line.gsub(/#.*$/, '')
215: line = line.gsub(/\s+$/, '')
216:
217: if in_zone
218: if line =~ /^\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)(\s+([0-9]+(\s+.*)?))?$/
219:
220: in_zone.add_observance(TZDataObservance.new($1, get_rules($2), $3, $5))
221:
222: in_zone = nil if $4.nil?
223: end
224: else
225: if line =~ /^Zone\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)(\s+([0-9]+(\s+.*)?))?$/
226: name = $1
227:
228: if @zones[name].nil?
229: @zones[name] = TZDataZone.new(name)
230: end
231:
232: @zones[name].add_observance(TZDataObservance.new($2, get_rules($3), $4, $6))
233:
234: in_zone = @zones[name] if !$5.nil?
235: end
236: end
237: }
238: end
Writes a country index file.
# File lib/tzinfo/tzdataparser.rb, line 296
296: def write_countries_index
297: dir = @output_dir + File::SEPARATOR + 'indexes'
298: FileUtils.mkdir_p(dir)
299:
300: File.open(dir + File::SEPARATOR + 'countries.rb', 'w') {|file|
301: file.binmode
302:
303: file.puts('module TZInfo')
304: file.puts(' module Indexes')
305: file.puts(' module Countries')
306: file.puts(' include CountryIndexDefinition')
307: file.puts('')
308:
309: countries = @countries.values.sort {|c1,c2| c1.code <=> c2.code}
310: countries.each {|country| country.write_index_record(file)}
311:
312: file.puts(' end') # end module Countries
313: file.puts(' end') # end module Indexes
314: file.puts('end') # end module TZInfo
315: }
316: end
Writes a timezone index file.
# File lib/tzinfo/tzdataparser.rb, line 319
319: def write_timezones_index
320: dir = File.join(@output_dir, 'indexes')
321: FileUtils.mkdir_p(dir)
322:
323: File.open(File.join(dir, 'timezones.rb'), 'w') do |file|
324: file.binmode
325:
326: file.puts('module TZInfo')
327: file.puts(' module Indexes')
328: file.puts(' module Timezones')
329: file.puts(' include TimezoneIndexDefinition')
330: file.puts('')
331:
332: zones = @zones.values.sort {|t1,t2| t1.name <=> t2.name}
333: zones.each {|zone| zone.write_index_record(file)}
334:
335: file.puts(' end') # end module Timezones
336: file.puts(' end') # end module Indexes
337: file.puts('end') # end module TZInfo
338: end
339:
340: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.