Cron Expression Parser
Explain any cron expression in plain English and list its upcoming run times.
Cron Expression Parser tool
| Field | Value | Allowed range | Meaning |
|---|
What this tool does
You have inherited a crontab, or found a schedule in a Helm chart, and you need to know what it does before you touch it. Paste it here for four answers: what each field restricts, a sentence summarising the whole thing, the next ten times it fires, and a warning when the expression contains the one rule that makes cron behave unlike every other scheduler.
Five-field crontab, six-field Quartz or node-cron with seconds, seven-field Quartz with a
year, names, ranges, steps, lists and the @ macros are all understood.
Common uses
- Auditing a legacy crontab before a migration, to find jobs that overlap or never run.
- Answering "why did this fire at 3am on a Sunday" during an incident review.
- Reviewing a pull request that changes a schedule, where the diff is five characters.
- Confirming a month-end-sensitive job actually has a run date.
A short example
0 0 13 * 5
Field Value Meaning
minute 0 0
hour 0 0
day of month 13 the 13th
month * every month
day of week 5 Friday Read casually, that says "midnight on Friday the 13th". It does not. It fires at midnight on the 13th of every month, and at midnight on every Friday — more than sixty times a year. Paste it above and watch the run list prove it.
The OR rule, and why it exists
When both day fields are restricted — that is, when neither begins with * —
cron matches a day if either field matches, not both. Vixie cron, which almost
every Linux distribution ships, records a flag per field at parse time and applies exactly
this logic; the behaviour is documented in man 5 crontab and required by
POSIX.
There is a reason. "The 1st and every Monday" is a schedule people want; "the 1st, but
only when it is a Monday" fires twice a year and nobody asks for it. The escape hatch is
that a field beginning with a star is exempt, so 0 0 1 * * fires only on the
1st and 0 0 * * 1 only on Mondays. */2 also counts as beginning
with a star: 0 0 */2 * 1 is ANDed, firing only on odd-numbered Mondays.
Worth knowing
An expression says when a job is due, not when it runs. If the machine is asleep
at the due time, classic cron simply misses it — anacron exists to catch up
on daily jobs afterwards, and systemd timers have Persistent=true for the
same reason. If a run is still going when the next is due, plain cron starts a second
copy, which is how a slow nightly job turns into a thundering herd; Kubernetes CronJobs
expose concurrencyPolicy to prevent it. And * * * * * is the
shortest interval cron can express: for anything faster you need a long-running process.
Frequently asked questions
Why does my schedule run more often than expected?
When both day-of-month and day-of-week are restricted (neither is *), cron treats them as OR, not AND. 0 0 1 * 1 runs on the 1st of the month and every Monday, which surprises almost everyone the first time.
My expression has six fields. Which one is extra?
It depends on the scheduler, and the two conventions sit at opposite ends. Quartz and Spring’s @Scheduled put seconds first, so 0 0 12 * * ? is noon daily. AWS EventBridge instead appends a year after the five standard fields and requires ? in exactly one of the two day fields. Pasting an expression from one into the other shifts every field by one position, and it usually still parses — which is why it reaches production.
Why does a step like */7 not fire every seven days?
Because a step counts across its own field’s range and restarts when the field does, rather than measuring an interval. */7 in day-of-month fires on the 1st, 8th, 15th, 22nd and 29th, then begins again at the 1st — a gap of two or three days across the month boundary, not seven. The same applies to */40 in minutes, which fires at :00 and :40 and then waits only twenty minutes. For a true fixed interval you need a scheduler that supports one, or a job that records its own last run.