Calculate next scheduled time based on cron spec

Parand picture Parand · Jan 6, 2011 · Viewed 8.9k times · Source

What's an efficient way to calculate the next run time of an event given the current time and a cron spec?

I'm looking for something other than "loop through every minute checking if it matches spec".

Examples of specs might be:

  • Every month, on the 1st and 15 at 15:01
  • At 10,20,30,40,50 mins past the hour every hour

Python code would be lovely but psuedo code or high level description would also be appreciated.

[Update] Assume the spec is already parsed and is in some reasonable format.

Answer

Hugh Bothwell picture Hugh Bothwell · Jan 6, 2011

Just looking at it, I think you need to:

  • parse the chron spec to five arrays containing acceptable values for each field;
  • parse 'now' to a value for each field;
  • in order of minute, hour, {day-of-month OR day-of-week}, month-of year: find the lowest array value that matches or exceeds the current value, correcting for carry.

I don't know how to handle day-of-week and day-of-month simultaneously; I am sure there is a way, but on the other hand I don't think I've ever seen a spec that actually specified both. I think it would be sufficient to write a handler for either and throw an error if you receive both.

Edit: apparently if day-of-week and day-of-month are both specified, it is supposed to fire on both - ie if the rule is '15th, Wednesday' it will fire on every 15th and every Wednesday.

The croniter package does what you want:

import croniter
import datetime

now = datetime.datetime.now()
sched = '1 15 1,15 * *'    # at 3:01pm on the 1st and 15th of every month
cron = croniter.croniter(sched, now)

for i in range(4):
    nextdate = cron.get_next(datetime.datetime)
    print nextdate

prints

2011-01-15 15:01:00
2011-02-01 15:01:00
2011-02-15 15:01:00
2011-03-01 15:01:00

although it would be nice if it were written as an actual iterator. Maybe I've got my next project ;-)