Mojar::Cron - Cron-style datetime patterns and algorithm


  use Mojar::Cron;
  my $c = Mojar::Cron->new(is_local => 1, pattern => '0 9 * * mon');
  my $t = time;
  $t = $c->next($t);  # next instance of 9am Monday
  say "Need to wait another $t seconds."


A time pattern is a sequence of six components: second, minute, hour, day, month, weekday (the component for 'second' may be omitted for brevity and consistency with standard cron syntax) and supports @-expressions in the weekday component. Each of the first four components consists of a comma-separated list of patterns.


The 'month' component can use those patterns, but may also use English prefices in place of numbers.

  apr-jun,oct-dec  # instead of 4-6,10-12

The 'weekday' component can do similarly.

  mon-fri  # instead of 1-5
  mon,wed,fri  # instead of 1,3,5

(Note that this implementation also supports 'wrap around' patterns such as fri-mon and oct-mar.)

In keeping with standard cron, a time pattern may specify sequences for both day and weekday in the same pattern. This can cause confusion because the pattern is satisfied if either sequence is satisfied.

  00 00 00 01  * mon  # midnight on the first of each month and also each Monday

The weekday component may use @-expressions, but in this case the 'day' and 'month' components must be unspecified.

  00 00 00  *  * @mon#1      # first Monday of each month
  00 00 16  *  * @5#L        # last Friday of each month
  00 00 16  *  * @week#L     # last week day (Mon-Fri) of each month
  00 00 03  *  * @weekend#1  # first weekend day (Sat-Sun) of each month

There are also special expressions which can replace the whole time pattern.

  00 01 00  *  * *  # @nightly
  00 01 06  *  * *  # @morningly
  00 01 12  *  * *  # @daily
  00 01 18  *  * *  # @eveningly

Cron patterns of the kind */n have a weakness that they only specify jumps within their sequence. For example the 'day' pattern */15 will trigger on 1st, 16th, 31st January and then again on 1st February; the pattern resets at the end of its sequence (month days). This might not be what you expect or want, so we also have yearday patterns. These have the same behaviour, but because they don't reset till the end of the year, they get closer to what people expect.

  00 00 00  *  * :*/2  # every two days through the year







For consistency with cron, patterns are one-based for day and month, but internally (using Mojar::Cron::Datetime) everything is zero-based. So when debugging your code [0,0,0,0,0,0] would be '1900-01-01 00:00:00' and [[0],[0],[0],undef,undef,[1]] would be '00 00 00 * * 1'.


The main algorithm is thanks to Paul Evans ( I hope I have implemented it in a readable way, and it turns out doing so revealed several bugs in the original.

Copyright (C) 2012, Paul Evans.

Copyright (C) 2012--2016, Nic Sandfield.

This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0.


Algorithm::Cron (Paul has merged in bugfixes I sent.)