rufus-scheduler 3.2.0 → 3.3.0
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 +7 -0
- data/CHANGELOG.txt +24 -0
- data/CREDITS.txt +12 -0
- data/LICENSE.txt +1 -1
- data/Makefile +23 -0
- data/README.md +65 -20
- data/fail18.txt +12 -0
- data/lib/rufus/scheduler/cronline.rb +113 -88
- data/lib/rufus/scheduler/job_array.rb +8 -4
- data/lib/rufus/scheduler/jobs.rb +56 -35
- data/lib/rufus/scheduler/locks.rb +2 -2
- data/lib/rufus/scheduler/util.rb +33 -48
- data/lib/rufus/scheduler/zotime.rb +348 -66
- data/lib/rufus/scheduler.rb +19 -10
- data/pics.txt +15 -0
- data/rufus-scheduler.gemspec +2 -4
- metadata +25 -48
- data/Rakefile +0 -83
- data/lib/rufus/scheduler/zones.rb +0 -175
data/lib/rufus/scheduler/util.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#--
|
|
2
|
-
# Copyright (c) 2006-
|
|
2
|
+
# Copyright (c) 2006-2016, John Mettraux, jmettraux@gmail.com
|
|
3
3
|
#
|
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
5
|
# of this software and associated documentation files (the "Software"), to deal
|
|
@@ -38,27 +38,27 @@ module Rufus
|
|
|
38
38
|
parse_cron(o, opts) ||
|
|
39
39
|
parse_in(o, opts) || # covers 'every' schedule strings
|
|
40
40
|
parse_at(o, opts) ||
|
|
41
|
-
fail(ArgumentError.new("couldn't parse
|
|
41
|
+
fail(ArgumentError.new("couldn't parse #{o.inspect} (#{o.class})"))
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
def self.
|
|
45
|
-
|
|
46
|
-
o.is_a?(String) ? parse_duration(o, opts) : o
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def self.parse_at(o, opts={})
|
|
44
|
+
def self.parse_cron(o, opts)
|
|
50
45
|
|
|
51
|
-
|
|
46
|
+
CronLine.new(o)
|
|
52
47
|
|
|
53
|
-
rescue
|
|
48
|
+
rescue ArgumentError => ae
|
|
54
49
|
|
|
55
50
|
return nil if opts[:no_error]
|
|
56
|
-
fail
|
|
51
|
+
fail ae
|
|
57
52
|
end
|
|
58
53
|
|
|
59
|
-
def self.
|
|
54
|
+
def self.parse_in(o, opts={})
|
|
60
55
|
|
|
61
|
-
|
|
56
|
+
#o.is_a?(String) ? parse_duration(o, opts) : o
|
|
57
|
+
|
|
58
|
+
return parse_duration(o, opts) if o.is_a?(String)
|
|
59
|
+
return o if o.is_a?(Numeric)
|
|
60
|
+
|
|
61
|
+
fail ArgumentError.new("couldn't parse time point in #{o.inspect}")
|
|
62
62
|
|
|
63
63
|
rescue ArgumentError => ae
|
|
64
64
|
|
|
@@ -66,17 +66,16 @@ module Rufus
|
|
|
66
66
|
fail ae
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
-
def self.
|
|
69
|
+
def self.parse_at(o, opts={})
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
return o if o.is_a?(Rufus::Scheduler::ZoTime)
|
|
72
|
+
return Rufus::Scheduler::ZoTime.make(o) if o.is_a?(Time)
|
|
73
|
+
Rufus::Scheduler::ZoTime.parse(o, opts)
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
"cannot turn #{o.inspect} to a point in time, doesn't make sense"
|
|
77
|
-
) unless t.is_a?(Time)
|
|
75
|
+
rescue StandardError => se
|
|
78
76
|
|
|
79
|
-
|
|
77
|
+
return nil if opts[:no_error]
|
|
78
|
+
fail se
|
|
80
79
|
end
|
|
81
80
|
|
|
82
81
|
DURATIONS2M = [
|
|
@@ -125,38 +124,24 @@ module Rufus
|
|
|
125
124
|
#
|
|
126
125
|
def self.parse_duration(string, opts={})
|
|
127
126
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
s = string.to_s.strip
|
|
128
|
+
mod = s[0, 1] == '-' ? -1 : 1
|
|
129
|
+
s = s[1..-1] if mod == -1
|
|
131
130
|
|
|
132
|
-
|
|
131
|
+
ss = mod < 0 ? '-' : ''
|
|
132
|
+
r = 0.0
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
val = 0.0
|
|
139
|
-
|
|
140
|
-
s = m[2]
|
|
134
|
+
s.scan(/(\d*\.\d+|\d+\.?)([#{DURATION_LETTERS}]?)/) do |f, d|
|
|
135
|
+
ss += "#{f}#{d}"
|
|
136
|
+
r += f.to_f * (DURATIONS[d] || 1.0)
|
|
137
|
+
end
|
|
141
138
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
val += m[1].to_f * DURATIONS[m[2]]
|
|
146
|
-
elsif s.match(/^\d+$/)
|
|
147
|
-
val += s.to_i
|
|
148
|
-
elsif s.match(/^\d*\.\d*$/)
|
|
149
|
-
val += s.to_f
|
|
150
|
-
elsif opts[:no_error]
|
|
151
|
-
return nil
|
|
152
|
-
else
|
|
153
|
-
fail ArgumentError.new("cannot parse '#{string}' (especially '#{s}')")
|
|
154
|
-
end
|
|
155
|
-
break unless m && m[3]
|
|
156
|
-
s = m[3]
|
|
139
|
+
if ss == '-' || ss != string.to_s.strip
|
|
140
|
+
return nil if opts[:no_error]
|
|
141
|
+
fail ArgumentError.new("invalid time duration #{string.inspect}")
|
|
157
142
|
end
|
|
158
143
|
|
|
159
|
-
mod *
|
|
144
|
+
mod * r
|
|
160
145
|
end
|
|
161
146
|
|
|
162
147
|
class << self
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#--
|
|
2
|
-
# Copyright (c) 2006-
|
|
2
|
+
# Copyright (c) 2006-2016, John Mettraux, jmettraux@gmail.com
|
|
3
3
|
#
|
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
5
|
# of this software and associated documentation files (the "Software"), to deal
|
|
@@ -22,8 +22,6 @@
|
|
|
22
22
|
# Made in Japan.
|
|
23
23
|
#++
|
|
24
24
|
|
|
25
|
-
require 'rufus/scheduler/zones'
|
|
26
|
-
|
|
27
25
|
|
|
28
26
|
class Rufus::Scheduler
|
|
29
27
|
|
|
@@ -32,52 +30,72 @@ class Rufus::Scheduler
|
|
|
32
30
|
#
|
|
33
31
|
class ZoTime
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
attr_reader :seconds
|
|
34
|
+
attr_reader :zone
|
|
37
35
|
|
|
38
36
|
def initialize(s, zone)
|
|
39
37
|
|
|
40
38
|
@seconds = s.to_f
|
|
41
|
-
@zone = zone
|
|
42
|
-
end
|
|
39
|
+
@zone = self.class.get_tzone(zone || :current)
|
|
43
40
|
|
|
44
|
-
|
|
41
|
+
fail ArgumentError.new(
|
|
42
|
+
"cannot determine timezone from #{zone.inspect}"
|
|
43
|
+
) unless @zone
|
|
45
44
|
|
|
46
|
-
|
|
45
|
+
@time = nil # cache for #to_time result
|
|
46
|
+
end
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
def seconds=(f)
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
# # ambiguous TZ (getting out of DST)
|
|
54
|
-
#else
|
|
55
|
-
# t.hour # force t to compute itself
|
|
56
|
-
#end
|
|
57
|
-
#
|
|
58
|
-
# jump out of DST as soon as possible, jumps 1h as seen from UTC
|
|
50
|
+
@time = nil
|
|
51
|
+
@seconds = f
|
|
52
|
+
end
|
|
59
53
|
|
|
60
|
-
|
|
61
|
-
#
|
|
62
|
-
# stay in DST as long as possible, no jump seen from UTC
|
|
54
|
+
def zone=(z)
|
|
63
55
|
|
|
64
|
-
|
|
65
|
-
|
|
56
|
+
@time = nil
|
|
57
|
+
@zone = self.class.get_tzone(zone || :current)
|
|
66
58
|
end
|
|
67
59
|
|
|
68
60
|
def utc
|
|
69
61
|
|
|
70
|
-
|
|
62
|
+
Time.utc(1970, 1, 1) + @seconds
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Returns a Ruby Time instance.
|
|
66
|
+
#
|
|
67
|
+
# Warning: the timezone of that Time instance will be UTC.
|
|
68
|
+
#
|
|
69
|
+
def to_time
|
|
70
|
+
|
|
71
|
+
@time ||= begin; u = utc; @zone.period_for_utc(u).to_local(u); end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
%w[
|
|
75
|
+
year month day wday hour min sec usec asctime
|
|
76
|
+
].each do |m|
|
|
77
|
+
define_method(m) { to_time.send(m) }
|
|
71
78
|
end
|
|
79
|
+
def iso8601(fraction_digits=0); to_time.iso8601(fraction_digits); end
|
|
72
80
|
|
|
73
|
-
def
|
|
81
|
+
def ==(o)
|
|
74
82
|
|
|
75
|
-
@seconds
|
|
83
|
+
o.is_a?(ZoTime) && o.seconds == @seconds && o.zone == @zone
|
|
76
84
|
end
|
|
85
|
+
#alias eq? == # FIXME see Object#== (ri)
|
|
86
|
+
|
|
87
|
+
def >(o); @seconds > _to_f(o); end
|
|
88
|
+
def >=(o); @seconds >= _to_f(o); end
|
|
89
|
+
def <(o); @seconds < _to_f(o); end
|
|
90
|
+
def <=(o); @seconds <= _to_f(o); end
|
|
91
|
+
def <=>(o); @seconds <=> _to_f(o); end
|
|
92
|
+
|
|
93
|
+
alias getutc utc
|
|
94
|
+
alias getgm utc
|
|
77
95
|
|
|
78
|
-
def
|
|
96
|
+
def to_i
|
|
79
97
|
|
|
80
|
-
@seconds
|
|
98
|
+
@seconds.to_i
|
|
81
99
|
end
|
|
82
100
|
|
|
83
101
|
def to_f
|
|
@@ -85,82 +103,346 @@ class Rufus::Scheduler
|
|
|
85
103
|
@seconds
|
|
86
104
|
end
|
|
87
105
|
|
|
88
|
-
|
|
106
|
+
def is_dst?
|
|
107
|
+
|
|
108
|
+
@zone.period_for_utc(utc).std_offset != 0
|
|
109
|
+
end
|
|
110
|
+
alias isdst is_dst?
|
|
111
|
+
|
|
112
|
+
def utc_offset
|
|
113
|
+
|
|
114
|
+
#@zone.period_for_utc(utc).utc_offset
|
|
115
|
+
#@zone.period_for_utc(utc).utc_total_offset
|
|
116
|
+
#@zone.period_for_utc(utc).std_offset
|
|
117
|
+
@zone.period_for_utc(utc).utc_offset
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def strftime(format)
|
|
121
|
+
|
|
122
|
+
format = format.gsub(/%(\/?Z|:{0,2}z)/) { |f| strfz(f) }
|
|
123
|
+
|
|
124
|
+
to_time.strftime(format)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def add(t); @time = nil; @seconds += t.to_f; end
|
|
128
|
+
def substract(t); @time = nil; @seconds -= t.to_f; end
|
|
129
|
+
|
|
130
|
+
def +(t); inc(t, 1); end
|
|
131
|
+
def -(t); inc(t, -1); end
|
|
132
|
+
|
|
133
|
+
WEEK_S = 7 * 24 * 3600
|
|
134
|
+
|
|
135
|
+
def monthdays
|
|
136
|
+
|
|
137
|
+
date = to_time
|
|
138
|
+
|
|
139
|
+
pos = 1
|
|
140
|
+
d = self.dup
|
|
141
|
+
|
|
142
|
+
loop do
|
|
143
|
+
d.add(-WEEK_S)
|
|
144
|
+
break if d.month != date.month
|
|
145
|
+
pos = pos + 1
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
neg = -1
|
|
149
|
+
d = self.dup
|
|
150
|
+
|
|
151
|
+
loop do
|
|
152
|
+
d.add(WEEK_S)
|
|
153
|
+
break if d.month != date.month
|
|
154
|
+
neg = neg - 1
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
[ "#{date.wday}##{pos}", "#{date.wday}##{neg}" ]
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def to_s
|
|
161
|
+
|
|
162
|
+
strftime('%Y-%m-%d %H:%M:%S %z')
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def to_debug_s
|
|
166
|
+
|
|
167
|
+
uo = self.utc_offset
|
|
168
|
+
uos = uo < 0 ? '-' : '+'
|
|
169
|
+
uo = uo.abs
|
|
170
|
+
uoh, uom = [ uo / 3600, uo % 3600 ]
|
|
171
|
+
|
|
172
|
+
[
|
|
173
|
+
'zt',
|
|
174
|
+
self.strftime('%Y-%m-%d %H:%M:%S'),
|
|
175
|
+
"%s%02d:%02d" % [ uos, uoh, uom ],
|
|
176
|
+
"dst:#{self.isdst}"
|
|
177
|
+
].join(' ')
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Debug current time by showing local time / delta / utc time
|
|
181
|
+
# for example: "0120-7(0820)"
|
|
182
|
+
#
|
|
183
|
+
def to_utc_comparison_s
|
|
184
|
+
|
|
185
|
+
per = @zone.period_for_utc(utc)
|
|
186
|
+
off = per.utc_total_offset
|
|
187
|
+
|
|
188
|
+
off = off / 3600
|
|
189
|
+
off = off >= 0 ? "+#{off}" : off.to_s
|
|
190
|
+
|
|
191
|
+
strftime('%H%M') + off + utc.strftime('(%H%M)')
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def self.now(zone=nil)
|
|
195
|
+
|
|
196
|
+
ZoTime.new(Time.now.to_f, zone)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# https://en.wikipedia.org/wiki/ISO_8601
|
|
200
|
+
# Postel's law applies
|
|
201
|
+
#
|
|
202
|
+
def self.extract_iso8601_zone(s)
|
|
203
|
+
|
|
204
|
+
m = s.match(
|
|
205
|
+
/[0-2]\d(?::?[0-6]\d(?::?[0-6]\d))?\s*([+-]\d\d(?::?\d\d)?)\s*\z/)
|
|
206
|
+
return nil unless m
|
|
207
|
+
|
|
208
|
+
zs = m[1].split(':')
|
|
209
|
+
zs << '00' if zs.length < 2
|
|
89
210
|
|
|
90
|
-
|
|
211
|
+
zh = zs[0].to_i.abs
|
|
91
212
|
|
|
92
|
-
|
|
213
|
+
return nil if zh > 24
|
|
214
|
+
return nil if zh == 24 && zs[1].to_i != 0
|
|
215
|
+
|
|
216
|
+
zs.join(':')
|
|
93
217
|
end
|
|
94
218
|
|
|
95
219
|
def self.parse(str, opts={})
|
|
96
220
|
|
|
97
221
|
if defined?(::Chronic) && t = ::Chronic.parse(str, opts)
|
|
98
|
-
return ZoTime.new(t,
|
|
222
|
+
return ZoTime.new(t, nil)
|
|
99
223
|
end
|
|
100
224
|
|
|
225
|
+
#rold = RUBY_VERSION < '1.9.0'
|
|
226
|
+
#rold = RUBY_VERSION < '2.0.0'
|
|
227
|
+
|
|
101
228
|
begin
|
|
102
229
|
DateTime.parse(str)
|
|
103
230
|
rescue
|
|
104
|
-
fail ArgumentError, "no time information in #{
|
|
105
|
-
end if
|
|
231
|
+
fail ArgumentError, "no time information in #{str.inspect}"
|
|
232
|
+
end #if rold
|
|
233
|
+
#
|
|
234
|
+
# is necessary since Time.parse('xxx') in Ruby < 1.9 yields `now`
|
|
106
235
|
|
|
107
236
|
zone = nil
|
|
108
237
|
|
|
109
238
|
s =
|
|
110
|
-
str.gsub(/\S+/)
|
|
111
|
-
if
|
|
112
|
-
zone ||=
|
|
239
|
+
str.gsub(/\S+/) do |w|
|
|
240
|
+
if z = get_tzone(w)
|
|
241
|
+
zone ||= z
|
|
113
242
|
''
|
|
114
243
|
else
|
|
115
|
-
|
|
244
|
+
w
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
local = Time.parse(s)
|
|
249
|
+
izone = extract_iso8601_zone(s)
|
|
250
|
+
|
|
251
|
+
zone ||=
|
|
252
|
+
if s.match(/\dZ\b/)
|
|
253
|
+
get_tzone('Zulu')
|
|
254
|
+
#elsif rold && izone
|
|
255
|
+
elsif izone
|
|
256
|
+
get_tzone(izone)
|
|
257
|
+
elsif local.zone.nil? && izone
|
|
258
|
+
get_tzone(local.strftime('%:z'))
|
|
259
|
+
else
|
|
260
|
+
get_tzone(:local)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
secs =
|
|
264
|
+
#if rold && izone
|
|
265
|
+
if izone
|
|
266
|
+
local.to_f
|
|
267
|
+
else
|
|
268
|
+
zone.period_for_local(local).to_utc(local).to_f
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
ZoTime.new(secs, zone)
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def self.get_tzone(str)
|
|
275
|
+
|
|
276
|
+
return str if str.is_a?(::TZInfo::Timezone)
|
|
277
|
+
|
|
278
|
+
# discard quickly when it's certainly not a timezone
|
|
279
|
+
|
|
280
|
+
return nil if str == nil
|
|
281
|
+
return nil if str == '*'
|
|
282
|
+
|
|
283
|
+
# ok, it's a timezone then
|
|
284
|
+
|
|
285
|
+
str = Time.now.zone if str == :current || str == :local
|
|
286
|
+
|
|
287
|
+
# utc_offset
|
|
288
|
+
|
|
289
|
+
if str.is_a?(Numeric)
|
|
290
|
+
i = str.to_i
|
|
291
|
+
sn = i < 0 ? '-' : '+'; i = i.abs
|
|
292
|
+
hr = i / 3600; mn = i % 3600; sc = i % 60
|
|
293
|
+
str = (sc > 0 ? "%s%02d:%02d:%02d" : "%s%02d:%02d") % [ sn, hr, mn, sc ]
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
return nil if str.index('#')
|
|
297
|
+
# counters "sun#2", etc... On OSX would go all the way to true
|
|
298
|
+
|
|
299
|
+
# vanilla time zones
|
|
300
|
+
|
|
301
|
+
z = (::TZInfo::Timezone.get(str) rescue nil)
|
|
302
|
+
return z if z
|
|
303
|
+
|
|
304
|
+
# time zone abbreviations
|
|
305
|
+
|
|
306
|
+
if str.match(/\A[A-Z0-9-]{3,6}\z/)
|
|
307
|
+
|
|
308
|
+
twin = Time.utc(Time.now.year, 1, 1)
|
|
309
|
+
tsum = Time.utc(Time.now.year, 7, 1)
|
|
310
|
+
|
|
311
|
+
z =
|
|
312
|
+
::TZInfo::Timezone.all.find do |tz|
|
|
313
|
+
tz.period_for_utc(twin).abbreviation.to_s == str ||
|
|
314
|
+
tz.period_for_utc(tsum).abbreviation.to_s == str
|
|
116
315
|
end
|
|
117
|
-
|
|
316
|
+
return z if z
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
# some time zone aliases
|
|
320
|
+
|
|
321
|
+
return ::TZInfo::Timezone.get('Zulu') if %w[ Z ].include?(str)
|
|
118
322
|
|
|
119
|
-
|
|
323
|
+
# custom timezones, no DST, just an offset, like "+08:00" or "-01:30"
|
|
324
|
+
|
|
325
|
+
tz = (@custom_tz_cache ||= {})[str]
|
|
326
|
+
return tz if tz
|
|
327
|
+
|
|
328
|
+
if m = str.match(/\A([+-][0-1][0-9]):?([0-5][0-9])\z/)
|
|
329
|
+
|
|
330
|
+
hr = m[1].to_i
|
|
331
|
+
mn = m[2].to_i
|
|
332
|
+
|
|
333
|
+
hr = nil if hr.abs > 11
|
|
334
|
+
hr = nil if mn > 59
|
|
335
|
+
mn = -mn if hr && hr < 0
|
|
336
|
+
|
|
337
|
+
return (
|
|
338
|
+
@custom_tz_cache[str] =
|
|
339
|
+
begin
|
|
340
|
+
tzi = TZInfo::TransitionDataTimezoneInfo.new(str)
|
|
341
|
+
tzi.offset(str, hr * 3600 + mn * 60, 0, str)
|
|
342
|
+
tzi.create_timezone
|
|
343
|
+
end
|
|
344
|
+
) if hr
|
|
345
|
+
end
|
|
120
346
|
|
|
121
|
-
|
|
122
|
-
zt.in_zone { zt.seconds = Time.parse(s).to_f }
|
|
347
|
+
# so it's not a timezone.
|
|
123
348
|
|
|
124
|
-
|
|
349
|
+
nil
|
|
125
350
|
end
|
|
126
351
|
|
|
127
|
-
def self.
|
|
352
|
+
def self.local_tzone
|
|
128
353
|
|
|
129
|
-
|
|
130
|
-
|
|
354
|
+
get_tzone(:local)
|
|
355
|
+
end
|
|
131
356
|
|
|
132
|
-
|
|
133
|
-
|
|
357
|
+
def self.make(o)
|
|
358
|
+
|
|
359
|
+
zt =
|
|
360
|
+
case o
|
|
361
|
+
when Time
|
|
362
|
+
ZoTime.new(o.to_f, o.zone)
|
|
363
|
+
when Date
|
|
364
|
+
t =
|
|
365
|
+
o.respond_to?(:to_time) ?
|
|
366
|
+
o.to_time :
|
|
367
|
+
Time.parse(o.strftime('%Y-%m-%d %H:%M:%S'))
|
|
368
|
+
ZoTime.new(t.to_f, t.zone)
|
|
369
|
+
when String
|
|
370
|
+
Rufus::Scheduler.parse_in(o, :no_error => true) || self.parse(o)
|
|
371
|
+
else
|
|
372
|
+
o
|
|
373
|
+
end
|
|
134
374
|
|
|
135
|
-
|
|
375
|
+
zt = ZoTime.new(Time.now.to_f + zt, nil) if zt.is_a?(Numeric)
|
|
136
376
|
|
|
137
|
-
|
|
377
|
+
fail ArgumentError.new(
|
|
378
|
+
"cannot turn #{o.inspect} to a ZoTime instance"
|
|
379
|
+
) unless zt.is_a?(ZoTime)
|
|
138
380
|
|
|
139
|
-
|
|
140
|
-
|
|
381
|
+
zt
|
|
382
|
+
end
|
|
141
383
|
|
|
142
|
-
|
|
384
|
+
# def in_zone(&block)
|
|
385
|
+
#
|
|
386
|
+
# current_timezone = ENV['TZ']
|
|
387
|
+
# ENV['TZ'] = @zone
|
|
388
|
+
#
|
|
389
|
+
# block.call
|
|
390
|
+
#
|
|
391
|
+
# ensure
|
|
392
|
+
#
|
|
393
|
+
# ENV['TZ'] = current_timezone
|
|
394
|
+
# end
|
|
395
|
+
|
|
396
|
+
protected
|
|
397
|
+
|
|
398
|
+
def inc(t, dir)
|
|
399
|
+
|
|
400
|
+
if t.is_a?(Numeric)
|
|
401
|
+
nt = self.dup
|
|
402
|
+
nt.seconds += dir * t.to_f
|
|
403
|
+
nt
|
|
404
|
+
elsif t.respond_to?(:to_f)
|
|
405
|
+
@seconds + dir * t.to_f
|
|
406
|
+
else
|
|
407
|
+
fail ArgumentError.new(
|
|
408
|
+
"cannot call ZoTime #- or #+ with arg of class #{t.class}")
|
|
409
|
+
end
|
|
410
|
+
end
|
|
143
411
|
|
|
144
|
-
|
|
145
|
-
return false if t.zone == 'UTC'
|
|
146
|
-
return false if t.utc_offset == 0 && str.start_with?(t.zone)
|
|
147
|
-
# 3 common fallbacks...
|
|
412
|
+
def _to_f(o)
|
|
148
413
|
|
|
149
|
-
|
|
414
|
+
fail ArgumentError(
|
|
415
|
+
"comparison of ZoTime with #{o.inspect} failed"
|
|
416
|
+
) unless o.is_a?(ZoTime) || o.is_a?(Time)
|
|
150
417
|
|
|
151
|
-
|
|
418
|
+
o.to_f
|
|
152
419
|
end
|
|
153
420
|
|
|
154
|
-
def
|
|
421
|
+
def strfz(code)
|
|
422
|
+
|
|
423
|
+
return @zone.name if code == '%/Z'
|
|
424
|
+
|
|
425
|
+
per = @zone.period_for_utc(utc)
|
|
155
426
|
|
|
156
|
-
|
|
157
|
-
ENV['TZ'] = @zone
|
|
427
|
+
return per.abbreviation.to_s if code == '%Z'
|
|
158
428
|
|
|
159
|
-
|
|
429
|
+
off = per.utc_total_offset
|
|
430
|
+
#
|
|
431
|
+
sn = off < 0 ? '-' : '+'; off = off.abs
|
|
432
|
+
hr = off / 3600
|
|
433
|
+
mn = (off % 3600) / 60
|
|
434
|
+
sc = 0
|
|
160
435
|
|
|
161
|
-
|
|
436
|
+
fmt =
|
|
437
|
+
if code == '%z'
|
|
438
|
+
"%s%02d%02d"
|
|
439
|
+
elsif code == '%:z'
|
|
440
|
+
"%s%02d:%02d"
|
|
441
|
+
else
|
|
442
|
+
"%s%02d:%02d:%02d"
|
|
443
|
+
end
|
|
162
444
|
|
|
163
|
-
|
|
445
|
+
fmt % [ sn, hr, mn, sc ]
|
|
164
446
|
end
|
|
165
447
|
end
|
|
166
448
|
end
|