et-orbi 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +48 -0
- data/lib/et-orbi.rb +300 -243
- metadata +14 -17
- data/cases.txt +0 -15
- data/out.txt +0 -2502
- data/out2.txt +0 -2487
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c7c982477f7068d7be62fbb84846f81de496a87
|
4
|
+
data.tar.gz: ec767fc4ce7efd5413d17b5cd90f69f9cc1dc6cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea3c1d4c24633d9820a1e9c58b30e9b0e418c91c9eda5308c20782210c4b041500df882a466e327e6110be1323966e64eaaf291aa12288e87cd96619f88bba91
|
7
|
+
data.tar.gz: ee248987a931f7ec23c58048b45f6970d082046656d790a2eb8c4fccec14ee1c58ff56484fba0e9cd0e18ae51ed452579e7909582de9d51c9e664f63b6fda090
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,12 @@
|
|
2
2
|
# et-orbi CHANGELOG.md
|
3
3
|
|
4
4
|
|
5
|
+
## et-orbi 1.0.2 released 2017-03-24
|
6
|
+
|
7
|
+
- Enhance no zone ArgumentError data
|
8
|
+
- Separate module methods from EoTime methods
|
9
|
+
|
10
|
+
|
5
11
|
## et-orbi 1.0.1 released 2017-03-22
|
6
12
|
|
7
13
|
- Detail Rails and Active Support info in nozone err
|
data/README.md
CHANGED
@@ -6,6 +6,54 @@
|
|
6
6
|
|
7
7
|
Time zones for [fugit](https://github.com/floraison/fugit) and for [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler). Urbi et Orbi.
|
8
8
|
|
9
|
+
`EtOrbi::EoTime` instances quack like Ruby `Time` instances, but their `#zone` returns a `TZInfo::TimeZone` instance.
|
10
|
+
|
11
|
+
Getting `EoTime` instances:
|
12
|
+
```ruby
|
13
|
+
require 'et-orbi'
|
14
|
+
|
15
|
+
EtOrbi.now
|
16
|
+
# => #<EtOrbi::EoTime:0x007f94d94 ...>
|
17
|
+
EtOrbi.parse('2017-12-13 13:00:00 America/Jamaica')
|
18
|
+
# => #<EtOrbi::EoTime:0x007f94d90 @zone=#<TZInfo::DataTimezone: America/Jamaica>...>
|
19
|
+
EtOrbi.make_time(Time.now)
|
20
|
+
# => #<EtOrbi::EoTime:0x007f94d91 ...>
|
21
|
+
|
22
|
+
EtOrbi::EoTime.new(0, 'UTC').to_s
|
23
|
+
# => "1970-01-01 00:00:00 +0000"
|
24
|
+
EtOrbi::EoTime.new(0, 'Europe/Moscow').to_s
|
25
|
+
# => "1970-01-01 03:00:00 +0300"
|
26
|
+
```
|
27
|
+
|
28
|
+
Helper methods:
|
29
|
+
```ruby
|
30
|
+
require 'et-orbi'
|
31
|
+
|
32
|
+
EtOrbi.get_tzone('Europe/Vilnius')
|
33
|
+
# => #<TZInfo::DataTimezone: Europe/Vilnius>
|
34
|
+
EtOrbi.local_tzone
|
35
|
+
# => #<TZInfo::TimezoneProxy: Asia/Tokyo>
|
36
|
+
|
37
|
+
EtOrbi.platform_info
|
38
|
+
# => "(etz:nil,tnz:\"JST\",tzid:nil,rv:\"2.2.6\",rp:\"x86_64-darwin14\",eov:\"1.0.1\",
|
39
|
+
# rorv:nil,astz:nil,debian:nil,centos:nil,osx:\"Asia/Tokyo\")"
|
40
|
+
#
|
41
|
+
# etz: ENV['TZ']
|
42
|
+
# tnz: Time.now.zone
|
43
|
+
# tzid: defined?(TZInfo::Data)
|
44
|
+
# rv: RUBY_VERSION
|
45
|
+
# rp: RUBY_PLATFORM
|
46
|
+
# eov: EtOrbi::VERSION
|
47
|
+
# rorv: Rails::VERSION::STRING
|
48
|
+
# astz: ActiveSupport provided Time.zone
|
49
|
+
```
|
50
|
+
|
51
|
+
### Rails?
|
52
|
+
|
53
|
+
If Rails is present, `Time.zone` is provided and EtOrbi will use it.
|
54
|
+
|
55
|
+
Rails sets its timezone under `config/application.rb`.
|
56
|
+
|
9
57
|
|
10
58
|
## Related projects
|
11
59
|
|
data/lib/et-orbi.rb
CHANGED
@@ -7,270 +7,178 @@ require 'tzinfo'
|
|
7
7
|
|
8
8
|
module EtOrbi
|
9
9
|
|
10
|
-
VERSION = '1.0.
|
10
|
+
VERSION = '1.0.2'
|
11
11
|
|
12
|
-
|
12
|
+
#
|
13
|
+
# module methods
|
13
14
|
|
14
|
-
|
15
|
-
# class methods
|
16
|
-
|
17
|
-
def self.now(zone=nil)
|
15
|
+
def self.now(zone=nil)
|
18
16
|
|
19
|
-
|
20
|
-
|
17
|
+
EoTime.new(Time.now.to_f, zone)
|
18
|
+
end
|
21
19
|
|
22
|
-
|
20
|
+
def self.parse(str, opts={})
|
23
21
|
|
24
|
-
|
25
|
-
|
26
|
-
|
22
|
+
if defined?(::Chronic) && t = ::Chronic.parse(str, opts)
|
23
|
+
return EoTime.new(t, nil)
|
24
|
+
end
|
27
25
|
|
28
|
-
|
29
|
-
|
26
|
+
#rold = RUBY_VERSION < '1.9.0'
|
27
|
+
#rold = RUBY_VERSION < '2.0.0'
|
30
28
|
|
31
29
|
#p [ '---', str ]
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
30
|
+
begin
|
31
|
+
DateTime.parse(str)
|
32
|
+
rescue
|
33
|
+
fail ArgumentError, "no time information in #{str.inspect}"
|
34
|
+
end #if rold
|
35
|
+
#
|
36
|
+
# is necessary since Time.parse('xxx') in Ruby < 1.9 yields `now`
|
39
37
|
|
40
|
-
|
38
|
+
zone = izone = get_tzone(list_iso8601_zones(str).last)
|
41
39
|
|
42
|
-
|
40
|
+
list_olson_zones(str).each { |s| break if zone; zone = get_tzone(s) }
|
43
41
|
|
44
|
-
|
42
|
+
zone ||= local_tzone
|
45
43
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
44
|
+
str = str.sub(zone.name, '') unless zone.name.match(/\A[-+]/)
|
45
|
+
#
|
46
|
+
# for 'Sun Nov 18 16:01:00 Asia/Singapore 2012',
|
47
|
+
# although where does rufus-scheduler have it from?
|
50
48
|
|
51
|
-
|
49
|
+
local = Time.parse(str)
|
52
50
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
51
|
+
secs =
|
52
|
+
if izone
|
53
|
+
local.to_f
|
54
|
+
else
|
55
|
+
zone.period_for_local(local).to_utc(local).to_f
|
56
|
+
end
|
59
57
|
|
60
|
-
|
61
|
-
|
58
|
+
EoTime.new(secs, zone)
|
59
|
+
end
|
62
60
|
|
63
|
-
|
61
|
+
def self.make_time(o)
|
62
|
+
|
63
|
+
ot =
|
64
|
+
case o
|
65
|
+
when Time
|
66
|
+
time_to_eo_time(
|
67
|
+
o)
|
68
|
+
when Date
|
69
|
+
time_to_eo_time(
|
70
|
+
o.respond_to?(:to_time) ?
|
71
|
+
o.to_time :
|
72
|
+
Time.parse(o.strftime('%Y-%m-%d %H:%M:%S')))
|
73
|
+
when String
|
74
|
+
#Rufus::Scheduler.parse_in(o, :no_error => true) || self.parse(o)
|
75
|
+
parse(o)
|
76
|
+
else
|
77
|
+
o
|
78
|
+
end
|
64
79
|
|
65
|
-
|
66
|
-
get_tzone(t.zone) ||
|
67
|
-
(
|
68
|
-
local_tzone.period_for_local(t).abbreviation.to_s == t.zone &&
|
69
|
-
local_tzone
|
70
|
-
) ||
|
71
|
-
t.zone
|
72
|
-
|
73
|
-
EoTime.new(t.to_f, z)
|
74
|
-
end
|
80
|
+
ot = EoTime.new(Time.now.to_f + ot, nil) if ot.is_a?(Numeric)
|
75
81
|
|
76
|
-
|
82
|
+
fail ArgumentError.new(
|
83
|
+
"cannot turn #{o.inspect} to a EoTime instance"
|
84
|
+
) unless ot.is_a?(EoTime)
|
77
85
|
|
78
|
-
|
79
|
-
|
80
|
-
when Time
|
81
|
-
time_to_eo_time(
|
82
|
-
o)
|
83
|
-
when Date
|
84
|
-
time_to_eo_time(
|
85
|
-
o.respond_to?(:to_time) ?
|
86
|
-
o.to_time :
|
87
|
-
Time.parse(o.strftime('%Y-%m-%d %H:%M:%S')))
|
88
|
-
when String
|
89
|
-
#Rufus::Scheduler.parse_in(o, :no_error => true) || self.parse(o)
|
90
|
-
parse(o)
|
91
|
-
else
|
92
|
-
o
|
93
|
-
end
|
86
|
+
ot
|
87
|
+
end
|
94
88
|
|
95
|
-
|
89
|
+
def self.get_tzone(o)
|
96
90
|
|
97
|
-
|
98
|
-
|
99
|
-
|
91
|
+
#p [ :gtz, o ]
|
92
|
+
return nil if o == nil
|
93
|
+
return local_tzone if o == :local
|
94
|
+
return o if o.is_a?(::TZInfo::Timezone)
|
95
|
+
return ::TZInfo::Timezone.get('Zulu') if o == 'Z'
|
100
96
|
|
101
|
-
|
102
|
-
end
|
97
|
+
o = to_offset(o) if o.is_a?(Numeric)
|
103
98
|
|
104
|
-
|
99
|
+
return nil unless o.is_a?(String)
|
105
100
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
end
|
111
|
-
|
112
|
-
def self.get_tzone(o)
|
101
|
+
(@custom_tz_cache ||= {})[o] ||
|
102
|
+
get_offset_tzone(o) ||
|
103
|
+
(::TZInfo::Timezone.get(o) rescue nil)
|
104
|
+
end
|
113
105
|
|
114
|
-
|
115
|
-
return nil if o == nil
|
116
|
-
return local_tzone if o == :local
|
117
|
-
return o if o.is_a?(::TZInfo::Timezone)
|
118
|
-
return ::TZInfo::Timezone.get('Zulu') if o == 'Z'
|
106
|
+
def self.local_tzone
|
119
107
|
|
120
|
-
|
108
|
+
@local_tzone = nil \
|
109
|
+
if @local_tzone_loaded_at && (Time.now > @local_tzone_loaded_at + 1800)
|
110
|
+
@local_tzone = nil \
|
111
|
+
if @local_tzone_tz != ENV['TZ']
|
121
112
|
|
122
|
-
|
113
|
+
@local_tzone ||=
|
114
|
+
begin
|
115
|
+
@local_tzone_tz = ENV['TZ']
|
116
|
+
@local_tzone_loaded_at = Time.now
|
117
|
+
determine_local_tzone
|
118
|
+
end
|
119
|
+
end
|
123
120
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
121
|
+
def self.platform_info
|
122
|
+
|
123
|
+
etos = Proc.new { |k, v| "#{k}:#{v.inspect}" }
|
124
|
+
|
125
|
+
'(' +
|
126
|
+
{
|
127
|
+
'etz' => ENV['TZ'],
|
128
|
+
'tnz' => Time.now.zone,
|
129
|
+
'tzid' => defined?(TZInfo::Data),
|
130
|
+
'rv' => RUBY_VERSION,
|
131
|
+
'rp' => RUBY_PLATFORM,
|
132
|
+
'eov' => EtOrbi::VERSION,
|
133
|
+
'rorv' => (Rails::VERSION::STRING rescue nil),
|
134
|
+
'astz' => Time.respond_to?(:zone) ? Time.zone.name : nil,
|
135
|
+
# Active Support Time.zone
|
136
|
+
}.collect(&etos).join(',') + ',' +
|
137
|
+
gather_tzs.collect(&etos).join(',') +
|
138
|
+
')'
|
139
|
+
end
|
128
140
|
|
129
|
-
|
141
|
+
class << self
|
130
142
|
|
131
|
-
|
143
|
+
alias make make_time
|
144
|
+
end
|
132
145
|
|
133
|
-
|
134
|
-
|
146
|
+
#
|
147
|
+
# our EoTime class (which quacks like a ::Time)
|
135
148
|
|
136
|
-
|
137
|
-
mn = m[2].to_i
|
149
|
+
class EoTime
|
138
150
|
|
139
|
-
|
140
|
-
|
141
|
-
mn = -mn if hr && hr < 0
|
151
|
+
#
|
152
|
+
# class methods
|
142
153
|
|
143
|
-
|
144
|
-
@custom_tz_cache[str] =
|
145
|
-
begin
|
146
|
-
tzi = TZInfo::TransitionDataTimezoneInfo.new(str)
|
147
|
-
tzi.offset(str, hr * 3600 + mn * 60, 0, str)
|
148
|
-
tzi.create_timezone
|
149
|
-
end
|
150
|
-
) if hr
|
154
|
+
def self.now(zone=nil)
|
151
155
|
|
152
|
-
|
156
|
+
EtOrbi.now(zone)
|
153
157
|
end
|
154
158
|
|
155
|
-
def self.
|
156
|
-
|
157
|
-
@local_tzone = nil \
|
158
|
-
if @local_tzone_loaded_at && (Time.now > @local_tzone_loaded_at + 1800)
|
159
|
-
@local_tzone = nil \
|
160
|
-
if @local_tzone_tz != ENV['TZ']
|
159
|
+
def self.parse(str, opts={})
|
161
160
|
|
162
|
-
|
163
|
-
begin
|
164
|
-
@local_tzone_tz = ENV['TZ']
|
165
|
-
@local_tzone_loaded_at = Time.now
|
166
|
-
determine_local_tzone
|
167
|
-
end
|
161
|
+
EtOrbi.parse(str, opts)
|
168
162
|
end
|
169
163
|
|
170
|
-
def self.
|
171
|
-
|
172
|
-
etz = ENV['TZ']
|
173
|
-
|
174
|
-
tz = ::TZInfo::Timezone.get(etz) rescue nil
|
175
|
-
return tz if tz
|
176
|
-
|
177
|
-
tz = Time.zone.tzinfo \
|
178
|
-
if Time.respond_to?(:zone) && Time.zone.respond_to?(:tzinfo)
|
179
|
-
return tz if tz
|
180
|
-
|
181
|
-
tzs = determine_local_tzones
|
164
|
+
def self.get_tzone(o)
|
182
165
|
|
183
|
-
(
|
166
|
+
EtOrbi.get_tzone(o)
|
184
167
|
end
|
185
168
|
|
186
|
-
def self.
|
187
|
-
|
188
|
-
tabbs = (-6..5)
|
189
|
-
.collect { |i| (Time.now + i * 30 * 24 * 3600).zone }
|
190
|
-
.uniq
|
191
|
-
.sort
|
192
|
-
|
193
|
-
t = Time.now
|
194
|
-
tu = t.dup.utc # /!\ dup is necessary, #utc modifies its target
|
195
|
-
|
196
|
-
twin = Time.utc(t.year, 1, 1) # winter
|
197
|
-
tsum = Time.utc(t.year, 7, 1) # summer
|
198
|
-
|
199
|
-
::TZInfo::Timezone.all.select do |tz|
|
200
|
-
|
201
|
-
pabbs =
|
202
|
-
[
|
203
|
-
tz.period_for_utc(twin).abbreviation.to_s,
|
204
|
-
tz.period_for_utc(tsum).abbreviation.to_s
|
205
|
-
].uniq.sort
|
206
|
-
|
207
|
-
pabbs == tabbs
|
208
|
-
end
|
209
|
-
end
|
169
|
+
def self.local_tzone
|
210
170
|
|
211
|
-
|
212
|
-
# Postel's law applies
|
213
|
-
#
|
214
|
-
def self.list_iso8601_zones(s)
|
215
|
-
|
216
|
-
s.scan(
|
217
|
-
%r{
|
218
|
-
(?<=:\d\d)
|
219
|
-
\s*
|
220
|
-
(?:
|
221
|
-
[-+]
|
222
|
-
(?:[0-1][0-9]|2[0-4])
|
223
|
-
(?:(?::)?(?:[0-5][0-9]|60))?
|
224
|
-
(?![-+])
|
225
|
-
|
|
226
|
-
Z
|
227
|
-
)
|
228
|
-
}x
|
229
|
-
).collect(&:strip)
|
171
|
+
EtOrbi.local_tzone
|
230
172
|
end
|
231
173
|
|
232
|
-
def self.
|
174
|
+
def self.platform_info
|
233
175
|
|
234
|
-
|
235
|
-
%r{
|
236
|
-
(?<=\s|\A)
|
237
|
-
(?:[A-Za-z][A-Za-z0-9+_-]+)
|
238
|
-
(?:\/(?:[A-Za-z][A-Za-z0-9+_-]+)){0,2}
|
239
|
-
}x)
|
176
|
+
EtOrbi.platform_info
|
240
177
|
end
|
241
178
|
|
242
|
-
|
243
|
-
#
|
244
|
-
# current_timezone = ENV['TZ']
|
245
|
-
# ENV['TZ'] = @zone
|
246
|
-
#
|
247
|
-
# block.call
|
248
|
-
#
|
249
|
-
#ensure
|
250
|
-
#
|
251
|
-
# ENV['TZ'] = current_timezone
|
252
|
-
#end
|
253
|
-
#
|
254
|
-
# kept around as a (thread-unsafe) relic
|
255
|
-
|
256
|
-
def self.platform_info
|
179
|
+
def self.make(o)
|
257
180
|
|
258
|
-
|
259
|
-
|
260
|
-
'(' +
|
261
|
-
{
|
262
|
-
'etz' => ENV['TZ'],
|
263
|
-
'tnz' => Time.now.zone,
|
264
|
-
'tzid' => defined?(TZInfo::Data),
|
265
|
-
'rv' => RUBY_VERSION,
|
266
|
-
'rp' => RUBY_PLATFORM,
|
267
|
-
'eov' => EtOrbi::VERSION,
|
268
|
-
'rorv' => (Rails::VERSION::STRING rescue nil),
|
269
|
-
'astz' => Time.respond_to?(:zone) ? Time.zone.name : nil,
|
270
|
-
# Active Support Time.zone
|
271
|
-
}.collect(&etos).join(',') + ',' +
|
272
|
-
gather_tzs.collect(&etos).join(',') +
|
273
|
-
')'
|
181
|
+
EtOrbi.make_time(o)
|
274
182
|
end
|
275
183
|
|
276
184
|
#
|
@@ -286,7 +194,8 @@ module EtOrbi
|
|
286
194
|
|
287
195
|
fail ArgumentError.new(
|
288
196
|
"cannot determine timezone from #{zone.inspect}" +
|
289
|
-
"\n#{
|
197
|
+
"\n#{render_nozone_time(s)}" +
|
198
|
+
"\n#{self.class.platform_info.sub(',debian:', ",\ndebian:")}" +
|
290
199
|
"\nTry setting `ENV['TZ'] = 'Continent/City'` in your script " +
|
291
200
|
"(see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)" +
|
292
201
|
(defined?(TZInfo::Data) ? '' : "\nand adding gem 'tzinfo-data'")
|
@@ -446,8 +355,20 @@ module EtOrbi
|
|
446
355
|
strftime("%H:%M:%S.#{'%06d' % usec}")
|
447
356
|
end
|
448
357
|
|
449
|
-
|
450
|
-
|
358
|
+
protected
|
359
|
+
|
360
|
+
def render_nozone_time(seconds)
|
361
|
+
|
362
|
+
t =
|
363
|
+
Time.utc(0) + seconds
|
364
|
+
ts =
|
365
|
+
t.strftime('%Y-%m-%d %H:%M:%S') +
|
366
|
+
".#{(seconds % 1).to_s.split('.').last}"
|
367
|
+
z =
|
368
|
+
EtOrbi.local_tzone.period_for_local(t).abbreviation.to_s
|
369
|
+
|
370
|
+
"(secs:#{seconds},utc~:#{ts.inspect},zo~:#{z.inspect})"
|
371
|
+
end
|
451
372
|
|
452
373
|
def strfz(code)
|
453
374
|
|
@@ -498,48 +419,184 @@ module EtOrbi
|
|
498
419
|
|
499
420
|
o.to_f
|
500
421
|
end
|
422
|
+
end
|
501
423
|
|
502
|
-
|
503
|
-
|
424
|
+
#
|
425
|
+
# not so public module methods
|
426
|
+
|
427
|
+
def self.time_to_eo_time(t)
|
428
|
+
|
429
|
+
z =
|
430
|
+
get_tzone(t.zone) ||
|
431
|
+
(
|
432
|
+
local_tzone.period_for_local(t).abbreviation.to_s == t.zone &&
|
433
|
+
local_tzone
|
434
|
+
) ||
|
435
|
+
t.zone
|
436
|
+
|
437
|
+
EoTime.new(t.to_f, z)
|
438
|
+
end
|
504
439
|
|
505
|
-
|
440
|
+
def self.to_offset(n)
|
506
441
|
|
507
|
-
|
442
|
+
i = n.to_i
|
443
|
+
sn = i < 0 ? '-' : '+'; i = i.abs
|
444
|
+
hr = i / 3600; mn = i % 3600; sc = i % 60
|
445
|
+
(sc > 0 ? "%s%02d:%02d:%02d" : "%s%02d:%02d") % [ sn, hr, mn, sc ]
|
446
|
+
end
|
447
|
+
|
448
|
+
def self.get_offset_tzone(str)
|
508
449
|
|
509
|
-
|
510
|
-
rescue; nil; end
|
450
|
+
# custom timezones, no DST, just an offset, like "+08:00" or "-01:30"
|
511
451
|
|
512
|
-
|
452
|
+
m = str.match(/\A([+-][0-1][0-9]):?([0-5][0-9])?\z/)
|
453
|
+
return nil unless m
|
513
454
|
|
514
|
-
|
455
|
+
hr = m[1].to_i
|
456
|
+
mn = m[2].to_i
|
515
457
|
|
516
|
-
|
517
|
-
|
518
|
-
|
458
|
+
hr = nil if hr.abs > 11
|
459
|
+
hr = nil if mn > 59
|
460
|
+
mn = -mn if hr && hr < 0
|
461
|
+
|
462
|
+
return (
|
463
|
+
@custom_tz_cache[str] =
|
464
|
+
begin
|
465
|
+
tzi = TZInfo::TransitionDataTimezoneInfo.new(str)
|
466
|
+
tzi.offset(str, hr * 3600 + mn * 60, 0, str)
|
467
|
+
tzi.create_timezone
|
519
468
|
end
|
520
|
-
|
469
|
+
) if hr
|
521
470
|
|
522
|
-
|
523
|
-
|
471
|
+
nil
|
472
|
+
end
|
524
473
|
|
525
|
-
|
474
|
+
def self.determine_local_tzone
|
526
475
|
|
527
|
-
|
476
|
+
etz = ENV['TZ']
|
528
477
|
|
529
|
-
|
530
|
-
|
531
|
-
nil
|
532
|
-
rescue; nil; end
|
478
|
+
tz = ::TZInfo::Timezone.get(etz) rescue nil
|
479
|
+
return tz if tz
|
533
480
|
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
481
|
+
tz = Time.zone.tzinfo \
|
482
|
+
if Time.respond_to?(:zone) && Time.zone.respond_to?(:tzinfo)
|
483
|
+
return tz if tz
|
484
|
+
|
485
|
+
tzs = determine_local_tzones
|
538
486
|
|
539
|
-
|
487
|
+
(etz && tzs.find { |z| z.name == etz }) || tzs.first
|
488
|
+
end
|
489
|
+
|
490
|
+
def self.determine_local_tzones
|
491
|
+
|
492
|
+
tabbs = (-6..5)
|
493
|
+
.collect { |i| (Time.now + i * 30 * 24 * 3600).zone }
|
494
|
+
.uniq
|
495
|
+
.sort
|
496
|
+
|
497
|
+
t = Time.now
|
498
|
+
tu = t.dup.utc # /!\ dup is necessary, #utc modifies its target
|
540
499
|
|
541
|
-
|
500
|
+
twin = Time.utc(t.year, 1, 1) # winter
|
501
|
+
tsum = Time.utc(t.year, 7, 1) # summer
|
502
|
+
|
503
|
+
::TZInfo::Timezone.all.select do |tz|
|
504
|
+
|
505
|
+
pabbs =
|
506
|
+
[
|
507
|
+
tz.period_for_utc(twin).abbreviation.to_s,
|
508
|
+
tz.period_for_utc(tsum).abbreviation.to_s
|
509
|
+
].uniq.sort
|
510
|
+
|
511
|
+
pabbs == tabbs
|
542
512
|
end
|
543
513
|
end
|
514
|
+
|
515
|
+
# https://en.wikipedia.org/wiki/ISO_8601
|
516
|
+
# Postel's law applies
|
517
|
+
#
|
518
|
+
def self.list_iso8601_zones(s)
|
519
|
+
|
520
|
+
s.scan(
|
521
|
+
%r{
|
522
|
+
(?<=:\d\d)
|
523
|
+
\s*
|
524
|
+
(?:
|
525
|
+
[-+]
|
526
|
+
(?:[0-1][0-9]|2[0-4])
|
527
|
+
(?:(?::)?(?:[0-5][0-9]|60))?
|
528
|
+
(?![-+])
|
529
|
+
|
|
530
|
+
Z
|
531
|
+
)
|
532
|
+
}x
|
533
|
+
).collect(&:strip)
|
534
|
+
end
|
535
|
+
|
536
|
+
def self.list_olson_zones(s)
|
537
|
+
|
538
|
+
s.scan(
|
539
|
+
%r{
|
540
|
+
(?<=\s|\A)
|
541
|
+
(?:[A-Za-z][A-Za-z0-9+_-]+)
|
542
|
+
(?:\/(?:[A-Za-z][A-Za-z0-9+_-]+)){0,2}
|
543
|
+
}x)
|
544
|
+
end
|
545
|
+
|
546
|
+
#def in_zone(&block)
|
547
|
+
#
|
548
|
+
# current_timezone = ENV['TZ']
|
549
|
+
# ENV['TZ'] = @zone
|
550
|
+
#
|
551
|
+
# block.call
|
552
|
+
#
|
553
|
+
#ensure
|
554
|
+
#
|
555
|
+
# ENV['TZ'] = current_timezone
|
556
|
+
#end
|
557
|
+
#
|
558
|
+
# kept around as a (thread-unsafe) relic
|
559
|
+
|
560
|
+
#
|
561
|
+
# system tz determination
|
562
|
+
|
563
|
+
def self.debian_tz
|
564
|
+
|
565
|
+
path = '/etc/timezone'
|
566
|
+
|
567
|
+
File.exist?(path) ? File.read(path).strip : nil
|
568
|
+
rescue; nil; end
|
569
|
+
|
570
|
+
def self.centos_tz
|
571
|
+
|
572
|
+
path = '/etc/sysconfig/clock'
|
573
|
+
|
574
|
+
File.open(path, 'rb') do |f|
|
575
|
+
until f.eof?
|
576
|
+
if m = f.readline.match(/ZONE="([^"]+)"/); return m[1]; end
|
577
|
+
end
|
578
|
+
end if File.exist?(path)
|
579
|
+
|
580
|
+
nil
|
581
|
+
rescue; nil; end
|
582
|
+
|
583
|
+
def self.osx_tz
|
584
|
+
|
585
|
+
path = '/etc/localtime'
|
586
|
+
|
587
|
+
File.symlink?(path) ?
|
588
|
+
File.readlink(path).split('/')[4..-1].join('/') :
|
589
|
+
nil
|
590
|
+
rescue; nil; end
|
591
|
+
|
592
|
+
# def self.find_tz
|
593
|
+
#
|
594
|
+
# debian_tz || centos_tz || osx_tz
|
595
|
+
# end
|
596
|
+
|
597
|
+
def self.gather_tzs
|
598
|
+
|
599
|
+
{ :debian => debian_tz, :centos => centos_tz, :osx => osx_tz }
|
600
|
+
end
|
544
601
|
end
|
545
602
|
|