rufus-scheduler 3.1.1 → 3.2.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 CHANGED
@@ -2,6 +2,63 @@
2
2
  = rufus-scheduler CHANGELOG.txt
3
3
 
4
4
 
5
+ == rufus-scheduler - 3.2.0 released 2015-12-28
6
+
7
+ - cache CronLine#brute_frequency results, gh-188 and gh-89
8
+ - "every" shift prevention by https://github.com/Korrigan
9
+ - Ruby warnings silenced by https://github.com/vivitar
10
+
11
+
12
+ == rufus-scheduler - 3.1.10 released 2015-11-18
13
+
14
+ - allow for :first_in => 0, gh-179 by https://github.com/JonMcPherson
15
+ for https://github.com/Shopify/dashing/commit/ea3730fa4
16
+ - stop shipping specs in gem
17
+
18
+
19
+ == rufus-scheduler - 3.1.9 released 2015-11-12
20
+
21
+ - fix potential RuntimeError in CronLine#prev_second,
22
+ by Alexandru https://github.com/alexandru-calinoiu
23
+
24
+
25
+ == rufus-scheduler - 3.1.8 released 2015-11-10
26
+
27
+ - stop jumping eagerly out of DST, fix for one hour jump when leaving DST
28
+ thanks Alyssa http://github.com/alyssa
29
+
30
+
31
+ == rufus-scheduler - 3.1.7 released 2015-10-15
32
+
33
+ - ack #unscheduled_at in #scheduled?, by Claude https://github.com/claudeatsafe
34
+
35
+
36
+ == rufus-scheduler - 3.1.6 released 2015-10-01
37
+
38
+ - fix job id uniqueness (JRuby), thanks 김성식 https://github.com/kssminus
39
+
40
+
41
+ == rufus-scheduler - 3.1.5 released 2015-09-25
42
+
43
+ - fix for "not a valid cronline" on "mingw" Ruby distributions, gh-166
44
+
45
+
46
+ == rufus-scheduler - 3.1.4 released 2015/08/29
47
+
48
+ - fix cron issue reported by Jesse https://github.com/jhw-at-prosperworks-com
49
+
50
+
51
+ == rufus-scheduler - 3.1.3 released 2015/06/20
52
+
53
+ - prevent Thread[:rufus_scheduler_time] -> nil, gh-156
54
+ - fix inconsistency in Job#start_work_thread
55
+
56
+
57
+ == rufus-scheduler - 3.1.2 released 2015/05/23
58
+
59
+ - avoid cron/:first_at infinite loop, thanks https://github.com/pouellet
60
+
61
+
5
62
  == rufus-scheduler - 3.1.1 released 2015/04/19
6
63
 
7
64
  - fix ZoTime.is_timezone? on OSX, thanks https://github.com/yaauie
data/CREDITS.txt CHANGED
@@ -4,6 +4,16 @@
4
4
 
5
5
  == Contributors
6
6
 
7
+ - Balasankar C (https://github.com/balasankarc) fix CronJob spec vs December
8
+ - Matthieu Rosinski (https://github.com/Korrigan) prevent "every" shifts
9
+ - vivitar (https://github.com/vivitar) silenced a set of Ruby warnings
10
+ - Jon McPherson (https://github.com/JonMcPherson) :first_in => 0 back
11
+ - Calinoiu Alexandru Nicolae (https://github.com/alexandru-calinoiu) CronLine#prev_second fix
12
+ - Alyssa Pohahau (https://github.com/alyssa) out of DST transition specs
13
+ - Claude Vessaz (https://github.com/claudeatsafe) ack #unscheduled_at in #scheduled?
14
+ - 김성식 (https://github.com/kssminus) job id uniqueness effort
15
+ - Jesse Willet (https://github.com/jhw-at-prosperworks-com) cron vs "*/10"
16
+ - Pascal Ouellet (https://github.com/pouellet) Scheduler#timeline loop fix
7
17
  - Ryan Biesemeyer (https://github.com/yaauie) ZoTime.is_timezone? on OSX
8
18
  - Ketan Padegaonkar (https://github.com/ketan) .brute_frequency improvement
9
19
  - Gabriel Gilder (https://github.com/ggilder) LA DST specs
@@ -36,6 +46,11 @@
36
46
 
37
47
  == Feedback
38
48
 
49
+ - Eduardo Maia - https://github.com/emaiax - rufus and the Rails console
50
+ - Suisea - https://github.com/suisea - readme rewording
51
+ - Radek - http://stackoverflow.com/users/250422 - gh-166
52
+ - Patrik Ragnarsson - https://github.com/dentarg - timeout vs nil, gh-156
53
+ - twitter @adefilaedward1 - typo in readme
39
54
  - Michael Guymon - https://github.com/mguymon - #next_time vs :first_at
40
55
  - junhanamaki - https://github.com/junhanamaki - #next_time and dst ambiguities
41
56
  - kreynolds (tossrock) - inspiration for #occurrences
data/README.md CHANGED
@@ -75,10 +75,10 @@ There is no EventMachine-based scheduler anymore.
75
75
 
76
76
  ## I don't know what this Ruby thing is, where are my Rails?
77
77
 
78
- Sir, I'll drive you right to the [tracks](#so-rails).
78
+ I'll drive you right to the [tracks](#so-rails).
79
79
 
80
80
 
81
- ## Notables changes:
81
+ ## Notable changes:
82
82
 
83
83
  * As said, no more EventMachine-based scheduler
84
84
  * ```scheduler.every('100') {``` will schedule every 100 seconds (previously, it would have been 0.1s). This aligns rufus-scheduler on Ruby's ```sleep(100)```
@@ -123,7 +123,8 @@ Yes, issues can be reported in [rufus-scheduler issues](https://github.com/jmett
123
123
  * [I want a refund](http://blog.nodejitsu.com/getting-refunds-on-open-source-projects)
124
124
  * [Passenger and rufus-scheduler](http://stackoverflow.com/questions/18108719/debugging-rufus-scheduler/18156180#18156180)
125
125
  * [Passenger and rufus-scheduler (2)](http://stackoverflow.com/questions/21861387/rufus-cron-job-not-working-in-apache-passenger#answer-21868555)
126
- * [Unicorn and rufus-scheduler](https://jkraemer.net/running-rufus-scheduler-in-a-unicorn-rails-app)
126
+ * [The scheduler comes up when running the Rails console](https://github.com/jmettraux/rufus-scheduler#avoid-scheduling-when-running-the-ruby-on-rails-console)
127
+ * [I don't get any of this, I just want it to work in my Rails application](#so-rails)
127
128
 
128
129
 
129
130
  ## scheduling
@@ -1399,6 +1400,7 @@ s = Rufus::Scheduler.singleton
1399
1400
  s.every '1m' do
1400
1401
 
1401
1402
  Rails.logger.info "hello, it's #{Time.now}"
1403
+ Rails.logger.flush
1402
1404
  end
1403
1405
  ```
1404
1406
 
@@ -1427,6 +1429,49 @@ The rufus-scheduler singleton is instantiated in the ```config/initializers/sche
1427
1429
 
1428
1430
  *Warning*: this works well with single-process Ruby servers like Webrick and Thin. Using rufus-scheduler with Passenger or Unicorn requires a bit more knowledge and tuning, gently provided by a bit of googling and reading, see [Faq](#faq) above.
1429
1431
 
1432
+ ### avoid scheduling when running the Ruby on Rails console
1433
+
1434
+ (Written in reply to https://github.com/jmettraux/rufus-scheduler/issues/186 )
1435
+
1436
+ If you don't want rufus-scheduler to kick in when running the Ruby on Rails console, you can wrap your initializer in a conditional:
1437
+
1438
+ ```ruby
1439
+ #
1440
+ # config/initializers/scheduler.rb
1441
+
1442
+ require 'rufus-scheduler'
1443
+
1444
+ s = Rufus::Scheduler.singleton
1445
+
1446
+
1447
+ unless defined?(Rails::Console)
1448
+ # only schedule when not running from the Rails on Rails console
1449
+
1450
+ s.every '1m' do
1451
+
1452
+ Rails.logger.info "hello, it's #{Time.now}"
1453
+ Rails.logger.flush
1454
+ end
1455
+ end
1456
+ ```
1457
+
1458
+ It should work for Ruby on Rails 3 and 4.
1459
+
1460
+ ### rails server -d
1461
+
1462
+ (Written in reply to https://github.com/jmettraux/rufus-scheduler/issues/165 )
1463
+
1464
+ There is the handy `rails server -d` that starts a development Rails as a daemon. The annoying thing is that the scheduler as seen above is started in the main process that then gets forked and daemonized. The rufus-scheduler thread (and any other thread) gets lost, no scheduling happens.
1465
+
1466
+ I avoid running `-d` in development mode and bother about daemonizing only for production deployment.
1467
+
1468
+ These are two well crafted articles on process daemonization, please read them:
1469
+
1470
+ * http://www.mikeperham.com/2014/09/22/dont-daemonize-your-daemons/
1471
+ * http://www.mikeperham.com/2014/07/07/use-runit/
1472
+
1473
+ If, anyway, you need something like `rails server -d`, why not try `bundle exec unicorn -D` instead? In my (limited) experience, it worked out of the box (well, had to add `gem 'unicorn'` to `Gemfile` first).
1474
+
1430
1475
 
1431
1476
  ## support
1432
1477
 
@@ -42,13 +42,13 @@ class Rufus::Scheduler
42
42
  attr_reader :hours
43
43
  attr_reader :days
44
44
  attr_reader :months
45
+ #attr_reader :monthdays # reader defined below
45
46
  attr_reader :weekdays
46
- attr_reader :monthdays
47
47
  attr_reader :timezone
48
48
 
49
49
  def initialize(line)
50
50
 
51
- raise ArgumentError.new(
51
+ fail ArgumentError.new(
52
52
  "not a string: #{line.inspect}"
53
53
  ) unless line.is_a?(String)
54
54
 
@@ -58,7 +58,7 @@ class Rufus::Scheduler
58
58
 
59
59
  @timezone = items.pop if ZoTime.is_timezone?(items.last)
60
60
 
61
- raise ArgumentError.new(
61
+ fail ArgumentError.new(
62
62
  "not a valid cronline : '#{line}'"
63
63
  ) unless items.length == 5 or items.length == 6
64
64
 
@@ -73,7 +73,7 @@ class Rufus::Scheduler
73
73
 
74
74
  [ @seconds, @minutes, @hours, @months ].each do |es|
75
75
 
76
- raise ArgumentError.new(
76
+ fail ArgumentError.new(
77
77
  "invalid cronline: '#{line}'"
78
78
  ) if es && es.find { |e| ! e.is_a?(Fixnum) }
79
79
  end
@@ -186,19 +186,6 @@ class Rufus::Scheduler
186
186
  time
187
187
  end
188
188
 
189
- if RUBY_VERSION >= '1.9'
190
- def toa(item)
191
- item == nil ? nil : item.to_a
192
- end
193
- else
194
- def toi(item); item.is_a?(String) ? item.hash.abs : item.to_i; end
195
- protected :toi
196
- def toa(item)
197
- item.is_a?(Set) ? item.to_a.sort_by { |e| toi(e) } : item
198
- end
199
- end
200
- protected :toa
201
-
202
189
  # Returns an array of 6 arrays (seconds, minutes, hours, days,
203
190
  # months, weekdays).
204
191
  # This method is used by the cronline unit tests.
@@ -228,18 +215,18 @@ class Rufus::Scheduler
228
215
 
229
216
  return brute_frequency unless @seconds && @seconds.length > 1
230
217
 
231
- delta = 60
232
218
  secs = toa(@seconds)
233
- prev = secs[0]
234
219
 
235
- secs[1..-1].each do |sec|
220
+ secs[1..-1].inject([ secs[0], 60 ]) { |(prev, delta), sec|
236
221
  d = sec - prev
237
- delta = d if d < delta
238
- end
239
-
240
- delta
222
+ [ sec, d < delta ? d : delta ]
223
+ }[1]
241
224
  end
242
225
 
226
+ # Caching facility. Currently only used for brute frequencies.
227
+ #
228
+ @cache = {}; class << self; attr_reader :cache; end
229
+
243
230
  # Returns the shortest delta between two potential occurences of the
244
231
  # schedule described by this cronline.
245
232
  #
@@ -256,16 +243,13 @@ class Rufus::Scheduler
256
243
  # Of course, this method can get VERY slow if you call on it a second-
257
244
  # based cronline...
258
245
  #
259
- # Since it's a rarely used method, I haven't taken the time to make it
260
- # smarter/faster.
261
- #
262
- # One obvious improvement would be to cache the result once computed...
263
- #
264
- # See https://github.com/jmettraux/rufus-scheduler/issues/89
265
- # for a discussion about this method.
266
- #
267
246
  def brute_frequency
268
247
 
248
+ key = "brute_frequency:#{@original}"
249
+
250
+ delta = self.class.cache[key]
251
+ return delta if delta
252
+
269
253
  delta = 366 * DAY_S
270
254
 
271
255
  t0 = previous_time(Time.local(2000, 1, 1))
@@ -285,16 +269,14 @@ class Rufus::Scheduler
285
269
  t0 = t1
286
270
  end
287
271
 
288
- delta
272
+ self.class.cache[key] = delta
289
273
  end
290
274
 
291
- protected
292
-
293
275
  def next_second(time)
294
276
 
295
- secs = @seconds.sort
277
+ secs = toa(@seconds)
296
278
 
297
- return secs.last + 60 - time.sec if time.sec > secs.last
279
+ return secs.first + 60 - time.sec if time.sec > secs.last
298
280
 
299
281
  secs.shift while secs.first < time.sec
300
282
 
@@ -303,13 +285,32 @@ class Rufus::Scheduler
303
285
 
304
286
  def prev_second(time)
305
287
 
306
- secs = @seconds.sort
288
+ secs = toa(@seconds)
289
+
290
+ return time.sec + 60 - secs.last if time.sec < secs.first
307
291
 
308
292
  secs.pop while time.sec < secs.last
309
293
 
310
294
  time.sec - secs.last
311
295
  end
312
296
 
297
+ protected
298
+
299
+ def sc_sort(a)
300
+
301
+ a.sort_by { |e| e.is_a?(String) ? 61 : e.to_i }
302
+ end
303
+
304
+ if RUBY_VERSION >= '1.9'
305
+ def toa(item)
306
+ item == nil ? nil : item.to_a
307
+ end
308
+ else
309
+ def toa(item)
310
+ item.is_a?(Set) ? sc_sort(item.to_a) : item
311
+ end
312
+ end
313
+
313
314
  WEEKDAYS = %w[ sun mon tue wed thu fri sat ]
314
315
  DAY_S = 24 * 3600
315
316
  WEEK_S = 7 * DAY_S
@@ -327,7 +328,7 @@ class Rufus::Scheduler
327
328
 
328
329
  if m = it.match(/^(.+)#(l|-?[12345])$/)
329
330
 
330
- raise ArgumentError.new(
331
+ fail ArgumentError.new(
331
332
  "ranges are not supported for monthdays (#{it})"
332
333
  ) if m[1].index('-')
333
334
 
@@ -340,7 +341,7 @@ class Rufus::Scheduler
340
341
  expr = it.dup
341
342
  WEEKDAYS.each_with_index { |a, i| expr.gsub!(/#{a}/, i.to_s) }
342
343
 
343
- raise ArgumentError.new(
344
+ fail ArgumentError.new(
344
345
  "invalid weekday expression (#{it})"
345
346
  ) if expr !~ /^0*[0-7](-0*[0-7])?$/
346
347
 
@@ -351,7 +352,7 @@ class Rufus::Scheduler
351
352
  end
352
353
  end
353
354
 
354
- weekdays = weekdays.uniq if weekdays
355
+ weekdays = weekdays.uniq.sort if weekdays
355
356
 
356
357
  [ weekdays, monthdays ]
357
358
  end
@@ -362,10 +363,12 @@ class Rufus::Scheduler
362
363
 
363
364
  r = item.split(',').map { |i| parse_range(i.strip, min, max) }.flatten
364
365
 
365
- raise ArgumentError.new(
366
+ fail ArgumentError.new(
366
367
  "found duplicates in #{item.inspect}"
367
368
  ) if r.uniq.size < r.size
368
369
 
370
+ r = sc_sort(r)
371
+
369
372
  Set.new(r)
370
373
  end
371
374
 
@@ -375,11 +378,11 @@ class Rufus::Scheduler
375
378
 
376
379
  return %w[ L ] if item == 'L'
377
380
 
378
- item = '*' + item if item.match(/^\//)
381
+ item = '*' + item if item[0, 1] == '/'
379
382
 
380
383
  m = item.match(RANGE_REGEX)
381
384
 
382
- raise ArgumentError.new(
385
+ fail ArgumentError.new(
383
386
  "cannot parse #{item.inspect}"
384
387
  ) unless m
385
388
 
@@ -393,7 +396,7 @@ class Rufus::Scheduler
393
396
  inc = m[3]
394
397
  inc = inc ? inc.to_i : 1
395
398
 
396
- raise ArgumentError.new(
399
+ fail ArgumentError.new(
397
400
  "#{item.inspect} is not in range #{min}..#{max}"
398
401
  ) if sta < min || edn > max
399
402
 
@@ -91,7 +91,7 @@ module Rufus
91
91
 
92
92
  @id = determine_id
93
93
 
94
- raise(
94
+ fail(
95
95
  ArgumentError,
96
96
  'missing block or callable to schedule',
97
97
  caller[2..-1]
@@ -235,7 +235,7 @@ module Rufus
235
235
 
236
236
  rescue StandardError => se
237
237
 
238
- raise se unless do_rescue
238
+ fail se unless do_rescue
239
239
 
240
240
  return if se.is_a?(KillSignal) # discard
241
241
 
@@ -284,7 +284,7 @@ module Rufus
284
284
  Thread.new do
285
285
 
286
286
  Thread.current[@scheduler.thread_key] = true
287
- Thread.current[:rufus_scheduler_job_thread] = true
287
+ Thread.current[:rufus_scheduler_work_thread] = true
288
288
 
289
289
  loop do
290
290
 
@@ -351,7 +351,7 @@ module Rufus
351
351
  self.class.name.split(':').last.downcase[0..-4],
352
352
  @scheduled_at.to_f,
353
353
  @next_time.to_f,
354
- opts.hash.abs
354
+ self.hash.abs
355
355
  ].map(&:to_s).join('_')
356
356
  end
357
357
 
@@ -391,7 +391,7 @@ module Rufus
391
391
  attr_reader :paused_at
392
392
 
393
393
  attr_reader :first_at
394
- attr_accessor :last_at
394
+ attr_reader :last_at
395
395
  attr_accessor :times
396
396
 
397
397
  def initialize(scheduler, duration, opts, block)
@@ -402,7 +402,7 @@ module Rufus
402
402
 
403
403
  @times = opts[:times]
404
404
 
405
- raise ArgumentError.new(
405
+ fail ArgumentError.new(
406
406
  "cannot accept :times => #{@times.inspect}, not nil or an int"
407
407
  ) unless @times == nil || @times.is_a?(Fixnum)
408
408
 
@@ -416,27 +416,34 @@ module Rufus
416
416
 
417
417
  def first_at=(first)
418
418
 
419
- return @first_at = nil if first == nil
419
+ return (@first_at = nil) if first == nil
420
420
 
421
- n = Time.now
422
- first = n + 0.003 if first == :now || first == :immediately
421
+ n0 = Time.now
422
+ n1 = n0 + 0.003
423
+
424
+ first = n0 if first == :now || first == :immediately || first == 0
423
425
 
424
426
  @first_at = Rufus::Scheduler.parse_to_time(first)
427
+ @first_at = n1 if @first_at >= n0 && @first_at < n1
425
428
 
426
- raise ArgumentError.new(
429
+ fail ArgumentError.new(
427
430
  "cannot set first[_at|_in] in the past: " +
428
431
  "#{first.inspect} -> #{@first_at.inspect}"
429
- ) if first != 0 && @first_at < n
432
+ ) if @first_at < n0
433
+
434
+ @first_at
430
435
  end
431
436
 
432
437
  def last_at=(last)
433
438
 
434
439
  @last_at = last ? Rufus::Scheduler.parse_to_time(last) : nil
435
440
 
436
- raise ArgumentError.new(
441
+ fail ArgumentError.new(
437
442
  "cannot set last[_at|_in] in the past: " +
438
443
  "#{last.inspect} -> #{@last_at.inspect}"
439
444
  ) if last && @last_at < Time.now
445
+
446
+ @last_at
440
447
  end
441
448
 
442
449
  def trigger(time)
@@ -473,7 +480,7 @@ module Rufus
473
480
  [
474
481
  self.class.name.split(':').last.downcase[0..-4],
475
482
  @scheduled_at.to_f,
476
- opts.hash.abs
483
+ self.hash.abs
477
484
  ].map(&:to_s).join('_')
478
485
  end
479
486
 
@@ -522,7 +529,7 @@ module Rufus
522
529
 
523
530
  @frequency = Rufus::Scheduler.parse_in(@original)
524
531
 
525
- raise ArgumentError.new(
532
+ fail ArgumentError.new(
526
533
  "cannot schedule #{self.class} with a frequency " +
527
534
  "of #{@frequency.inspect} (#{@original.inspect})"
528
535
  ) if @frequency <= 0
@@ -536,9 +543,12 @@ module Rufus
536
543
 
537
544
  return if is_post
538
545
 
546
+ n = Time.now
547
+
539
548
  @next_time =
540
- if @first_at == nil || @first_at < Time.now
541
- (trigger_time || Time.now) + @frequency
549
+ if @first_at == nil || @first_at < n
550
+ nt = (@next_time || trigger_time || n) + @frequency
551
+ nt > n ? nt : (trigger_time || n) + @frequency
542
552
  else
543
553
  @first_at
544
554
  end
@@ -560,7 +570,7 @@ module Rufus
560
570
 
561
571
  @interval = Rufus::Scheduler.parse_in(@original)
562
572
 
563
- raise ArgumentError.new(
573
+ fail ArgumentError.new(
564
574
  "cannot schedule #{self.class} with an interval " +
565
575
  "of #{@interval.inspect} (#{@original.inspect})"
566
576
  ) if @interval <= 0
@@ -621,7 +631,7 @@ module Rufus
621
631
 
622
632
  def next_time_from(time)
623
633
 
624
- if @first_at == nil || @first_at < time
634
+ if @first_at == nil || @first_at <= time
625
635
  @cron_line.next_time(time)
626
636
  else
627
637
  @first_at
@@ -38,7 +38,7 @@ 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
- raise(ArgumentError.new("couldn't parse \"#{o}\""))
41
+ fail(ArgumentError.new("couldn't parse \"#{o}\""))
42
42
  end
43
43
 
44
44
  def self.parse_in(o, opts={})
@@ -53,7 +53,7 @@ module Rufus
53
53
  rescue StandardError => se
54
54
 
55
55
  return nil if opts[:no_error]
56
- raise se
56
+ fail se
57
57
  end
58
58
 
59
59
  def self.parse_cron(o, opts)
@@ -63,7 +63,7 @@ module Rufus
63
63
  rescue ArgumentError => ae
64
64
 
65
65
  return nil if opts[:no_error]
66
- raise ae
66
+ fail ae
67
67
  end
68
68
 
69
69
  def self.parse_to_time(o)
@@ -72,7 +72,7 @@ module Rufus
72
72
  t = parse(t) if t.is_a?(String)
73
73
  t = Time.now + t if t.is_a?(Numeric)
74
74
 
75
- raise ArgumentError.new(
75
+ fail ArgumentError.new(
76
76
  "cannot turn #{o.inspect} to a point in time, doesn't make sense"
77
77
  ) unless t.is_a?(Time)
78
78
 
@@ -132,7 +132,7 @@ module Rufus
132
132
  m = string.match(/^(-?)([\d\.#{DURATION_LETTERS}]+)$/)
133
133
 
134
134
  return nil if m.nil? && opts[:no_error]
135
- raise ArgumentError.new("cannot parse '#{string}'") if m.nil?
135
+ fail ArgumentError.new("cannot parse '#{string}'") if m.nil?
136
136
 
137
137
  mod = m[1] == '-' ? -1.0 : 1.0
138
138
  val = 0.0
@@ -150,9 +150,7 @@ module Rufus
150
150
  elsif opts[:no_error]
151
151
  return nil
152
152
  else
153
- raise ArgumentError.new(
154
- "cannot parse '#{string}' (especially '#{s}')"
155
- )
153
+ fail ArgumentError.new("cannot parse '#{string}' (especially '#{s}')")
156
154
  end
157
155
  break unless m && m[3]
158
156
  s = m[3]
@@ -151,6 +151,7 @@ America/Argentina/Catamarca America/Indiana/Indianapolis
151
151
  America/North_Dakota/New_Salem America/Argentina/Rio_Gallegos
152
152
  America/Argentina/Buenos_Aires America/Argentina/ComodRivadavia
153
153
  ]
154
+ TIMEZONEs = TIMEZONES.collect(&:downcase)
154
155
 
155
156
  ##
156
157
  ## http://en.wikipedia.org/wiki/List_of_time_zone_abbreviations
@@ -47,13 +47,19 @@ class Rufus::Scheduler
47
47
 
48
48
  t = Time.at(@seconds)
49
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
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
+ # jump out of DST as soon as possible, jumps 1h as seen from UTC
59
+
60
+ t.hour # force t to compute itself
61
+ #
62
+ # stay in DST as long as possible, no jump seen from UTC
57
63
 
58
64
  t
59
65
  end
@@ -95,7 +101,7 @@ class Rufus::Scheduler
95
101
  begin
96
102
  DateTime.parse(str)
97
103
  rescue
98
- raise ArgumentError, "no time information in #{o.inspect}"
104
+ fail ArgumentError, "no time information in #{o.inspect}"
99
105
  end if RUBY_VERSION < '1.9.0'
100
106
 
101
107
  zone = nil
@@ -121,17 +127,23 @@ class Rufus::Scheduler
121
127
  def self.is_timezone?(str)
122
128
 
123
129
  return false if str == nil
130
+ return false if str == '*'
131
+
132
+ return false if str.index('#')
133
+ # "sun#2", etc... On OSX would go all the way to true
124
134
 
125
135
  return true if Time.zone_offset(str)
126
- return true if str == 'Zulu' || str == 'UTC'
127
136
 
128
137
  return !! (::TZInfo::Timezone.get(str) rescue nil) if defined?(::TZInfo)
129
138
 
139
+ return true if TIMEZONES.include?(str)
140
+ return true if TIMEZONEs.include?(str)
141
+
130
142
  t = ZoTime.new(0, str).time
131
143
 
132
144
  return false if t.zone == ''
133
145
  return false if t.zone == 'UTC'
134
- return false if str.match(/[a-z]/) && str.start_with?(t.zone)
146
+ return false if t.utc_offset == 0 && str.start_with?(t.zone)
135
147
  # 3 common fallbacks...
136
148
 
137
149
  return false if RUBY_PLATFORM.include?('java') && ! envtzable?(str)