lib/rufus/sc/cronline.rb in rufus-scheduler-2.0.8 vs lib/rufus/sc/cronline.rb in rufus-scheduler-2.0.9

- old
+ new

@@ -41,10 +41,11 @@ attr_reader :minutes attr_reader :hours attr_reader :days attr_reader :months attr_reader :weekdays + attr_reader :monthdays attr_reader :timezone def initialize(line) super() @@ -65,11 +66,11 @@ @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]) + @weekdays, @monthdays = parse_weekdays(items[4 + offset]) end # Returns true if the given time matches this cron line. # def matches?(time) @@ -79,13 +80,11 @@ 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) + return false unless date_match?(time) true end # Returns the next time that this cron line is supposed to 'fire' # @@ -162,30 +161,51 @@ @minutes, @hours, @days, @months, @weekdays, + @monthdays, @timezone ? @timezone.name : nil ] end private - WDS = %w[ sun mon tue wed thu fri sat ] - # used by parse_weekday() + WEEKDAYS = %w[ sun mon tue wed thu fri sat ] def parse_weekdays(item) - item = item.downcase + return nil if item == '*' - WDS.each_with_index { |day, index| item = item.gsub(day, index.to_s) } + items = item.downcase.split(',') - r = parse_item(item, 0, 7) + weekdays = nil + monthdays = nil - r.is_a?(Array) ? - r.collect { |e| e == 7 ? 0 : e }.uniq : - r + items.each do |it| + + if it.match(/#[12345]$/) + + raise ArgumentError.new( + "ranges are not supported for monthdays (#{it})" + ) if it.index('-') + + (monthdays ||= []) << it + else + + WEEKDAYS.each_with_index { |a, i| it.gsub!(/#{a}/, i.to_s) } + + its = it.index('-') ? parse_range(it, 0, 7) : [ Integer(it) ] + its = its.collect { |i| i == 7 ? 0 : i } + + (weekdays ||= []).concat(its) + end + end + + weekdays = weekdays.uniq if weekdays + + [ weekdays, monthdays ] end def parse_item(item, min, max) return nil if item == '*' @@ -253,15 +273,38 @@ def sub_match?(value, values) values.nil? || values.include?(value) end + def monthday_match(monthday, monthdays) + + return true if monthdays == nil + return true if monthdays.include?(monthday) + 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) + return false unless sub_match?(CronLine.monthday(date), @monthdays) true + end + + DAY_IN_SECONDS = 7 * 24 * 3600 + + def self.monthday(date) + + count = 1 + date2 = date.dup + + loop do + date2 = date2 - DAY_IN_SECONDS + break if date2.month != date.month + count = count + 1 + end + + "#{WEEKDAYS[date.wday]}##{count}" end end end