To read a cron expression, split it into space-separated fields: minute, hour, day of month, month, day of week (Quartz adds seconds in front and a year at the end). Paste yours below and you get the exact English meaning plus its next five run times. For example, */15 9-17 * * 1-5 means "every 15 minutes, between 09:00 AM and 05:59 PM, Monday through Friday," and 0 0 * * * (also written @daily) means midnight every day.

Your expression

Advertisement

The Cron Fields

#Standard 5-fieldAllowed valuesQuartz position
1Minute0–592nd field (Quartz puts Seconds 0–59 first)
2Hour0–233rd field
3Day of month1–314th field
4Month1–12 or JAN–DEC5th field
5Day of week0–6 or SUN–SAT (0 and 7 = Sunday)6th field
6Year (optional, 1970–2099)

A job fires at every minute where all fields match simultaneously. Day names and month names (MON-FRI, JAN) work in the day-of-week and month fields; casing doesn't matter.

Special Characters, Decoded

SyntaxNameReads asExample
*Wildcardevery value in this field* * * * * — every minute
*/nStepevery n values, starting at the field's minimum*/15 — 0, 15, 30, 45
a-bRangefrom a through b, inclusive9-17 — 9am to 5:59pm
a,b,cListeach value listedMON,WED,FRI
a-b/nRanged stepevery n values inside the range0-20/2 — every 2 hours up to 8pm
LLast (Quartz)last day of month, or last given weekdayL / 6L — last day / last Friday
WWeekday (Quartz)weekday nearest the given day15W — weekday closest to the 15th
n#mNth day (Quartz)the m-th weekday n of the month2#1 — first Tuesday
?No value (Quartz)leave this field open (day fields only)0 0 12 ? * SAT
@nameNicknamecommon schedules, pre-written@daily = 0 0 * * *

Common Expressions in English

ExpressionExact meaning
*/15 * * * *Every 15 minutes
0 0 * * * / @dailyAt 12:00 AM, every day
0 9 * * MON-FRIAt 09:00 AM, Monday through Friday
0 22 * * 1-5At 10:00 PM, Monday through Friday
*/5 8-18 * * 1-5Every 5 minutes, between 08:00 AM and 06:59 PM, Monday through Friday
30 4 1,15 * *At 04:30 AM, on day 1 and 15 of the month
0 12 1 */2 *At 12:00 PM, on day 1 of the month, every 2 months
0 4 8-14 * *At 04:00 AM, between day 8 and 14 of the month
23 0-20/2 * * *At 23 minutes past the hour, every 2 hours, between 12:00 AM and 08:59 PM
0 0 12 ? * SAT,SUNAt 12:00 PM, only on Saturday and Sunday (Quartz)
0 15 10 ? * 6L 2026At 10:15 AM, on the last Saturday of the month, only in 2026 (Quartz)
*/30 * * * * *Every 30 seconds (Quartz seconds field)
@weekly / @monthly / @yearlySunday midnight / 1st of the month / January 1st

Every sentence in this table is produced by the same open-source engine (cRonstrue) that translates your expression above, so what you see here is what the tool outputs, verbatim.

How the Cron Explainer Works

Cron has a reputation for being unreadable because it packs five filters into one line and lets you mix wildcards, ranges, steps, and names per field. This tool runs two small open-source engines in your browser: cRonstrue (MIT) translates the expression into English, and croner (MIT) computes the actual next fire times by walking the calendar — the same way a scheduler would.

How the translation works

The parser splits your input on whitespace and counts fields: five means standard crontab, six or seven means Quartz (seconds first, optional year last). Nicknames like @daily expand to their canonical five-field form — @daily and @midnight become 0 0 * * *, @weekly becomes 0 0 * * 0. Each field is then described in context: a step becomes "every 15 minutes," a range becomes "between 09:00 AM and 05:59 PM" (inclusive ends, so 9-17 runs through the 5 PM hour), and day names stay names rather than becoming numbers.

A worked example: reading 0 9 * * MON-FRI, with next runs

Take the weekday-9am job. Field by field: minute 0 (top of the hour), hour 9, day-of-month * (any), month * (any), day-of-week MON-FRI — "At 09:00 AM, Monday through Friday."

Now the calendar. Counting from Monday, August 31, 2026 at 10:00 UTC, the next five runs in UTC are Tue Sep 1 09:00, Wed Sep 2 09:00, Thu Sep 3 09:00, Fri Sep 4 09:00, and — after the weekend is skipped — Mon Sep 7 09:00. That weekend skip is the proof the day-of-week filter is doing real work: a scheduler that just ran "daily at 9" would have produced Sep 5 and Sep 6 too.

One more, month-end this time: 0 12 L * * fires at noon on the last day of the month. From the same Monday, the next three runs are Aug 31 (that day, at noon), Sep 30, and Oct 31 — July has 31 days, September 30, and the engine knows which is which without anyone hard-coding a calendar table.

Building vs. reading

This tool reads expressions you've found — in a config file, a Stack Overflow answer, a colleague's crontab. If you're writing a schedule from scratch and want to compose it field by field, use the cron generator; paste its output here whenever you want to double-check what you built.

Frequently Asked Questions

What does */15 9-17 * * 1-5 mean in cron?

It means every 15 minutes, between 9:00 AM and 5:59 PM, Monday through Friday: a classic business-hours health check. Each field narrows the schedule — */15 on minutes, 9-17 on hours, * on day-of-month and month, 1-5 on day-of-week — and a job fires when every field matches at once.

How do I read a cron expression?

Split it into fields separated by spaces. The standard five are minute (0-59), hour (0-23), day of month (1-31), month (1-12), and day of week (0-6, where 0 and 7 are Sunday). Quartz adds seconds in front and optionally a year at the end, making six or seven fields. Within a field, * means any value, */n means every nth value, a-b is a range, and commas make a list. A job runs at every moment where all five fields match.

What is the difference between 5-field cron and Quartz cron?

Standard crontab has five fields. Quartz (used by Java schedulers and many cloud cron services) prefixes a seconds field and can append a year field, so expressions have six or seven parts — 0 0 12 ? * SAT,SUN runs at noon on weekends, with the seconds field pinned at 0. Quartz also adds the ? no-specific-value marker, L for last, W for nearest weekday, and # for the nth weekday of the month. This explainer accepts both formats and detects which one you pasted.

What does L mean in a cron expression?

L stands for last. In the day-of-month field, L is the last day of the month — 31 for July, 30 for September, 28 or 29 for February. In Quartz's day-of-week field, 6L is the last Friday of the month and FRIL means the last Friday. It's the reliable way to say month-end without hard-coding 28, 29, 30, or 31.

Why does my cron use ? instead of *?

Quartz forbids setting both day-of-month and day-of-week to real values, so one of them must be ? — no specific value — whenever the other is set. 0 0 12 ? * SAT,SUN means noon on Saturday and Sunday with day-of-month left open. Standard five-field cron doesn't have this rule and treats ? the same as * where it appears.

Are @daily and @midnight the same?

Yes — both expand to 0 0 * * *, midnight every day. The @ shorthand family: @hourly is 0 * * * *, @daily and @midnight are 0 0 * * *, @weekly is 0 0 * * 0 (Sunday midnight), @monthly is 0 0 1 * *, and @yearly and @annually are 0 0 1 1 *. They're conveniences in crontab files, and this explainer translates them directly.

Advertisement