rufus-scheduler 2.0.24 → 3.1.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.
- data/CHANGELOG.txt +76 -0
- data/CREDITS.txt +23 -0
- data/LICENSE.txt +1 -1
- data/README.md +1439 -0
- data/Rakefile +1 -5
- data/TODO.txt +149 -55
- data/lib/rufus/{sc → scheduler}/cronline.rb +167 -53
- data/lib/rufus/scheduler/job_array.rb +92 -0
- data/lib/rufus/scheduler/jobs.rb +633 -0
- data/lib/rufus/scheduler/locks.rb +95 -0
- data/lib/rufus/scheduler/util.rb +306 -0
- data/lib/rufus/scheduler/zones.rb +174 -0
- data/lib/rufus/scheduler/zotime.rb +154 -0
- data/lib/rufus/scheduler.rb +608 -27
- data/rufus-scheduler.gemspec +6 -4
- data/spec/basics_spec.rb +54 -0
- data/spec/cronline_spec.rb +479 -152
- data/spec/error_spec.rb +139 -0
- data/spec/job_array_spec.rb +39 -0
- data/spec/job_at_spec.rb +58 -0
- data/spec/job_cron_spec.rb +128 -0
- data/spec/job_every_spec.rb +104 -0
- data/spec/job_in_spec.rb +20 -0
- data/spec/job_interval_spec.rb +68 -0
- data/spec/job_repeat_spec.rb +357 -0
- data/spec/job_spec.rb +498 -109
- data/spec/lock_custom_spec.rb +47 -0
- data/spec/lock_flock_spec.rb +47 -0
- data/spec/lock_lockfile_spec.rb +61 -0
- data/spec/lock_spec.rb +59 -0
- data/spec/parse_spec.rb +263 -0
- data/spec/schedule_at_spec.rb +158 -0
- data/spec/schedule_cron_spec.rb +66 -0
- data/spec/schedule_every_spec.rb +109 -0
- data/spec/schedule_in_spec.rb +80 -0
- data/spec/schedule_interval_spec.rb +128 -0
- data/spec/scheduler_spec.rb +928 -124
- data/spec/spec_helper.rb +126 -0
- data/spec/threads_spec.rb +96 -0
- data/spec/zotime_spec.rb +396 -0
- metadata +56 -33
- data/README.rdoc +0 -661
- data/lib/rufus/otime.rb +0 -3
- data/lib/rufus/sc/jobqueues.rb +0 -160
- data/lib/rufus/sc/jobs.rb +0 -471
- data/lib/rufus/sc/rtime.rb +0 -363
- data/lib/rufus/sc/scheduler.rb +0 -636
- data/lib/rufus/sc/version.rb +0 -32
- data/spec/at_in_spec.rb +0 -47
- data/spec/at_spec.rb +0 -125
- data/spec/blocking_spec.rb +0 -64
- data/spec/cron_spec.rb +0 -134
- data/spec/every_spec.rb +0 -304
- data/spec/exception_spec.rb +0 -113
- data/spec/in_spec.rb +0 -150
- data/spec/mutex_spec.rb +0 -159
- data/spec/rtime_spec.rb +0 -137
- data/spec/schedulable_spec.rb +0 -97
- data/spec/spec_base.rb +0 -87
- data/spec/stress_schedule_unschedule_spec.rb +0 -159
- data/spec/timeout_spec.rb +0 -148
- data/test/kjw.rb +0 -113
- data/test/t.rb +0 -20
@@ -0,0 +1,306 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2006-2015, John Mettraux, jmettraux@gmail.com
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
#
|
22
|
+
# Made in Japan.
|
23
|
+
#++
|
24
|
+
|
25
|
+
|
26
|
+
module Rufus
|
27
|
+
|
28
|
+
class Scheduler
|
29
|
+
|
30
|
+
#--
|
31
|
+
# time and string methods
|
32
|
+
#++
|
33
|
+
|
34
|
+
def self.parse(o, opts={})
|
35
|
+
|
36
|
+
opts[:no_error] = true
|
37
|
+
|
38
|
+
parse_cron(o, opts) ||
|
39
|
+
parse_in(o, opts) || # covers 'every' schedule strings
|
40
|
+
parse_at(o, opts) ||
|
41
|
+
raise(ArgumentError.new("couldn't parse \"#{o}\""))
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.parse_in(o, opts={})
|
45
|
+
|
46
|
+
o.is_a?(String) ? parse_duration(o, opts) : o
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.parse_at(o, opts={})
|
50
|
+
|
51
|
+
Rufus::Scheduler::ZoTime.parse(o, opts).time
|
52
|
+
|
53
|
+
rescue StandardError => se
|
54
|
+
|
55
|
+
return nil if opts[:no_error]
|
56
|
+
raise se
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.parse_cron(o, opts)
|
60
|
+
|
61
|
+
CronLine.new(o)
|
62
|
+
|
63
|
+
rescue ArgumentError => ae
|
64
|
+
|
65
|
+
return nil if opts[:no_error]
|
66
|
+
raise ae
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.parse_to_time(o)
|
70
|
+
|
71
|
+
t = o
|
72
|
+
t = parse(t) if t.is_a?(String)
|
73
|
+
t = Time.now + t if t.is_a?(Numeric)
|
74
|
+
|
75
|
+
raise ArgumentError.new(
|
76
|
+
"cannot turn #{o.inspect} to a point in time, doesn't make sense"
|
77
|
+
) unless t.is_a?(Time)
|
78
|
+
|
79
|
+
t
|
80
|
+
end
|
81
|
+
|
82
|
+
DURATIONS2M = [
|
83
|
+
[ 'y', 365 * 24 * 3600 ],
|
84
|
+
[ 'M', 30 * 24 * 3600 ],
|
85
|
+
[ 'w', 7 * 24 * 3600 ],
|
86
|
+
[ 'd', 24 * 3600 ],
|
87
|
+
[ 'h', 3600 ],
|
88
|
+
[ 'm', 60 ],
|
89
|
+
[ 's', 1 ]
|
90
|
+
]
|
91
|
+
DURATIONS2 = DURATIONS2M.dup
|
92
|
+
DURATIONS2.delete_at(1)
|
93
|
+
|
94
|
+
DURATIONS = DURATIONS2M.inject({}) { |r, (k, v)| r[k] = v; r }
|
95
|
+
DURATION_LETTERS = DURATIONS.keys.join
|
96
|
+
|
97
|
+
DU_KEYS = DURATIONS2M.collect { |k, v| k.to_sym }
|
98
|
+
|
99
|
+
# Turns a string like '1m10s' into a float like '70.0', more formally,
|
100
|
+
# turns a time duration expressed as a string into a Float instance
|
101
|
+
# (millisecond count).
|
102
|
+
#
|
103
|
+
# w -> week
|
104
|
+
# d -> day
|
105
|
+
# h -> hour
|
106
|
+
# m -> minute
|
107
|
+
# s -> second
|
108
|
+
# M -> month
|
109
|
+
# y -> year
|
110
|
+
# 'nada' -> millisecond
|
111
|
+
#
|
112
|
+
# Some examples:
|
113
|
+
#
|
114
|
+
# Rufus::Scheduler.parse_duration "0.5" # => 0.5
|
115
|
+
# Rufus::Scheduler.parse_duration "500" # => 0.5
|
116
|
+
# Rufus::Scheduler.parse_duration "1000" # => 1.0
|
117
|
+
# Rufus::Scheduler.parse_duration "1h" # => 3600.0
|
118
|
+
# Rufus::Scheduler.parse_duration "1h10s" # => 3610.0
|
119
|
+
# Rufus::Scheduler.parse_duration "1w2d" # => 777600.0
|
120
|
+
#
|
121
|
+
# Negative time strings are OK (Thanks Danny Fullerton):
|
122
|
+
#
|
123
|
+
# Rufus::Scheduler.parse_duration "-0.5" # => -0.5
|
124
|
+
# Rufus::Scheduler.parse_duration "-1h" # => -3600.0
|
125
|
+
#
|
126
|
+
def self.parse_duration(string, opts={})
|
127
|
+
|
128
|
+
string = string.to_s
|
129
|
+
|
130
|
+
return 0.0 if string == ''
|
131
|
+
|
132
|
+
m = string.match(/^(-?)([\d\.#{DURATION_LETTERS}]+)$/)
|
133
|
+
|
134
|
+
return nil if m.nil? && opts[:no_error]
|
135
|
+
raise ArgumentError.new("cannot parse '#{string}'") if m.nil?
|
136
|
+
|
137
|
+
mod = m[1] == '-' ? -1.0 : 1.0
|
138
|
+
val = 0.0
|
139
|
+
|
140
|
+
s = m[2]
|
141
|
+
|
142
|
+
while s.length > 0
|
143
|
+
m = nil
|
144
|
+
if m = s.match(/^(\d+|\d+\.\d*|\d*\.\d+)([#{DURATION_LETTERS}])(.*)$/)
|
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
|
+
raise ArgumentError.new(
|
154
|
+
"cannot parse '#{string}' (especially '#{s}')"
|
155
|
+
)
|
156
|
+
end
|
157
|
+
break unless m && m[3]
|
158
|
+
s = m[3]
|
159
|
+
end
|
160
|
+
|
161
|
+
mod * val
|
162
|
+
end
|
163
|
+
|
164
|
+
class << self
|
165
|
+
#-
|
166
|
+
# for compatibility with rufus-scheduler 2.x
|
167
|
+
#+
|
168
|
+
alias parse_duration_string parse_duration
|
169
|
+
alias parse_time_string parse_duration
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
# Turns a number of seconds into a a time string
|
174
|
+
#
|
175
|
+
# Rufus.to_duration 0 # => '0s'
|
176
|
+
# Rufus.to_duration 60 # => '1m'
|
177
|
+
# Rufus.to_duration 3661 # => '1h1m1s'
|
178
|
+
# Rufus.to_duration 7 * 24 * 3600 # => '1w'
|
179
|
+
# Rufus.to_duration 30 * 24 * 3600 + 1 # => "4w2d1s"
|
180
|
+
#
|
181
|
+
# It goes from seconds to the year. Months are not counted (as they
|
182
|
+
# are of variable length). Weeks are counted.
|
183
|
+
#
|
184
|
+
# For 30 days months to be counted, the second parameter of this
|
185
|
+
# method can be set to true.
|
186
|
+
#
|
187
|
+
# Rufus.to_duration 30 * 24 * 3600 + 1, true # => "1M1s"
|
188
|
+
#
|
189
|
+
# If a Float value is passed, milliseconds will be displayed without
|
190
|
+
# 'marker'
|
191
|
+
#
|
192
|
+
# Rufus.to_duration 0.051 # => "51"
|
193
|
+
# Rufus.to_duration 7.051 # => "7s51"
|
194
|
+
# Rufus.to_duration 0.120 + 30 * 24 * 3600 + 1 # => "4w2d1s120"
|
195
|
+
#
|
196
|
+
# (this behaviour mirrors the one found for parse_time_string()).
|
197
|
+
#
|
198
|
+
# Options are :
|
199
|
+
#
|
200
|
+
# * :months, if set to true, months (M) of 30 days will be taken into
|
201
|
+
# account when building up the result
|
202
|
+
# * :drop_seconds, if set to true, seconds and milliseconds will be trimmed
|
203
|
+
# from the result
|
204
|
+
#
|
205
|
+
def self.to_duration(seconds, options={})
|
206
|
+
|
207
|
+
h = to_duration_hash(seconds, options)
|
208
|
+
|
209
|
+
return (options[:drop_seconds] ? '0m' : '0s') if h.empty?
|
210
|
+
|
211
|
+
s =
|
212
|
+
DU_KEYS.inject('') { |r, key|
|
213
|
+
count = h[key]
|
214
|
+
count = nil if count == 0
|
215
|
+
r << "#{count}#{key}" if count
|
216
|
+
r
|
217
|
+
}
|
218
|
+
|
219
|
+
ms = h[:ms]
|
220
|
+
s << ms.to_s if ms
|
221
|
+
|
222
|
+
s
|
223
|
+
end
|
224
|
+
|
225
|
+
class << self
|
226
|
+
#-
|
227
|
+
# for compatibility with rufus-scheduler 2.x
|
228
|
+
#+
|
229
|
+
alias to_duration_string to_duration
|
230
|
+
alias to_time_string to_duration
|
231
|
+
end
|
232
|
+
|
233
|
+
# Turns a number of seconds (integer or Float) into a hash like in :
|
234
|
+
#
|
235
|
+
# Rufus.to_duration_hash 0.051
|
236
|
+
# # => { :ms => "51" }
|
237
|
+
# Rufus.to_duration_hash 7.051
|
238
|
+
# # => { :s => 7, :ms => "51" }
|
239
|
+
# Rufus.to_duration_hash 0.120 + 30 * 24 * 3600 + 1
|
240
|
+
# # => { :w => 4, :d => 2, :s => 1, :ms => "120" }
|
241
|
+
#
|
242
|
+
# This method is used by to_duration behind the scenes.
|
243
|
+
#
|
244
|
+
# Options are :
|
245
|
+
#
|
246
|
+
# * :months, if set to true, months (M) of 30 days will be taken into
|
247
|
+
# account when building up the result
|
248
|
+
# * :drop_seconds, if set to true, seconds and milliseconds will be trimmed
|
249
|
+
# from the result
|
250
|
+
#
|
251
|
+
def self.to_duration_hash(seconds, options={})
|
252
|
+
|
253
|
+
h = {}
|
254
|
+
|
255
|
+
if seconds.is_a?(Float)
|
256
|
+
h[:ms] = (seconds % 1 * 1000).to_i
|
257
|
+
seconds = seconds.to_i
|
258
|
+
end
|
259
|
+
|
260
|
+
if options[:drop_seconds]
|
261
|
+
h.delete(:ms)
|
262
|
+
seconds = (seconds - seconds % 60)
|
263
|
+
end
|
264
|
+
|
265
|
+
durations = options[:months] ? DURATIONS2M : DURATIONS2
|
266
|
+
|
267
|
+
durations.each do |key, duration|
|
268
|
+
|
269
|
+
count = seconds / duration
|
270
|
+
seconds = seconds % duration
|
271
|
+
|
272
|
+
h[key.to_sym] = count if count > 0
|
273
|
+
end
|
274
|
+
|
275
|
+
h
|
276
|
+
end
|
277
|
+
|
278
|
+
#--
|
279
|
+
# misc
|
280
|
+
#++
|
281
|
+
|
282
|
+
# Produces the UTC string representation of a Time instance
|
283
|
+
#
|
284
|
+
# like "2009/11/23 11:11:50.947109 UTC"
|
285
|
+
#
|
286
|
+
def self.utc_to_s(t=Time.now)
|
287
|
+
|
288
|
+
"#{t.utc.strftime('%Y-%m-%d %H:%M:%S')}.#{sprintf('%06d', t.usec)} UTC"
|
289
|
+
end
|
290
|
+
|
291
|
+
# Produces a hour/min/sec/milli string representation of Time instance
|
292
|
+
#
|
293
|
+
def self.h_to_s(t=Time.now)
|
294
|
+
|
295
|
+
"#{t.strftime('%H:%M:%S')}.#{sprintf('%06d', t.usec)}"
|
296
|
+
end
|
297
|
+
|
298
|
+
# Debugging tools...
|
299
|
+
#
|
300
|
+
class D
|
301
|
+
|
302
|
+
def self.h_to_s(t=Time.now); Rufus::Scheduler.h_to_s(t); end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
@@ -0,0 +1,174 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2006-2015, John Mettraux, jmettraux@gmail.com
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
#
|
22
|
+
# Made in Japan.
|
23
|
+
#++
|
24
|
+
|
25
|
+
|
26
|
+
class Rufus::Scheduler
|
27
|
+
|
28
|
+
TIMEZONES = %w[
|
29
|
+
GB NZ UCT EET CET PRC ROC WET GMT EST ROK UTC MST HST MET Zulu Cuba Iran W-SU
|
30
|
+
Eire GMT0 Libya Japan Egypt GMT+0 GMT-0 Israel Poland Navajo Turkey GB-Eire
|
31
|
+
Iceland PST8PDT Etc/UCT CST6CDT NZ-CHAT MST7MDT Jamaica EST5EDT Etc/GMT Etc/UTC
|
32
|
+
US/Samoa Etc/GMT0 Portugal Hongkong Etc/Zulu Singapore Asia/Baku Etc/GMT-9
|
33
|
+
Etc/GMT+1 Etc/GMT+0 Asia/Aden Etc/GMT+2 Etc/GMT+3 Etc/GMT+4 Etc/GMT+5 Etc/GMT+6
|
34
|
+
Etc/GMT+7 Etc/GMT+8 Etc/GMT+9 Etc/GMT-0 Etc/GMT-1 Universal Asia/Dili Greenwich
|
35
|
+
Asia/Gaza Etc/GMT-8 Etc/GMT-7 US/Alaska Asia/Oral Etc/GMT-6 Etc/GMT-5 Etc/GMT-4
|
36
|
+
Asia/Hovd Etc/GMT-3 US/Hawaii Etc/GMT-2 Kwajalein Asia/Omsk Asia/Macao
|
37
|
+
Etc/GMT-14 Asia/Kabul US/Central Etc/GMT-13 US/Arizona Asia/Macau Asia/Qatar
|
38
|
+
Asia/Seoul Asia/Tokyo Asia/Dubai US/Pacific Etc/GMT-12 Etc/GMT-11 Etc/GMT-10
|
39
|
+
Asia/Dhaka Asia/Dacca Asia/Chita Etc/GMT+12 Etc/GMT+10 Asia/Amman Asia/Aqtau
|
40
|
+
Etc/GMT+11 US/Eastern Asia/Thimbu Asia/Brunei Asia/Tehran Asia/Beirut
|
41
|
+
Europe/Rome Europe/Riga Brazil/Acre Brazil/East Europe/Oslo Brazil/West
|
42
|
+
Africa/Lome Asia/Taipei Asia/Saigon Asia/Riyadh Asia/Aqtobe Asia/Anadyr
|
43
|
+
Europe/Kiev Asia/Almaty Africa/Juba Pacific/Yap US/Aleutian Asia/Muscat
|
44
|
+
US/Mountain Asia/Harbin Asia/Hebron Asia/Manila Asia/Kuwait Asia/Urumqi
|
45
|
+
US/Michigan Indian/Mahe SystemV/EST5 Asia/Kashgar Indian/Cocos Asia/Jakarta
|
46
|
+
Asia/Kolkata Asia/Kuching America/Atka Asia/Irkutsk Pacific/Apia Asia/Magadan
|
47
|
+
Africa/Dakar America/Lima Pacific/Fiji Pacific/Guam Europe/Vaduz Pacific/Niue
|
48
|
+
Asia/Nicosia Africa/Ceuta Pacific/Truk America/Adak Pacific/Wake Africa/Tunis
|
49
|
+
Africa/Cairo Asia/Colombo SystemV/AST4 SystemV/CST6 Asia/Karachi Asia/Rangoon
|
50
|
+
SystemV/MST7 Asia/Baghdad Europe/Malta Africa/Lagos Europe/Minsk SystemV/PST8
|
51
|
+
Canada/Yukon Asia/Tbilisi America/Nome Asia/Bahrain Africa/Accra Europe/Paris
|
52
|
+
Asia/Bangkok Asia/Bishkek Asia/Thimphu SystemV/YST9 Asia/Yerevan Asia/Yakutsk
|
53
|
+
Europe/Sofia Asia/Ust-Nera Australia/ACT Australia/LHI Europe/Tirane
|
54
|
+
Asia/Tel_Aviv Australia/NSW Africa/Luanda Asia/Tashkent Africa/Lusaka
|
55
|
+
Asia/Shanghai Africa/Malabo Asia/Sakhalin Africa/Maputo Africa/Maseru
|
56
|
+
SystemV/HST10 Africa/Kigali Africa/Niamey Pacific/Samoa America/Sitka
|
57
|
+
Pacific/Palau Pacific/Nauru Pacific/Efate Asia/Makassar Pacific/Chuuk
|
58
|
+
Africa/Harare Africa/Douala America/Aruba America/Thule America/Bahia
|
59
|
+
America/Jujuy America/Belem Asia/Katmandu America/Boise Indian/Comoro
|
60
|
+
Indian/Chagos Asia/Jayapura Europe/Zurich Asia/Istanbul Europe/Zagreb
|
61
|
+
Etc/Greenwich Europe/Warsaw Europe/Vienna Etc/Universal Asia/Dushanbe
|
62
|
+
Europe/Athens Europe/Berlin Africa/Bissau Asia/Damascus Africa/Banjul
|
63
|
+
Europe/Dublin Africa/Bangui Africa/Bamako Europe/Jersey Africa/Asmera
|
64
|
+
Europe/Lisbon Africa/Asmara Europe/London Asia/Ashgabat Asia/Calcutta
|
65
|
+
Europe/Madrid Europe/Monaco Europe/Moscow Europe/Prague Europe/Samara
|
66
|
+
Europe/Skopje Asia/Khandyga Canada/Pacific Africa/Abidjan America/Manaus
|
67
|
+
Asia/Chongqing Asia/Chungking Africa/Algiers America/Maceio US/Pacific-New
|
68
|
+
Africa/Conakry America/La_Paz America/Juneau America/Nassau America/Inuvik
|
69
|
+
Europe/Andorra Africa/Kampala Asia/Ashkhabad Asia/Hong_Kong America/Havana
|
70
|
+
Canada/Eastern Europe/Belfast Canada/Central Australia/West Asia/Jerusalem
|
71
|
+
Africa/Mbabane Asia/Kamchatka America/Virgin America/Guyana Asia/Kathmandu
|
72
|
+
Mexico/General America/Panama Europe/Nicosia America/Denver Europe/Tallinn
|
73
|
+
Africa/Nairobi America/Dawson Europe/Vatican Europe/Vilnius America/Cuiaba
|
74
|
+
Africa/Tripoli Pacific/Wallis Atlantic/Faroe Pacific/Tarawa Pacific/Tahiti
|
75
|
+
Pacific/Saipan Pacific/Ponape America/Cayman America/Cancun Asia/Pontianak
|
76
|
+
Asia/Pyongyang Asia/Vientiane Asia/Qyzylorda Pacific/Noumea America/Bogota
|
77
|
+
Pacific/Midway Pacific/Majuro Asia/Samarkand Indian/Mayotte Pacific/Kosrae
|
78
|
+
Asia/Singapore Indian/Reunion America/Belize America/Regina America/Recife
|
79
|
+
Pacific/Easter Mexico/BajaSur America/Merida Pacific/Chatham Pacific/Fakaofo
|
80
|
+
Pacific/Gambier America/Rosario Asia/Ulan_Bator Indian/Maldives Pacific/Norfolk
|
81
|
+
America/Antigua Asia/Phnom_Penh America/Phoenix America/Caracas America/Cayenne
|
82
|
+
Atlantic/Azores Pacific/Pohnpei Atlantic/Canary America/Chicago Atlantic/Faeroe
|
83
|
+
Africa/Windhoek America/Cordoba America/Creston Africa/Timbuktu America/Curacao
|
84
|
+
Africa/Sao_Tome Africa/Ndjamena SystemV/AST4ADT Europe/Uzhgorod Europe/Tiraspol
|
85
|
+
SystemV/CST6CDT Africa/Monrovia America/Detroit Europe/Sarajevo Australia/Eucla
|
86
|
+
America/Tijuana America/Toronto America/Godthab America/Grenada Europe/Istanbul
|
87
|
+
America/Ojinaga America/Tortola Australia/Perth Europe/Helsinki Australia/South
|
88
|
+
Europe/Guernsey SystemV/EST5EDT Europe/Chisinau SystemV/MST7MDT Europe/Busingen
|
89
|
+
Europe/Budapest Europe/Brussels America/Halifax America/Mendoza America/Noronha
|
90
|
+
America/Nipigon Canada/Atlantic America/Yakutat SystemV/PST8PDT SystemV/YST9YDT
|
91
|
+
Canada/Mountain Africa/Kinshasa Africa/Khartoum Africa/Gaborone Africa/Freetown
|
92
|
+
America/Iqaluit America/Jamaica US/East-Indiana Africa/El_Aaiun America/Knox_IN
|
93
|
+
Africa/Djibouti Africa/Blantyre America/Moncton America/Managua Asia/Choibalsan
|
94
|
+
America/Marigot Australia/North Europe/Belgrade America/Resolute
|
95
|
+
America/Mazatlan Pacific/Funafuti Pacific/Auckland Pacific/Honolulu
|
96
|
+
Pacific/Johnston America/Miquelon America/Santarem Mexico/BajaNorte
|
97
|
+
America/Santiago Antarctica/Troll America/Asuncion America/Atikokan
|
98
|
+
America/Montreal America/Barbados Africa/Bujumbura Pacific/Pitcairn
|
99
|
+
Asia/Ulaanbaatar Indian/Mauritius America/New_York Antarctica/Syowa
|
100
|
+
America/Shiprock Indian/Kerguelen Asia/Novosibirsk America/Anguilla
|
101
|
+
Indian/Christmas Asia/Vladivostok Asia/Ho_Chi_Minh Antarctica/Davis
|
102
|
+
Atlantic/Bermuda Europe/Amsterdam Antarctica/Casey America/St_Johns
|
103
|
+
Atlantic/Madeira America/Winnipeg America/St_Kitts Europe/Volgograd
|
104
|
+
Brazil/DeNoronha Europe/Bucharest Africa/Mogadishu America/St_Lucia
|
105
|
+
Atlantic/Stanley Europe/Stockholm Australia/Currie Europe/Gibraltar
|
106
|
+
Australia/Sydney Asia/Krasnoyarsk Australia/Darwin America/Dominica
|
107
|
+
America/Edmonton America/Eirunepe Europe/Podgorica America/Ensenada
|
108
|
+
Europe/Ljubljana Australia/Hobart Europe/Mariehamn Africa/Lubumbashi
|
109
|
+
America/Goose_Bay Europe/Luxembourg America/Menominee America/Glace_Bay
|
110
|
+
America/Fortaleza Africa/Nouakchott America/Matamoros Pacific/Galapagos
|
111
|
+
America/Guatemala Pacific/Kwajalein Pacific/Marquesas America/Guayaquil
|
112
|
+
Asia/Kuala_Lumpur Europe/San_Marino America/Monterrey Europe/Simferopol
|
113
|
+
America/Araguaina Antarctica/Vostok Europe/Copenhagen America/Catamarca
|
114
|
+
Pacific/Pago_Pago America/Sao_Paulo America/Boa_Vista America/St_Thomas
|
115
|
+
Chile/Continental America/Vancouver Africa/Casablanca Europe/Bratislava
|
116
|
+
Pacific/Enderbury Pacific/Rarotonga Europe/Zaporozhye US/Indiana-Starke
|
117
|
+
Antarctica/Palmer Asia/Novokuznetsk Africa/Libreville America/Chihuahua
|
118
|
+
America/Anchorage Pacific/Tongatapu Antarctica/Mawson Africa/Porto-Novo
|
119
|
+
Asia/Yekaterinburg America/Paramaribo America/Hermosillo Atlantic/Jan_Mayen
|
120
|
+
Antarctica/McMurdo America/Costa_Rica Antarctica/Rothera America/Grand_Turk
|
121
|
+
Atlantic/Reykjavik Atlantic/St_Helena Australia/Victoria Chile/EasterIsland
|
122
|
+
Asia/Ujung_Pandang Australia/Adelaide America/Montserrat America/Porto_Acre
|
123
|
+
Africa/Brazzaville Australia/Brisbane America/Kralendijk America/Montevideo
|
124
|
+
America/St_Vincent America/Louisville Australia/Canberra Australia/Tasmania
|
125
|
+
Europe/Isle_of_Man Europe/Kaliningrad Africa/Ouagadougou America/Rio_Branco
|
126
|
+
Pacific/Kiritimati Africa/Addis_Ababa America/Metlakatla America/Martinique
|
127
|
+
Asia/Srednekolymsk America/Guadeloupe America/Fort_Wayne Australia/Lindeman
|
128
|
+
America/Whitehorse Arctic/Longyearbyen America/Pangnirtung America/Mexico_City
|
129
|
+
America/Los_Angeles America/Rainy_River Atlantic/Cape_Verde Pacific/Guadalcanal
|
130
|
+
Indian/Antananarivo America/El_Salvador Australia/Lord_Howe Africa/Johannesburg
|
131
|
+
America/Tegucigalpa Canada/Saskatchewan America/Thunder_Bay Canada/Newfoundland
|
132
|
+
America/Puerto_Rico America/Yellowknife Australia/Melbourne America/Porto_Velho
|
133
|
+
Australia/Queensland Australia/Yancowinna America/Santa_Isabel
|
134
|
+
America/Blanc-Sablon America/Scoresbysund America/Danmarkshavn
|
135
|
+
Pacific/Port_Moresby Antarctica/Macquarie America/Buenos_Aires
|
136
|
+
Africa/Dar_es_Salaam America/Campo_Grande America/Dawson_Creek
|
137
|
+
America/Indianapolis Pacific/Bougainville America/Rankin_Inlet
|
138
|
+
America/Indiana/Knox America/Lower_Princes America/Coral_Harbour
|
139
|
+
America/St_Barthelemy Australia/Broken_Hill America/Cambridge_Bay
|
140
|
+
America/Indiana/Vevay America/Swift_Current America/Port_of_Spain
|
141
|
+
Antarctica/South_Pole America/Santo_Domingo Atlantic/South_Georgia
|
142
|
+
America/Port-au-Prince America/Bahia_Banderas America/Indiana/Winamac
|
143
|
+
America/Indiana/Marengo America/Argentina/Jujuy America/Argentina/Salta
|
144
|
+
Canada/East-Saskatchewan America/Indiana/Vincennes America/Argentina/Tucuman
|
145
|
+
America/Argentina/Ushuaia Antarctica/DumontDUrville America/Indiana/Tell_City
|
146
|
+
America/Argentina/Mendoza America/Argentina/Cordoba America/Indiana/Petersburg
|
147
|
+
America/Argentina/San_Luis America/Argentina/San_Juan America/Argentina/La_Rioja
|
148
|
+
America/North_Dakota/Center America/Kentucky/Monticello
|
149
|
+
America/North_Dakota/Beulah America/Kentucky/Louisville
|
150
|
+
America/Argentina/Catamarca America/Indiana/Indianapolis
|
151
|
+
America/North_Dakota/New_Salem America/Argentina/Rio_Gallegos
|
152
|
+
America/Argentina/Buenos_Aires America/Argentina/ComodRivadavia
|
153
|
+
]
|
154
|
+
|
155
|
+
##
|
156
|
+
## http://en.wikipedia.org/wiki/List_of_time_zone_abbreviations
|
157
|
+
#
|
158
|
+
#ABBREVIATIONS = %w[
|
159
|
+
#ACDT ACST ACT ADT AEDT AEST AFT AKDT AKST AMST AMST AMT AMT ART AST AST AWDT
|
160
|
+
#AWST AZOST AZT BDT BIOT BIT BOT BRT BST BST BTT CAT CCT CDT CDT CEDT CEST CET
|
161
|
+
#CHADT CHAST CHOT ChST CHUT CIST CIT CKT CLST CLT COST COT CST CST CST CST CST
|
162
|
+
#CT CVT CWST CXT DAVT DDUT DFT EASST EAST EAT ECT ECT EDT EEDT EEST EET EGST EGT
|
163
|
+
#EIT EST EST FET FJT FKST FKST FKT FNT GALT GAMT GET GFT GILT GIT GMT GST GST
|
164
|
+
#GYT HADT HAEC HAST HKT HMT HOVT HST ICT IDT IOT IRDT IRKT IRST IST IST IST JST
|
165
|
+
#KGT KOST KRAT KST LHST LHST LINT MAGT MART MAWT MDT MET MEST MHT MIST MIT MMT
|
166
|
+
#MSK MST MST MST MUT MVT MYT NCT NDT NFT NPT NST NT NUT NZDT NZST OMST ORAT PDT
|
167
|
+
#PET PETT PGT PHOT PKT PMDT PMST PONT PST PST PYST PYT RET ROTT SAKT SAMT SAST
|
168
|
+
#SBT SCT SGT SLST SRET SRT SST SST SYOT TAHT THA TFT TJT TKT TLT TMT TOT TVT UCT
|
169
|
+
#ULAT USZ1 UTC UYST UYT UZT VET VLAT VOLT VOST VUT WAKT WAST WAT WEDT WEST WET
|
170
|
+
#WIT WST YAKT YEKT Z
|
171
|
+
#].uniq
|
172
|
+
|
173
|
+
end
|
174
|
+
|
@@ -0,0 +1,154 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2006-2015, John Mettraux, jmettraux@gmail.com
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
#
|
22
|
+
# Made in Japan.
|
23
|
+
#++
|
24
|
+
|
25
|
+
require 'rufus/scheduler/zones'
|
26
|
+
|
27
|
+
|
28
|
+
class Rufus::Scheduler
|
29
|
+
|
30
|
+
#
|
31
|
+
# Zon{ing|ed}Time, whatever.
|
32
|
+
#
|
33
|
+
class ZoTime
|
34
|
+
|
35
|
+
attr_accessor :seconds
|
36
|
+
attr_accessor :zone
|
37
|
+
|
38
|
+
def initialize(s, zone)
|
39
|
+
|
40
|
+
@seconds = s.to_f
|
41
|
+
@zone = zone
|
42
|
+
end
|
43
|
+
|
44
|
+
def time
|
45
|
+
|
46
|
+
in_zone do
|
47
|
+
|
48
|
+
t = Time.at(@seconds)
|
49
|
+
|
50
|
+
if t.isdst
|
51
|
+
t1 = Time.at(@seconds + 3600)
|
52
|
+
t = t1 if t.zone != t1.zone && t.hour == t1.hour && t.min == t1.min
|
53
|
+
# ambiguous TZ (getting out of DST)
|
54
|
+
else
|
55
|
+
t.hour # force t to compute itself
|
56
|
+
end
|
57
|
+
|
58
|
+
t
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def utc
|
63
|
+
|
64
|
+
time.utc
|
65
|
+
end
|
66
|
+
|
67
|
+
def add(s)
|
68
|
+
|
69
|
+
@seconds += s.to_f
|
70
|
+
end
|
71
|
+
|
72
|
+
def substract(s)
|
73
|
+
|
74
|
+
@seconds -= s.to_f
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_f
|
78
|
+
|
79
|
+
@seconds
|
80
|
+
end
|
81
|
+
|
82
|
+
#DELTA_TZ_REX = /^[+-][0-1][0-9]:?[0-5][0-9]$/
|
83
|
+
|
84
|
+
def self.envtzable?(s)
|
85
|
+
|
86
|
+
TIMEZONES.include?(s)
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.parse(str, opts={})
|
90
|
+
|
91
|
+
if defined?(::Chronic) && t = ::Chronic.parse(str, opts)
|
92
|
+
return ZoTime.new(t, ENV['TZ'])
|
93
|
+
end
|
94
|
+
|
95
|
+
begin
|
96
|
+
DateTime.parse(str)
|
97
|
+
rescue
|
98
|
+
raise ArgumentError, "no time information in #{o.inspect}"
|
99
|
+
end if RUBY_VERSION < '1.9.0'
|
100
|
+
|
101
|
+
zone = nil
|
102
|
+
|
103
|
+
s =
|
104
|
+
str.gsub(/\S+/) { |m|
|
105
|
+
if envtzable?(m)
|
106
|
+
zone ||= m
|
107
|
+
''
|
108
|
+
else
|
109
|
+
m
|
110
|
+
end
|
111
|
+
}
|
112
|
+
|
113
|
+
return nil unless zone.nil? || is_timezone?(zone)
|
114
|
+
|
115
|
+
zt = ZoTime.new(0, zone || ENV['TZ'])
|
116
|
+
zt.in_zone { zt.seconds = Time.parse(s).to_f }
|
117
|
+
|
118
|
+
zt.seconds == nil ? nil : zt
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.is_timezone?(str)
|
122
|
+
|
123
|
+
return false if str == nil
|
124
|
+
|
125
|
+
return true if Time.zone_offset(str)
|
126
|
+
return true if str == 'Zulu'
|
127
|
+
|
128
|
+
return !! (::TZInfo::Timezone.get(str) rescue nil) if defined?(::TZInfo)
|
129
|
+
|
130
|
+
zt = ZoTime.new(0, str)
|
131
|
+
t = zt.time
|
132
|
+
|
133
|
+
return false if t.zone == ''
|
134
|
+
return false if str.match(/[a-z]/) && str.start_with?(t.zone)
|
135
|
+
|
136
|
+
return false if RUBY_PLATFORM.include?('java') && ! envtzable?(str)
|
137
|
+
|
138
|
+
true
|
139
|
+
end
|
140
|
+
|
141
|
+
def in_zone(&block)
|
142
|
+
|
143
|
+
current_timezone = ENV['TZ']
|
144
|
+
ENV['TZ'] = @zone
|
145
|
+
|
146
|
+
block.call
|
147
|
+
|
148
|
+
ensure
|
149
|
+
|
150
|
+
ENV['TZ'] = current_timezone
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|