Minimal UTC cron expression parser and next-occurrence calculator, backing
the native {:cron, spec} expectation trigger.
Supported syntax
Standard 5-field crontab: minute hour day-of-month month day-of-week.
*— every valuea— a single valuea-b— an inclusive rangea,b,c— a list*/n,a-b/n— steps
Day-of-week is 0..6 with Sunday = 0 (7 is also accepted as Sunday).
When both day-of-month and day-of-week are restricted (neither is *), a
timestamp matches if either field matches — the standard Vixie-cron rule.
Macros
@yearly / @annually 0 0 1 1 *
@monthly 0 0 1 * *
@weekly 0 0 * * 0
@daily / @midnight 0 0 * * *
@hourly 0 * * * *Time zone
All matching and next/2 math are in UTC. There is no time-zone or DST
handling — "0 5 * * *" means 05:00 UTC, every day.
Examples
iex> {:ok, c} = Cyclium.Cron.parse("0 5 * * *")
iex> Cyclium.Cron.next(c, ~U[2026-06-05 04:59:30Z])
~U[2026-06-05 05:00:00Z]
Summary
Functions
Returns true if dt (UTC) matches the cron expression.
First occurrence strictly after from (UTC), at second :00. Raises if no
occurrence falls within 366 days (an impossible spec, e.g. Feb 30).
Parse a cron expression (or macro) into a t/0. Returns {:error, reason}
for malformed input.
Raising variant of parse/1 — used for boot-time validation.
Types
Functions
@spec match?(t(), DateTime.t()) :: boolean()
Returns true if dt (UTC) matches the cron expression.
@spec next(t(), DateTime.t()) :: DateTime.t()
First occurrence strictly after from (UTC), at second :00. Raises if no
occurrence falls within 366 days (an impossible spec, e.g. Feb 30).
Parse a cron expression (or macro) into a t/0. Returns {:error, reason}
for malformed input.
Raising variant of parse/1 — used for boot-time validation.