NAME

Cron::Toolkit - Quartz-compatible cron parser with unique extensions and over 400 tests

SYNOPSIS

use Cron::Toolkit;
use feature qw(say);

my $c = Cron::Toolkit->new(
    expression => "0 30 14 ? * 6-2 *",
    time_zone  => "Europe/London",
);

say $c->describe;
# 2:30 PM every day from Saturday to Tuesday of every month

# next occurence in epoch seconds
say $c->next;

# previous occurence in epoch seconds
say $c->previous;

# Question: when does February 29th next land on a Monday? 
say Cron::Toolkit->new(expression => "0 0 0 29 2 1 *")->next;
# Mon Feb 29 00:00:00 2044

# See exactly what was parsed
$c->dump_tree;
# ┌─ second: 0
# ├─ minute: 30
# ├─ hour:   14
# ├─ dom:    ?
# ├─ month:  *
# ├─ dow:    6-2 
# └─ year:   *

DESCRIPTION

Cron::Toolkit implements a complete, rigorously-tested cron expression parser that supports the full Quartz Scheduler syntax plus several useful extensions not found in other implementations.

Notable features include:

RELIABILITY

The distribution ships with over 400 data-driven tests covering every supported token, leap years, DST transitions, all time zones from UTC−12 to UTC+14, and every edge case discovered during development.

If it parses, the result is correct.

UNIQUE EXTENSIONS

FIELD REFERENCE & ALLOWED VALUES

Field            Allowed values         Allowed special characters 
-------------------------------------------------------------------
Second           0–59                   *,/,-                     
Minute           0–59                   *,/,-,
Hour             0–23                   *,/,-,
Day of month     1–31                   *,/,-,?,L,LW,W
Month            1–12 or JAN–DEC        *,/,-                          
Day of week      1–7 or MON-SUN         *,/,-,?,L,#
Year (optional)  1970–2099              *,/,-

Legend:
  *    wildcard
  ,    list
  -    range
  /    step
  ?    no specific value (DOM or DOW only)
  L    last (day or day-of-week)
  L-n  n to last day of the month
  nL   last n-day of the month 
  LW   last weekday of month
  nW   nearest weekday to n
  #    nth day-of-week (e.g. 3#2 = 2nd Wednesday)

@aliases: @yearly @annually @monthly @weekly @daily @hourly (Quartz standard)

METHODS

TIME ZONES AND DST

All calculations are performed in the configured time zone. DST transitions follow Quartz Scheduler rules exactly:

BUGS AND CONTRIBUTIONS

The test suite currently contains over 400 data-driven tests covering every supported token, DST transitions, leap years, all time zones, and many edge cases — but real-world cron expressions can be surprisingly creative.

If you find:

...please file a bug report at https://github.com/nathanielgraham/cron-toolkit-perl/issues

Pull requests with failing test cases are especially welcome — they are the fastest way to get a fix merged.

Feature requests (e.g. more natural-language locales, RRULE export, etc.) are also very much appreciated.

Thank you!

AUTHOR

Nathaniel Graham

COPYRIGHT AND LICENSE

Copyright 2025 Nathaniel Graham

This library is free software; you may redistribute it and/or modify it under the same terms as Perl itself.