lib/rufus/sc/cronline.rb in rufus-scheduler-2.0.6 vs lib/rufus/sc/cronline.rb in rufus-scheduler-2.0.7
- old
+ new
@@ -20,82 +20,75 @@
# THE SOFTWARE.
#
# Made in Japan.
#++
+require 'tzinfo'
+
module Rufus
#
# A 'cron line' is a line in the sense of a crontab
# (man 5 crontab) file line.
#
class CronLine
- #
# The string used for creating this cronline instance.
#
attr_reader :original
- attr_reader \
- :seconds,
- :minutes,
- :hours,
- :days,
- :months,
- :weekdays
+ attr_reader :seconds
+ attr_reader :minutes
+ attr_reader :hours
+ attr_reader :days
+ attr_reader :months
+ attr_reader :weekdays
+ attr_reader :timezone
- def initialize (line)
+ def initialize(line)
super()
@original = line
items = line.split
- unless items.length == 5 or items.length == 6
- raise(
- "cron '#{line}' string should hold 5 or 6 items, not #{items.length}")
- end
+ @timezone = (TZInfo::Timezone.get(items.last) rescue nil)
+ items.pop if @timezone
+ raise ArgumentError.new(
+ "not a valid cronline : '#{line}'"
+ ) unless items.length == 5 or items.length == 6
+
offset = items.length - 5
@seconds = offset == 1 ? parse_item(items[0], 0, 59) : [ 0 ]
@minutes = parse_item(items[0 + offset], 0, 59)
@hours = parse_item(items[1 + offset], 0, 24)
@days = parse_item(items[2 + offset], 1, 31)
@months = parse_item(items[3 + offset], 1, 12)
@weekdays = parse_weekdays(items[4 + offset])
end
- #
# Returns true if the given time matches this cron line.
#
- def matches? (time)
+ def matches?(time)
time = Time.at(time) unless time.kind_of?(Time)
+ time = @timezone.utc_to_local(time.getutc) if @timezone
+
return false unless sub_match?(time.sec, @seconds)
return false unless sub_match?(time.min, @minutes)
return false unless sub_match?(time.hour, @hours)
return false unless sub_match?(time.day, @days)
return false unless sub_match?(time.month, @months)
return false unless sub_match?(time.wday, @weekdays)
true
end
- #
- # Returns an array of 6 arrays (seconds, minutes, hours, days,
- # months, weekdays).
- # This method is used by the cronline unit tests.
- #
- def to_array
-
- [ @seconds, @minutes, @hours, @days, @months, @weekdays ]
- end
-
- #
# Returns the next time that this cron line is supposed to 'fire'
#
# This is raw, 3 secs to iterate over 1 year on my macbook :( brutal.
# (Well, I was wrong, takes 0.001 sec on 1.8.7 and 1.9.1)
#
@@ -105,61 +98,84 @@
# Note that the time instance returned will be in the same time zone that
# the given start point Time (thus a result in the local time zone will
# be passed if no start time is specified (search start time set to
# Time.now))
#
- # >> Rufus::CronLine.new('30 7 * * *').next_time( Time.mktime(2008,10,24,7,29) )
- # => Fri Oct 24 07:30:00 -0500 2008
+ # Rufus::CronLine.new('30 7 * * *').next_time(
+ # Time.mktime(2008, 10, 24, 7, 29))
+ # #=> Fri Oct 24 07:30:00 -0500 2008
#
- # >> Rufus::CronLine.new('30 7 * * *').next_time( Time.utc(2008,10,24,7,29) )
- # => Fri Oct 24 07:30:00 UTC 2008
+ # Rufus::CronLine.new('30 7 * * *').next_time(
+ # Time.utc(2008, 10, 24, 7, 29))
+ # #=> Fri Oct 24 07:30:00 UTC 2008
#
- # >> Rufus::CronLine.new('30 7 * * *').next_time( Time.utc(2008,10,24,7,29) ).localtime
- # => Fri Oct 24 02:30:00 -0500 2008
+ # Rufus::CronLine.new('30 7 * * *').next_time(
+ # Time.utc(2008, 10, 24, 7, 29)).localtime
+ # #=> Fri Oct 24 02:30:00 -0500 2008
#
# (Thanks to K Liu for the note and the examples)
#
- def next_time (time=Time.now)
+ def next_time(now=Time.now)
- time -= time.usec * 1e-6
- time += 1
+ time = @timezone ? @timezone.utc_to_local(now.getutc) : now
+ time = time - time.usec * 1e-6 + 1
+ # little adjustment before starting
+
loop do
unless date_match?(time)
time += (24 - time.hour) * 3600 - time.min * 60 - time.sec
next
end
-
unless sub_match?(time.hour, @hours)
time += (60 - time.min) * 60 - time.sec
next
end
-
unless sub_match?(time.min, @minutes)
time += 60 - time.sec
next
end
-
unless sub_match?(time.sec, @seconds)
time += 1
next
end
break
end
+ if @timezone
+ time = @timezone.local_to_utc(time)
+ time = time.getlocal unless now.utc?
+ end
+
time
end
+ # Returns an array of 6 arrays (seconds, minutes, hours, days,
+ # months, weekdays).
+ # This method is used by the cronline unit tests.
+ #
+ def to_array
+
+ [
+ @seconds,
+ @minutes,
+ @hours,
+ @days,
+ @months,
+ @weekdays,
+ @timezone ? @timezone.name : nil
+ ]
+ end
+
private
WDS = %w[ sun mon tue wed thu fri sat ]
- #
# used by parse_weekday()
- def parse_weekdays (item)
+ def parse_weekdays(item)
item = item.downcase
WDS.each_with_index { |day, index| item = item.gsub(day, index.to_s) }
@@ -168,11 +184,11 @@
r.is_a?(Array) ?
r.collect { |e| e == 7 ? 0 : e }.uniq :
r
end
- def parse_item (item, min, max)
+ def parse_item(item, min, max)
return nil if item == '*'
return parse_list(item, min, max) if item.index(',')
return parse_range(item, min, max) if item.index('*') or item.index('-')
@@ -182,18 +198,18 @@
i = max if i > max
[ i ]
end
- def parse_list (item, min, max)
+ def parse_list(item, min, max)
item.split(',').inject([]) { |r, i|
r.push(parse_range(i, min, max))
}.flatten
end
- def parse_range (item, min, max)
+ def parse_range(item, min, max)
i = item.index('-')
j = item.index('/')
return item.to_i if (not i and not j)
@@ -233,18 +249,19 @@
result
end
def sub_match?(value, values)
+
values.nil? || values.include?(value)
end
def date_match?(date)
+
return false unless sub_match?(date.day, @days)
return false unless sub_match?(date.month, @months)
return false unless sub_match?(date.wday, @weekdays)
true
end
end
-
end