Cron Expression Parser

Paste a cron expression and see what it actually means: a plain-English summary, every value each field matches, and the next five times it will fire in the timezone you choose. Reads standard 5-field cron, 6-field seconds-first expressions, and Quartz — including the ? L W # characters most generators refuse.

Try an example:

Reading an Expression You Did Not Write

Most cron problems are not authoring problems. Someone hands you a line from a crontab, a Helm chart, a Jenkins job or a Quartz trigger, and the question is not "how do I write this?" but "what did the last person mean, and is it doing that?". Decoding is a different task from generating, and it has its own failure modes: the field count is ambiguous, the day-of-week numbering depends on the format, and two of the fields interact in a way that is not obvious from reading them left to right.

This page answers the decode question directly. It enumerates every value each field matches rather than paraphrasing it, because a list of concrete numbers is impossible to misread, and it computes real timestamps so you can check the schedule against a calendar instead of against your mental model of one.

Step One: Count the Fields

Before anything else, count the space-separated fields. The count determines what the expression means, and the same string can be valid and completely different at two different lengths.

Fields Almost certainly How to read it
5 Standard Unix cron minute, hour, day of month, month, day of week. Seconds are not expressible; the job fires at second zero.
6 Seconds-first, or Quartz Genuinely ambiguous. NCRONTAB and Spring prepend a seconds field; Quartz also uses six. If the expression contains ?, L, W or #, it is Quartz — those characters exist nowhere else.
7 Quartz The seventh field is an optional year. No other common format has one.

The parser above applies exactly that rule when the format is set to auto-detect, and it tells you which reading it chose. Where the guess matters, override it with the Format control and compare the two — a six-field expression read as Quartz instead of seconds-first shifts every day-of-week digit by one.

The Day-of-Week Numbering Trap

Unix cron and NCRONTAB number the days of the week 0 to 6 with Sunday as 0, and tolerate 7 as a second spelling of Sunday. Quartz numbers them 1 to 7 with Sunday as 1. The ranges overlap, so the same digit is legal in both and means a different day.

Day Cron / NCRONTAB Quartz
SUN0 / 71
MON12
TUE23
WED34
THU45
FRI56
SAT67

A 5 means Friday in a crontab and Thursday in Quartz. A schedule copied between the two without changing the digit runs a day early or a day late, every week, silently — there is no error to catch it, because both readings are valid. The field breakdown above resolves the digit to a named day so the mismatch is visible rather than implied.

When Day-of-Month and Day-of-Week Both Apply

This is the rule that catches experienced people. In standard cron, if BOTH the day-of-month and the day-of-week field are restricted — neither is a bare asterisk — the job runs when EITHER matches, not when both do. Every other pair of fields combines with AND; these two combine with OR.

So 0 0 13 * 5 does not mean "Friday the 13th". It means "every 13th of the month, and also every Friday" — roughly five times a month rather than once or twice a year. To get Friday the 13th from cron you have to test the date inside the job itself, because the expression cannot express it. The parser flags this case explicitly whenever it applies.

Quartz avoids the ambiguity by forbidding it: exactly one of the two day fields must be ?, which means "no specific value". That is what the question mark is for, and it is why a Quartz expression always has one.

Quartz Special Characters

Quartz adds five constructs to cron that express calendar rules rather than fixed values. They cannot be flattened into a list of numbers, because what they match depends on which month the candidate date falls in. The parser evaluates them per date instead.

Character Field Meaning
? Day of month, day of week No specific value. Required in exactly one of the two day fields, and equivalent to * for matching purposes.
L Day of month, day of week Last. Alone in day-of-month it is the last day of the month; L-3 is three days before it. After a weekday in day-of-week, as in FRIL or 6L, it is the last Friday of the month.
W Day of month Nearest weekday. 15W is the weekday closest to the 15th, moving back from a Saturday and forward from a Sunday, but never across a month boundary. LW is the last weekday of the month.
# Day of week Nth occurrence. 6#3 is the third Friday of the month. If the month has no fifth occurrence, 6#5 simply does not fire that month.
2027 Year (7th field) Optional. Omitted means every year; 2027 restricts the schedule to a single year, after which it never fires again.

What "Next Run" Actually Predicts

The run times above are what the expression matches on a wall clock. They are not a promise that your scheduler will fire then, and the gap between those two things is where scheduled jobs go wrong.

A cron expression carries no timezone. It is interpreted in whatever zone the scheduler happens to run in, and that default varies: a Linux crontab uses the system zone unless CRON_TZ says otherwise, while containers, Kubernetes CronJobs, GitHub Actions and Azure Functions timer triggers default to UTC regardless of where you are. Picking the wrong zone in the control above will give you a plausible, confidently wrong answer, so set it to the zone the scheduler actually uses rather than your own.

Daylight saving makes it worse. When the clock springs forward, an hour of wall-clock time does not exist, and a job scheduled inside it may be skipped entirely; when it falls back, an hour repeats, and a job may run twice. The parser marks any predicted time that falls in a spring-forward gap, because that is a time the local calendar does not contain — but what your scheduler does with it is implementation-defined, and implementations genuinely differ. For anything where a missed or duplicated run matters, schedule in UTC, avoid the transition window, and make the job idempotent.

Finally, a match is not an execution. A timer that is already running will not overlap itself on most platforms, so a schedule tighter than the job's runtime silently skips occurrences rather than stacking them up. The expression tells you when the scheduler will consider running the job, not when the job will finish or whether it will run at all.

Worked Examples

Each of these is a real expression of the kind that turns up in review. Click any of them to load it into the parser above.

Expression What it means Worth knowing
09:00, Monday to Friday The common case, and unambiguous: only one day field is restricted, so there is no union rule to worry about.
Every 15 minutes, all day Steps anchor to the start of the range and reset each hour, so this fires at :00, :15, :30, :45 — not 15 minutes after the previous run.
Every 13th of the month, and every Friday Not Friday the 13th. Both day fields are restricted, so cron ORs them.
Every 40 minutes — except it is not Fires at :00 and :40 of every hour, so the gap between :40 and the next :00 is 20 minutes, not 40. Steps that do not divide 60 are almost always a mistake.
Noon on the third Friday of the month Quartz only. The 6 is Friday under Quartz numbering, where Sunday is 1.
Noon on the last day of every month Quartz only, and the reason L exists — no combination of numbers expresses "the last day" when months differ in length.
09:30 on weekdays, with an explicit seconds field Six fields with no Quartz characters, so it is read as seconds-first: NCRONTAB for Azure Functions, or a Spring @Scheduled cron.
Midnight every day A nickname. @hourly, @weekly, @monthly and @yearly work the same way; @reboot is the odd one out and is not a clock schedule at all.

Related Tools

If you are writing a schedule rather than decoding one, start from form controls and let the expression be built for you. Build one with the Cron Expression Generator.

Scheduled jobs usually carry a payload or a config file, and a malformed one fails at 3am rather than at review time. Check it with the JSON Formatter.

Alerting on a job's output normally comes down to a pattern that matches a failure line or pulls a duration out of a log. Build that pattern in the Regex Tester.

Correlating one scheduled run's log lines end to end needs a unique identifier per run. Generate one with the UUID Generator.

Frequently Asked Questions

What does this cron expression mean?

Paste it into the parser above and it will tell you three things: a one-line summary in plain English, the full set of values each field matches, and the next five times it fires in the timezone you select. It reads standard 5-field cron, 6-field seconds-first expressions such as NCRONTAB and Spring, and Quartz with its ?, L, W and # characters.

Does 0 0 13 * 5 mean Friday the 13th?

No. It means every 13th of the month and every Friday. In standard cron, when both the day-of-month and day-of-week fields are restricted, the job runs when either matches rather than when both do — the two day fields combine with OR while every other pair combines with AND. Cron cannot express Friday the 13th; you have to test the date inside the job itself.

How do I tell a 6-field cron expression from a Quartz expression?

Look for a character that only Quartz defines. If the expression contains ?, L, W or #, it is Quartz. If it is six plain fields using only *, comma, dash and slash, it is a seconds-first expression of the kind NCRONTAB and Spring use, where the leading field is seconds. Seven fields is always Quartz, because the trailing year field exists nowhere else.

Why does the same digit mean a different weekday in Quartz?

Unix cron and NCRONTAB number days of the week 0 to 6 with Sunday as 0, and also accept 7 for Sunday. Quartz numbers them 1 to 7 with Sunday as 1. Both ranges overlap, so a digit such as 5 is valid in either and means Friday in a crontab but Thursday in Quartz. Copying a schedule between the two without adjusting the digit shifts it by one day with no error to warn you.

What timezone do cron expressions run in?

Whatever zone the scheduler runs in — the expression itself carries none. A Linux crontab uses the system timezone unless CRON_TZ or TZ overrides it, while containers, Kubernetes CronJobs, GitHub Actions schedules and Azure Functions timer triggers default to UTC. Set the timezone control above to the zone your scheduler actually uses, not your own, or the predicted times will be confidently wrong.

What happens to a cron job during a daylight saving change?

It depends on the implementation, which is why it is worth avoiding. When clocks spring forward an hour of wall-clock time does not exist, so a job scheduled inside it may be skipped; when they fall back the hour repeats and the job may run twice. This parser marks any predicted time that falls in a spring-forward gap. For jobs where a missed or duplicated run matters, schedule in UTC, keep away from the transition window, and make the job idempotent.

What does @reboot mean and why does it have no next run?

@reboot tells cron to run the job once when the machine starts, rather than at any clock time. It is a trigger, not a schedule, so there is nothing for a parser to predict. The other nicknames — @hourly, @daily, @midnight, @weekly, @monthly, @yearly and @annually — are ordinary schedules and expand to plain expressions, which the parser shows when you enter one.