lib/rufus/scheduler/cronline.rb in rufus-scheduler-3.2.2 vs lib/rufus/scheduler/cronline.rb in rufus-scheduler-3.3.0

- old
+ new

@@ -34,10 +34,11 @@ class CronLine # The string used for creating this cronline instance. # attr_reader :original + attr_reader :original_timezone attr_reader :seconds attr_reader :minutes attr_reader :hours attr_reader :days @@ -51,14 +52,19 @@ fail ArgumentError.new( "not a string: #{line.inspect}" ) unless line.is_a?(String) @original = line + @original_timezone = nil items = line.split - @timezone = items.pop if ZoTime.is_timezone?(items.last) + if @timezone = ZoTime.get_tzone(items.last) + @original_timezone = items.pop + else + @timezone = ZoTime.get_tzone(:current) + end fail ArgumentError.new( "not a valid cronline : '#{line}'" ) unless items.length == 5 or items.length == 6 @@ -75,22 +81,30 @@ fail ArgumentError.new( "invalid cronline: '#{line}'" ) if es && es.find { |e| ! e.is_a?(Fixnum) } end + + if @days && @days.include?(0) # gh-221 + + fail ArgumentError.new('invalid day 0 in cronline') + end end # Returns true if the given time matches this cron line. # def matches?(time) - time = ZoTime.new(time.to_f, @timezone || ENV['TZ']).time + # FIXME Don't create a new ZoTime if time is already a ZoTime in same + # zone ... + # Wait, this seems only used in specs... + t = ZoTime.new(time.to_f, @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 date_match?(time) + return false unless sub_match?(t, :sec, @seconds) + return false unless sub_match?(t, :min, @minutes) + return false unless sub_match?(t, :hour, @hours) + return false unless date_match?(t) true end # Returns the next time that this cron line is supposed to 'fire' # @@ -117,75 +131,75 @@ # 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(from=Time.now) + def next_time(from=ZoTime.now) - time = nil - zotime = ZoTime.new(from.to_i + 1, @timezone || ENV['TZ']) + nt = nil + zt = ZoTime.new(from.to_i + 1, @timezone) loop do - time = zotime.time + nt = zt.dup - unless date_match?(time) - zotime.add((24 - time.hour) * 3600 - time.min * 60 - time.sec) + unless date_match?(nt) + zt.add((24 - nt.hour) * 3600 - nt.min * 60 - nt.sec) next end - unless sub_match?(time, :hour, @hours) - zotime.add((60 - time.min) * 60 - time.sec) + unless sub_match?(nt, :hour, @hours) + zt.add((60 - nt.min) * 60 - nt.sec) next end - unless sub_match?(time, :min, @minutes) - zotime.add(60 - time.sec) + unless sub_match?(nt, :min, @minutes) + zt.add(60 - nt.sec) next end - unless sub_match?(time, :sec, @seconds) - zotime.add(next_second(time)) + unless sub_match?(nt, :sec, @seconds) + zt.add(next_second(nt)) next end break end - time + nt end # Returns the previous time the cronline matched. It's like next_time, but # for the past. # def previous_time(from=Time.now) - time = nil - zotime = ZoTime.new(from.to_i - 1, @timezone || ENV['TZ']) + pt = nil + zt = ZoTime.new(from.to_i - 1, @timezone) loop do - time = zotime.time + pt = zt.dup - unless date_match?(time) - zotime.substract(time.hour * 3600 + time.min * 60 + time.sec + 1) + unless date_match?(pt) + zt.substract(pt.hour * 3600 + pt.min * 60 + pt.sec + 1) next end - unless sub_match?(time, :hour, @hours) - zotime.substract(time.min * 60 + time.sec + 1) + unless sub_match?(pt, :hour, @hours) + zt.substract(pt.min * 60 + pt.sec + 1) next end - unless sub_match?(time, :min, @minutes) - zotime.substract(time.sec + 1) + unless sub_match?(pt, :min, @minutes) + zt.substract(pt.sec + 1) next end - unless sub_match?(time, :sec, @seconds) - zotime.substract(prev_second(time)) + unless sub_match?(pt, :sec, @seconds) + zt.substract(prev_second(pt)) next end break end - time + pt end # Returns an array of 6 arrays (seconds, minutes, hours, days, # months, weekdays). # This method is mostly used by the cronline specs. @@ -198,11 +212,11 @@ toa(@hours), toa(@days), toa(@months), toa(@weekdays), toa(@monthdays), - @timezone + @timezone.name ] end alias to_array to_a # Returns a quickly computed approximation of the frequency for this @@ -258,11 +272,13 @@ loop do break if delta <= 1 break if delta <= 60 && @seconds && @seconds.size == 1 +#st = Time.now t1 = next_time(t0) +#p Time.now - st d = t1 - t0 delta = d if d < delta break if @months == nil && t1.month == 2 break if t1.year >= 2001 @@ -312,11 +328,10 @@ end end WEEKDAYS = %w[ sun mon tue wed thu fri sat ] DAY_S = 24 * 3600 - WEEK_S = 7 * DAY_S def parse_weekdays(item) return nil if item == '*' @@ -429,16 +444,18 @@ end r.uniq end + # FIXME: Eventually split into day_match?, hour_match? and monthdays_match?o + # def sub_match?(time, accessor, values) - value = time.send(accessor) - return true if values.nil? + value = time.send(accessor) + if accessor == :day values.each do |v| return true if v == 'L' && (time + DAY_S).day == 1 return true if v.to_i < 0 && (time + (1 - v) * DAY_S).day == 1 @@ -448,51 +465,34 @@ if accessor == :hour return true if value == 0 && values.include?(24) end - values.include?(value) - end + if accessor == :monthdays - def monthday_match?(date, values) + return true if (values & value).any? + end - return true if values.nil? - - today_values = monthdays(date) - - (today_values & values).any? + values.include?(value) end - def date_match?(date) +# def monthday_match?(zt, values) +# +# return true if values.nil? +# +# today_values = monthdays(zt) +# +# (today_values & values).any? +# end - return false unless sub_match?(date, :day, @days) - return false unless sub_match?(date, :month, @months) - return false unless sub_match?(date, :wday, @weekdays) - return false unless monthday_match?(date, @monthdays) - true - end + def date_match?(zt) - def monthdays(date) - - pos = 1 - d = date.dup - - loop do - d = d - WEEK_S - break if d.month != date.month - pos = pos + 1 - end - - neg = -1 - d = date.dup - - loop do - d = d + WEEK_S - break if d.month != date.month - neg = neg - 1 - end - - [ "#{date.wday}##{pos}", "#{date.wday}##{neg}" ] + return false unless sub_match?(zt, :day, @days) + return false unless sub_match?(zt, :month, @months) + return false unless sub_match?(zt, :wday, @weekdays) + #return false unless monthday_match?(zt, @monthdays) + return false unless sub_match?(zt, :monthdays, @monthdays) + true end end end