TimezoneParser 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/.yardopts +1 -0
- data/Gemfile +10 -0
- data/README.md +133 -0
- data/Rakefile +160 -0
- data/TimezoneParser.gemspec +40 -0
- data/UNLICENSE +24 -0
- data/data/version.yml +5 -0
- data/lib/timezone_parser.rb +159 -0
- data/lib/timezone_parser/abbreviation.rb +120 -0
- data/lib/timezone_parser/data.rb +121 -0
- data/lib/timezone_parser/data/cldr.rb +175 -0
- data/lib/timezone_parser/data/storage.rb +172 -0
- data/lib/timezone_parser/data/tzinfo.rb +151 -0
- data/lib/timezone_parser/data/windows.rb +124 -0
- data/lib/timezone_parser/rails_zone.rb +178 -0
- data/lib/timezone_parser/timezone.rb +159 -0
- data/lib/timezone_parser/version.rb +5 -0
- data/lib/timezone_parser/windows_zone.rb +169 -0
- data/lib/timezone_parser/zone_info.rb +70 -0
- data/spec/abbreviation_spec.rb +122 -0
- data/spec/rails_zone_spec.rb +84 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/timezone_parser_spec.rb +76 -0
- data/spec/timezone_spec.rb +108 -0
- data/spec/windows_zone_spec.rb +81 -0
- metadata +228 -0
@@ -0,0 +1,120 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module TimezoneParser
|
4
|
+
# Timezone abbreviation
|
5
|
+
class Abbreviation < ZoneInfo
|
6
|
+
protected
|
7
|
+
@@Regions = []
|
8
|
+
|
9
|
+
public
|
10
|
+
# Regions which will be used for Abbreviation methods if not specified there
|
11
|
+
#
|
12
|
+
# Each region is either ISO 3166-1 alpha-2 code
|
13
|
+
# @return [Array<String>] list containing region identifiers
|
14
|
+
# @see http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
|
15
|
+
def self.Regions
|
16
|
+
@@Regions
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_accessor :Regions
|
20
|
+
attr_accessor :Type
|
21
|
+
|
22
|
+
# Abbreviation instance
|
23
|
+
# @param abbreviation [String] Timezone abbreviation
|
24
|
+
def initialize(abbreviation)
|
25
|
+
@Abbreviation = abbreviation
|
26
|
+
@Data = Data.new
|
27
|
+
setTime
|
28
|
+
set(@@Regions.dup, nil)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Set regions and type
|
32
|
+
# @param regions [Array<String>] filter for these regions
|
33
|
+
# @param type [Symbol] filter by type, :standard time or :daylight
|
34
|
+
# @return [Abbreviation] self
|
35
|
+
# @see Regions
|
36
|
+
def set(regions = nil, type = nil)
|
37
|
+
@Regions = regions unless regions.nil?
|
38
|
+
@Type = type.to_sym if type
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
# Check if abbreviation is valid
|
43
|
+
# @return [Boolean] whether abbreviation is valid
|
44
|
+
def isValid?
|
45
|
+
Data::Storage.Abbreviations.has_key?(@Abbreviation)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Abbreviation data
|
49
|
+
# @return [Data] data
|
50
|
+
def getData
|
51
|
+
unless @Loaded
|
52
|
+
@Loaded = true
|
53
|
+
if isValid?
|
54
|
+
data = Data::Storage.Abbreviations[@Abbreviation]
|
55
|
+
if data.count == 1
|
56
|
+
@Data.processEntry(data.first, @ToTime, @FromTime, @Regions)
|
57
|
+
return @Data
|
58
|
+
end
|
59
|
+
entries = Data.filterData(data, @ToTime, @FromTime, @Type, @Regions)
|
60
|
+
entries.each do |entry|
|
61
|
+
@Data.processEntry(entry, @ToTime, @FromTime, @Regions)
|
62
|
+
end
|
63
|
+
return @Data
|
64
|
+
end
|
65
|
+
end
|
66
|
+
@Data
|
67
|
+
end
|
68
|
+
|
69
|
+
# Get UTC offsets in seconds
|
70
|
+
# @return [Array<Fixnum>] list of timezone offsets in seconds
|
71
|
+
def getOffsets
|
72
|
+
unless @Offsets
|
73
|
+
@Offsets = getData.Offsets.to_a
|
74
|
+
if @Offsets.empty? and not getTimezones.empty?
|
75
|
+
types = nil
|
76
|
+
types = [@Type] if @Type
|
77
|
+
@Offsets = @Data.findOffsets(@ToTime, @FromTime, @Regions, types).to_a
|
78
|
+
end
|
79
|
+
end
|
80
|
+
@Offsets
|
81
|
+
end
|
82
|
+
|
83
|
+
# Check if given Timezone abbreviation is a valid timezone
|
84
|
+
# @param abbreviation [String] Timezone abbreviation
|
85
|
+
# @return [Boolean] whether Timezone is valid
|
86
|
+
def self.isValid?(abbreviation)
|
87
|
+
Data::Storage.Abbreviations.has_key?(abbreviation)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Get UTC offsets in seconds for given Timezone abbreviation
|
91
|
+
# @param abbreviation [String] Timezone abbreviation
|
92
|
+
# @param toTime [DateTime] look for offsets which came into effect before this date, exclusive
|
93
|
+
# @param fromTime [DateTime] look for offsets which came into effect at this date, inclusive
|
94
|
+
# @param regions [Array<String>] look for offsets only for these regions
|
95
|
+
# @param type [Symbol] specify whether offset should be :standard time or :daylight
|
96
|
+
# @return [Array<Fixnum>] list of timezone offsets in seconds
|
97
|
+
# @see Regions
|
98
|
+
def self.getOffsets(abbreviation, toTime = nil, fromTime = nil, regions = nil, type = nil)
|
99
|
+
self.new(abbreviation).setTime(toTime, fromTime).set(regions, type).getOffsets
|
100
|
+
end
|
101
|
+
|
102
|
+
# Get Timezone identifiers for given Timezone abbreviation
|
103
|
+
# @param abbreviation [String] Timezone abbreviation
|
104
|
+
# @param toTime [DateTime] look for timezones which came into effect before this date, exclusive
|
105
|
+
# @param fromTime [DateTime] look for timezones which came into effect at this date, inclusive
|
106
|
+
# @param regions [Array<String>] look for timezones only for these regions
|
107
|
+
# @param type [Symbol] specify whether timezones should be :standard time or :daylight
|
108
|
+
# @return [Array<String>] list of timezone identifiers
|
109
|
+
# @see Regions
|
110
|
+
def self.getTimezones(abbreviation, toTime = nil, fromTime = nil, regions = nil, type = nil)
|
111
|
+
self.new(abbreviation).setTime(toTime, fromTime).set(regions, type).getTimezones
|
112
|
+
end
|
113
|
+
|
114
|
+
# Get Metazone identifiers for given Timezone abbreviation
|
115
|
+
# @param abbreviation [String] Timezone abbreviation
|
116
|
+
def self.getMetazones(abbreviation)
|
117
|
+
self.new(abbreviation).getMetazones
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'pathname'
|
3
|
+
require 'set'
|
4
|
+
require 'tzinfo'
|
5
|
+
require 'timezone_parser/data/storage'
|
6
|
+
|
7
|
+
module TimezoneParser
|
8
|
+
# Timezone data
|
9
|
+
class Data
|
10
|
+
# Library Root directory
|
11
|
+
RootDir = Pathname.new(__FILE__).realpath.dirname.parent.parent
|
12
|
+
# Path to Data directory
|
13
|
+
DataDir = RootDir + 'data'
|
14
|
+
# Path to Vendor directory
|
15
|
+
VendorDir = RootDir + 'vendor'
|
16
|
+
|
17
|
+
attr_reader :Offsets
|
18
|
+
attr_reader :Timezones
|
19
|
+
attr_reader :Types
|
20
|
+
attr_reader :Metazones
|
21
|
+
def initialize
|
22
|
+
@Offsets = SortedSet.new
|
23
|
+
@Timezones = SortedSet.new
|
24
|
+
@Types = SortedSet.new
|
25
|
+
@Metazones = SortedSet.new
|
26
|
+
end
|
27
|
+
|
28
|
+
def processEntry(entry, toTime, fromTime, regions = [])
|
29
|
+
@Timezones += entry['Timezones'] if entry['Timezones']
|
30
|
+
@Offsets << entry['Offset'] if entry['Offset']
|
31
|
+
@Types += entry['Types'].map(&:to_sym) if entry['Types']
|
32
|
+
if entry.has_key?('Metazones')
|
33
|
+
entry['Metazones'].each do |zone|
|
34
|
+
@Metazones << zone
|
35
|
+
@Timezones += Storage.getTimezones(zone, toTime, fromTime, regions)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def findOffsets(toTime, fromTime, regions = nil, types = nil)
|
42
|
+
types = @Types.to_a unless types
|
43
|
+
types = [:daylight, :standard] if types.empty?
|
44
|
+
@Timezones.each do |timezone|
|
45
|
+
if regions and not regions.empty?
|
46
|
+
timezoneRegions = Data::Storage.TimezoneCountries[timezone]
|
47
|
+
next if timezoneRegions and (timezoneRegions & regions).empty?
|
48
|
+
end
|
49
|
+
begin
|
50
|
+
tz = TZInfo::Timezone.get(timezone)
|
51
|
+
rescue TZInfo::InvalidTimezoneIdentifier
|
52
|
+
tz = nil
|
53
|
+
end
|
54
|
+
next unless tz
|
55
|
+
offsets = []
|
56
|
+
ts = false
|
57
|
+
tz.transitions_up_to(toTime, fromTime).each do |transition|
|
58
|
+
ts = true
|
59
|
+
self.class.addOffset(offsets, transition.offset, types)
|
60
|
+
end
|
61
|
+
self.class.addOffset(offsets, tz.period_for_utc(toTime - 0.001).offset, types) unless ts
|
62
|
+
@Offsets += offsets
|
63
|
+
end
|
64
|
+
@Offsets
|
65
|
+
end
|
66
|
+
|
67
|
+
# Load data entries which match specified time
|
68
|
+
# @param data [Array<Hash>] array of entries
|
69
|
+
# @param toTime [DateTime] entries before this date, exclusive
|
70
|
+
# @param fromTime [DateTime] entries after/at this date, inclusive
|
71
|
+
# @return [Array<Hash>] resulting array containing filtered entries
|
72
|
+
def self.loadEntries(data, toTime, fromTime, offsets = false)
|
73
|
+
result = []
|
74
|
+
data.each do |entry|
|
75
|
+
result << entry if (entry['From'] && entry['To'] and toTime > entry['From'] and fromTime < entry['To']) or
|
76
|
+
(entry['From'] && !entry['To'] and toTime > entry['From']) or
|
77
|
+
(!entry['From'] && entry['To'] and fromTime < entry['To']) or
|
78
|
+
(!entry['From'] && !entry['To'])
|
79
|
+
end
|
80
|
+
result.each do |entry|
|
81
|
+
return result if not offsets or (offsets and entry['Offset'])
|
82
|
+
end
|
83
|
+
data.each_index do |i|
|
84
|
+
entry = data[i]
|
85
|
+
nextentry = offsets ? getNextEntry(data, i) : data[i+1]
|
86
|
+
result << entry if ( entry['From'] && entry['To'] and toTime > entry['From'] and fromTime < entry['To'] ) or
|
87
|
+
( entry['To'] and ( (nextentry.nil? and fromTime >= entry['To']) or
|
88
|
+
(nextentry and nextentry['From'] and fromTime >= entry['To'] and toTime <= nextentry['From']) or
|
89
|
+
(!entry['From'] and fromTime < entry['To']) ) ) or
|
90
|
+
( entry['From'] and ( (i.zero? and toTime <= entry['From']) or (!entry['To'] and toTime > entry['From']) ) )
|
91
|
+
end
|
92
|
+
result
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.filterData(data, toTime, fromTime, type, regions)
|
96
|
+
entries = []
|
97
|
+
data.each do |entry|
|
98
|
+
next if type and entry['Types'] and not entry['Types'].include?(type)
|
99
|
+
next if not regions.empty? and entry['Countries'] and (entry['Countries'] & regions).empty?
|
100
|
+
entries << entry
|
101
|
+
end
|
102
|
+
loadEntries(entries, toTime, fromTime, true)
|
103
|
+
end
|
104
|
+
|
105
|
+
protected
|
106
|
+
|
107
|
+
def self.getNextEntry(data, i)
|
108
|
+
j = 1
|
109
|
+
begin
|
110
|
+
entry = data[i+j]
|
111
|
+
j += 1
|
112
|
+
end until entry.nil? or (entry and entry['Offset'])
|
113
|
+
entry
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.addOffset(offsets, offset, types)
|
117
|
+
offsets << offset.utc_total_offset if (offset.dst? and types.include?(:daylight)) or (not offset.dst? and types.include?(:standard))
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'cldr'
|
3
|
+
require 'cldr/download'
|
4
|
+
require 'cldr/export/data'
|
5
|
+
require 'cldr/export/data/timezones'
|
6
|
+
require 'pathname'
|
7
|
+
|
8
|
+
module TimezoneParser
|
9
|
+
# CLDR module
|
10
|
+
module CLDR
|
11
|
+
|
12
|
+
# Data directory
|
13
|
+
DataDir = Pathname.new(Cldr::Export::Data.dir)
|
14
|
+
|
15
|
+
protected
|
16
|
+
@@Version = nil
|
17
|
+
|
18
|
+
public
|
19
|
+
def self.download(source = 'http://unicode.org/Public/cldr/latest/core.zip', target = nil)
|
20
|
+
Cldr.download(source, target)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.updateHash(hash, name, data)
|
24
|
+
hash[name] ||= []
|
25
|
+
hash[name] << data.to_s
|
26
|
+
hash[name].uniq!
|
27
|
+
hash[name].sort!
|
28
|
+
hash
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.getVersion(source = DataDir)
|
32
|
+
return @@Version if @@Version
|
33
|
+
content = File.read(source + 'dtd' + 'ldml.dtd')
|
34
|
+
content.gsub!(/<!--.*?-->/, '')
|
35
|
+
data = content.match(/\s+cldrVersion\s+[\#\w\s]+\s+"(\d+)"\s*\>/)
|
36
|
+
@@Version = data[1].to_i if data
|
37
|
+
@@Version
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.getTimezones
|
41
|
+
timezones = { }
|
42
|
+
Cldr::Export::Data.locales.sort.each do |locale|
|
43
|
+
tz = Cldr::Export::Data::Timezones.new(locale)
|
44
|
+
next if tz.timezones.empty? and tz.metazones.empty?
|
45
|
+
|
46
|
+
tz.timezones.each do |timezone, data|
|
47
|
+
next if timezone == :'Etc/Unknown' or data[:city].nil?
|
48
|
+
city = data[:city].to_s.encode(Encoding::UTF_8).chomp.strip
|
49
|
+
timezones[locale] ||= {}
|
50
|
+
timezones[locale][city] ||= {}
|
51
|
+
self.updateHash(timezones[locale][city], 'Timezones', timezone)
|
52
|
+
data[:long].to_a.each do |type, name|
|
53
|
+
name = name.to_s.encode(Encoding::UTF_8).chomp.strip
|
54
|
+
type = type.to_s.encode(Encoding::UTF_8)
|
55
|
+
timezones[locale][name] ||= {}
|
56
|
+
if type == 'generic'
|
57
|
+
self.updateHash(timezones[locale][name], 'Types', 'standard')
|
58
|
+
self.updateHash(timezones[locale][name], 'Types', 'daylight')
|
59
|
+
else
|
60
|
+
self.updateHash(timezones[locale][name], 'Types', type)
|
61
|
+
end
|
62
|
+
self.updateHash(timezones[locale][name], 'Timezones', timezone.to_s.encode(Encoding::UTF_8))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
tz.metazones.each do |metazone, data|
|
66
|
+
data[:long].to_a.each do |type, name|
|
67
|
+
name = name.to_s.encode(Encoding::UTF_8).chomp.strip
|
68
|
+
next if name.empty?
|
69
|
+
type = type.to_s.encode(Encoding::UTF_8)
|
70
|
+
timezones[locale] ||= {}
|
71
|
+
timezones[locale][name] ||= {}
|
72
|
+
if type == 'generic'
|
73
|
+
self.updateHash(timezones[locale][name], 'Types', 'standard')
|
74
|
+
self.updateHash(timezones[locale][name], 'Types', 'daylight')
|
75
|
+
else
|
76
|
+
self.updateHash(timezones[locale][name], 'Types', type)
|
77
|
+
end
|
78
|
+
self.updateHash(timezones[locale][name], 'Metazones', metazone.to_s.encode(Encoding::UTF_8))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
timezones[locale] = Hash[timezones[locale].to_a.sort_by { |d| d.first } ] if timezones[locale]
|
82
|
+
end
|
83
|
+
timezones
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.updateAbbreviations(abbreviations)
|
87
|
+
Cldr::Export::Data.locales.sort.each do |locale|
|
88
|
+
tz = Cldr::Export::Data::Timezones.new(locale)
|
89
|
+
next if tz.timezones.empty? and tz.metazones.empty?
|
90
|
+
tz.timezones.each do |timezone, data|
|
91
|
+
data[:short].to_a.each do |type, name|
|
92
|
+
next if name == '∅∅∅'
|
93
|
+
name = name.chomp.strip
|
94
|
+
type = type.to_s.encode(Encoding::UTF_8)
|
95
|
+
abbreviations[name] ||= []
|
96
|
+
data = {}
|
97
|
+
add = true
|
98
|
+
abbreviations[name].each_index do |i|
|
99
|
+
next unless abbreviations[name][i]['Offset'].nil?
|
100
|
+
data = abbreviations[name][i]
|
101
|
+
add = false
|
102
|
+
break
|
103
|
+
end
|
104
|
+
if type == 'generic'
|
105
|
+
self.updateHash(data, 'Types', 'standard')
|
106
|
+
self.updateHash(data, 'Types', 'daylight')
|
107
|
+
else
|
108
|
+
self.updateHash(data, 'Types', type)
|
109
|
+
end
|
110
|
+
self.updateHash(data, 'Timezones', timezone)
|
111
|
+
abbreviations[name] << data if add
|
112
|
+
end
|
113
|
+
end
|
114
|
+
tz.metazones.each do |metazone, data|
|
115
|
+
data[:short].to_a.each do |type, name|
|
116
|
+
next if name == '∅∅∅'
|
117
|
+
name = name.chomp.strip
|
118
|
+
type = type.to_s.encode(Encoding::UTF_8)
|
119
|
+
abbreviations[name] ||= []
|
120
|
+
data = {}
|
121
|
+
add = true
|
122
|
+
abbreviations[name].each_index do |i|
|
123
|
+
next unless abbreviations[name][i]['Offset'].nil?
|
124
|
+
data = abbreviations[name][i]
|
125
|
+
add = false
|
126
|
+
break
|
127
|
+
end
|
128
|
+
if type == 'generic'
|
129
|
+
self.updateHash(data, 'Types', 'standard')
|
130
|
+
self.updateHash(data, 'Types', 'daylight')
|
131
|
+
else
|
132
|
+
self.updateHash(data, 'Types', type)
|
133
|
+
end
|
134
|
+
self.updateHash(data, 'Metazones', metazone)
|
135
|
+
abbreviations[name] << data if add
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
abbreviations = Hash[abbreviations.to_a.sort_by { |d| d.first } ]
|
140
|
+
abbreviations
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.getMetazones
|
144
|
+
zones = {}
|
145
|
+
Cldr::Export::Data::Metazones.new[:timezones].each do |timezone, zonedata|
|
146
|
+
zonedata.each do |data|
|
147
|
+
entry = {}
|
148
|
+
add = true
|
149
|
+
zones[data['metazone']] ||= []
|
150
|
+
zones[data['metazone']].each_index do |i|
|
151
|
+
next if zones[data['metazone']][i]['From'].to_s != data['from'].to_s or zones[data['metazone']][i]['To'].to_s != data['to'].to_s
|
152
|
+
entry = zones[data['metazone']][i]
|
153
|
+
add = false
|
154
|
+
break
|
155
|
+
end
|
156
|
+
self.updateHash(entry, 'Timezones', timezone)
|
157
|
+
if add
|
158
|
+
entry['From'] = data['from'].to_s if data['from']
|
159
|
+
entry['To'] = data['to'].to_s if data['to']
|
160
|
+
zones[data['metazone']] << entry
|
161
|
+
end
|
162
|
+
zones[data['metazone']].sort_by! { |d| [d['To'] ? d['To'] : 'zzzz', d['From'] ? d['From'] : ''] }
|
163
|
+
end
|
164
|
+
end
|
165
|
+
zones = Hash[zones.to_a.sort_by { |d| d.first } ]
|
166
|
+
zones
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.getWindowsZones
|
170
|
+
zones = Cldr::Export::Data::WindowsZones.new
|
171
|
+
zones = Hash[zones.to_a.sort_by { |d| d.first } ]
|
172
|
+
zones
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'yaml'
|
3
|
+
require 'date'
|
4
|
+
require 'insensitive_hash'
|
5
|
+
|
6
|
+
module TimezoneParser
|
7
|
+
class Data
|
8
|
+
# Timezone data Storage class
|
9
|
+
class Storage
|
10
|
+
protected
|
11
|
+
@@Abbreviations = nil
|
12
|
+
@@Timezones = nil
|
13
|
+
@@TimezoneCountries = nil
|
14
|
+
@@Metazones = nil
|
15
|
+
@@WindowsZones = nil
|
16
|
+
@@WindowsTimezones = nil
|
17
|
+
@@WindowsOffsets = nil
|
18
|
+
@@RailsZones = nil
|
19
|
+
@@RailsTranslated = nil
|
20
|
+
|
21
|
+
public
|
22
|
+
def self.Abbreviations
|
23
|
+
unless @@Abbreviations
|
24
|
+
@@Abbreviations = Marshal.load(File.open(Data::DataDir + 'abbreviations.dat')).insensitive
|
25
|
+
@@Abbreviations.each do |abbr, data|
|
26
|
+
proccessData(data)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
@@Abbreviations
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.Timezones
|
33
|
+
unless @@Timezones
|
34
|
+
@@Timezones = Marshal.load(File.open(Data::DataDir + 'timezones.dat')).insensitive
|
35
|
+
end
|
36
|
+
@@Timezones
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.TimezoneCountries
|
40
|
+
unless @@TimezoneCountries
|
41
|
+
@@TimezoneCountries = Marshal.load(File.open(Data::DataDir + 'countries.dat')).insensitive
|
42
|
+
end
|
43
|
+
@@TimezoneCountries
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.Metazones
|
47
|
+
unless @@Metazones
|
48
|
+
@@Metazones = Marshal.load(File.open(Data::DataDir + 'metazones.dat')).insensitive
|
49
|
+
@@Metazones.each do |zone, data|
|
50
|
+
proccessData(data)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
@@Metazones
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.WindowsZones
|
57
|
+
unless @@WindowsZones
|
58
|
+
@@WindowsZones = Marshal.load(File.open(Data::DataDir + 'windows_zonenames.dat')).insensitive
|
59
|
+
end
|
60
|
+
@@WindowsZones
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.WindowsTimezones
|
64
|
+
unless @@WindowsTimezones
|
65
|
+
@@WindowsTimezones = Marshal.load(File.open(Data::DataDir + 'windows_timezones.dat')).insensitive
|
66
|
+
end
|
67
|
+
@@WindowsTimezones
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.WindowsOffsets
|
71
|
+
unless @@WindowsOffsets
|
72
|
+
@@WindowsOffsets = Marshal.load(File.open(Data::DataDir + 'windows_offsets.dat')).insensitive
|
73
|
+
end
|
74
|
+
@@WindowsOffsets
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.RailsZones
|
78
|
+
unless @@RailsZones
|
79
|
+
@@RailsZones = Marshal.load(File.open(Data::DataDir + 'rails.dat')).insensitive
|
80
|
+
end
|
81
|
+
@@RailsZones
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.RailsTranslated
|
85
|
+
unless @@RailsTranslated
|
86
|
+
@@RailsTranslated = Marshal.load(File.open(Data::DataDir + 'rails_i18n.dat')).insensitive
|
87
|
+
end
|
88
|
+
@@RailsTranslated
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.preload(modules)
|
92
|
+
preloaded = false
|
93
|
+
modules.each do |m|
|
94
|
+
case m
|
95
|
+
when :Abbreviations
|
96
|
+
self.Abbreviations
|
97
|
+
self.Metazones
|
98
|
+
preloaded = true
|
99
|
+
when :Timezones
|
100
|
+
self.Timezones
|
101
|
+
self.Metazones
|
102
|
+
preloaded = true
|
103
|
+
when :WindowsZones
|
104
|
+
self.WindowsZones
|
105
|
+
self.WindowsTimezones
|
106
|
+
self.WindowsOffsets
|
107
|
+
preloaded = true
|
108
|
+
when :RailsZones
|
109
|
+
self.RailsZones
|
110
|
+
self.RailsTranslated
|
111
|
+
preloaded = true
|
112
|
+
end
|
113
|
+
end
|
114
|
+
preloaded
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.getTimezones(metazone, toTime, fromTime, regions = [])
|
118
|
+
timezones = SortedSet.new
|
119
|
+
if self.Metazones.has_key?(metazone)
|
120
|
+
entries = Data::loadEntries(self.Metazones[metazone], toTime, fromTime)
|
121
|
+
entries.each do |entry|
|
122
|
+
add = true
|
123
|
+
timezones += entry['Timezones'].select do |timezone|
|
124
|
+
if regions.empty?
|
125
|
+
true
|
126
|
+
else
|
127
|
+
timezoneRegions = self.TimezoneCountries[timezone]
|
128
|
+
timezoneRegions && !(regions & timezoneRegions).empty?
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
timezones
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.getTimezones2(zone, regions = [])
|
137
|
+
timezones = SortedSet.new
|
138
|
+
if self.WindowsTimezones.has_key?(zone)
|
139
|
+
entries = self.WindowsTimezones[zone]
|
140
|
+
regions = entries.keys if regions.empty?
|
141
|
+
regions.each do |region|
|
142
|
+
next unless entries.has_key?(region)
|
143
|
+
timezones += entries[region]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
timezones
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.getOffsets(zone, types = [])
|
150
|
+
offsets = SortedSet.new
|
151
|
+
if self.WindowsOffsets.has_key?(zone)
|
152
|
+
data = self.WindowsOffsets[zone]
|
153
|
+
types = [:standard, :daylight] if types.empty?
|
154
|
+
types.each do |type|
|
155
|
+
next unless data.has_key?(type)
|
156
|
+
offsets << data[type]
|
157
|
+
end
|
158
|
+
end
|
159
|
+
offsets
|
160
|
+
end
|
161
|
+
|
162
|
+
protected
|
163
|
+
|
164
|
+
def self.proccessData(data)
|
165
|
+
data.each do |entry|
|
166
|
+
entry['From'] = DateTime.parse(entry['From']) if entry['From']
|
167
|
+
entry['To'] = DateTime.parse(entry['To']) if entry['To']
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|