PhilipAng
← All projects

Tempolite

A cron expression parser small enough to read in one sitting.

  • Rust

Tempolite parses cron expressions and tells you when they will next fire. That is the entire library.

Why write another one

The existing crates were either enormous or subtly wrong about the thing everyone gets wrong: when both day-of-month and day-of-week are restricted, cron ORs them rather than ANDing them. 0 0 1 * MON fires on the first of the month and every Monday.

The implementation

Each field compiles to a bitset, so matching is a handful of bit tests:

pub struct Schedule {
    minutes: u64,
    hours: u32,
    days_of_month: u32,
    months: u16,
    days_of_week: u8,
}

impl Schedule {
    fn matches(&self, t: &DateTime<Utc>) -> bool {
        self.minutes >> t.minute() & 1 == 1
            && self.hours >> t.hour() & 1 == 1
            && self.day_matches(t)
    }
}

Finding the next firing time steps forward a minute at a time, skipping whole months and days when their bit is clear. Not clever, but it is exact and it never loops forever.

Testing

The test suite is mostly a table of expressions and expected firing times, half of them lifted from other libraries' bug reports. Property tests assert the obvious invariant: the next firing time is always strictly in the future, and always matches.