Skip to content
FindTool

    Cron Expression Parser

    Explain any cron expression in plain English and list its upcoming run times.

    Cron Expression Parser tool

    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.