lib/fugit/cron.rb in fugit-1.1.6 vs lib/fugit/cron.rb in fugit-1.1.7
- old
+ new
@@ -41,11 +41,11 @@
end
def do_parse(s)
parse(s) ||
- fail(ArgumentError.new("not a cron string #{s.inspect}"))
+ fail(ArgumentError.new("invalid cron string #{s.inspect}"))
end
end
def to_cron_s
@@ -164,31 +164,51 @@
month_match?(t) && day_match?(t) &&
hour_match?(t) && min_match?(t) && sec_match?(t)
end
+ BREAKER_S = 41 * (365 + 1) * 24 * 3600
+ # 41 years and a few days... there wont'be a next or a previous time
+
def next_time(from=::EtOrbi::EoTime.now)
from = ::EtOrbi.make_time(from)
sfrom = from.strftime('%F/%T')
+ ifrom = from.to_i
t = TimeCursor.new(from.translate(@timezone))
#
# the translation occurs in the timezone of
# this Fugit::Cron instance
+ ti = 0
+ stalling = false
+
loop do
- (from.to_i == t.to_i) && (t.inc(1); next)
+ ti1 = t.to_i
+
+ fail RuntimeError.new(
+ "loop stalled for #{@original.inspect} #next_time, breaking"
+ ) if stalling && ti == ti1
+
+ stalling = (ti == ti1)
+ ti = ti1
+
+ fail RuntimeError.new(
+ "too many loops for #{@original.inspect} #next_time, breaking"
+ ) if (ti - ifrom).abs > BREAKER_S
+
+ (ifrom == ti) && (t.inc(1); next)
month_match?(t) || (t.inc_month; next)
day_match?(t) || (t.inc_day; next)
hour_match?(t) || (t.inc_hour; next)
min_match?(t) || (t.inc_min; next)
sec_match?(t) || (t.inc_sec(@seconds); next)
st = t.time.strftime('%F/%T')
- (from, sfrom = t.time, st; next) if st == sfrom
+ (from, sfrom, ifrom = t.time, st, t.time.to_i; next) if st == sfrom
#
# when transitioning out of DST, this prevents #next_time from
# yielding the same literal time twice in a row, see gh-6
break
@@ -201,15 +221,32 @@
end
def previous_time(from=::EtOrbi::EoTime.now)
from = ::EtOrbi.make_time(from)
+ ti = 0
+ ifrom = from.to_i
+
t = TimeCursor.new(from.translate(@timezone))
+ stalling = false
loop do
-#p [ :l, Fugit.time_to_s(t.time) ]
- (from.to_i == t.to_i) && (t.inc(-1); next)
+
+ ti1 = t.to_i
+
+ fail RuntimeError.new(
+ "loop stalled for #{@original.inspect} #previous_time, breaking"
+ ) if stalling && ti == ti1
+
+ stalling = (ti == ti1)
+ ti = ti1
+
+ fail RuntimeError.new(
+ "too many loops for #{@original.inspect} #previous_time, breaking"
+ ) if (ifrom - ti).abs > BREAKER_S
+
+ (ifrom == ti) && (t.inc(-1); next)
month_match?(t) || (t.dec_month; next)
day_match?(t) || (t.dec_day; next)
hour_match?(t) || (t.dec_hour; next)
min_match?(t) || (t.dec_min; next)
sec_match?(t) || (t.dec_sec(@seconds); next)
@@ -235,10 +272,11 @@
deltas = []
t = EtOrbi.make_time("#{year}-01-01") - 1
t0 = nil
t1 = nil
+
loop do
t1 = next_time(t)
deltas << (t1 - t).to_i if t0
t0 ||= t1
break if deltas.any? && t1.year > year
@@ -482,11 +520,11 @@
def slash(i); rex(:slash, i, /\/\d\d?/); end
def core_mos(i); rex(:mos, i, /[0-5]?\d/); end # min or sec
def core_hou(i); rex(:hou, i, /(2[0-4]|[01]?[0-9])/); end
- def core_dom(i); rex(:dom, i, /(-?(3[01]|[012]?[0-9])|last|l)/i); end
- def core_mon(i); rex(:mon, i, /(1[0-2]|0?[0-9]|#{MONTHS[1..-1].join('|')})/i); end
+ def core_dom(i); rex(:dom, i, /(-?(3[01]|[12][0-9]|0?[1-9])|last|l)/i); end
+ def core_mon(i); rex(:mon, i, /(1[0-2]|0?[1-9]|#{MONTHS[1..-1].join('|')})/i); end
def core_dow(i); rex(:dow, i, /([0-7]|#{WEEKDS.join('|')})/i); end
def dow_hash(i); rex(:hash, i, /#(-?[1-5]|last|l)/i); end
def mos(i); core_mos(i); end