et-orbi 1.0.1 → 1.0.2
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.
- 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
|
|