Cron expressions explained, field by field
· 6 min read
Cron syntax is five numbers and some punctuation, and almost everyone reaches for a reference every single time. Here is the whole thing in one page, including the two rules that cause most of the surprises.
The five fields
A standard cron entry is minute, hour, day-of-month, month, day-of-week — in that order. So 30 2 * * * is "02:30 every day", and 0 9 1 * * is "09:00 on the first of the month".
The ranges are: minute 0-59, hour 0-23, day-of-month 1-31, month 1-12 (or JAN-DEC), day-of-week 0-7 where both 0 and 7 mean Sunday (or SUN-SAT). An asterisk means "every value".
Ranges, steps and lists
Three operators cover nearly everything you will write. A range uses a hyphen: 9-17 in the hour field means every hour from nine to five. A list uses commas: 1,15 in day-of-month means the first and the fifteenth. A step uses a slash: */15 in the minute field means every fifteenth minute — 0, 15, 30, 45.
They combine. 0 9-17/2 * * 1-5 reads as "at minute zero, every second hour between 09:00 and 17:00, Monday to Friday". Steps apply to whatever precedes them, so 9-17/2 steps within the range rather than across the whole field.
The day-of-month and day-of-week trap
This is the rule that catches everyone. When both day-of-month and day-of-week are restricted — neither is an asterisk — cron treats them as OR, not AND.
So 0 0 13 * 5 does not mean "Friday the 13th". It means "every 13th of the month, and also every Friday". If you want the intersection you have to test for it inside the job itself, because cron cannot express it. When only one of the two fields is restricted, it behaves the way you would expect.
Time zones will bite you
Cron runs in the time zone of whatever is running it. Your laptop is probably local time; your server is probably UTC; a Kubernetes CronJob is UTC unless you set spec.timeZone. A schedule that reads "9am" on your machine may fire at 4am in production.
Daylight saving is the follow-on problem. A job scheduled at 02:30 local time will run twice on the day the clocks go back and not at all on the day they go forward. If the job is not idempotent, schedule it in UTC or outside the 01:00-03:00 window.
Verify before you deploy
The slowest way to check a cron expression is to deploy it and wait. Paste it into a parser instead: a good one turns the expression into a sentence and lists the next several fire times, which catches an off-by-one field almost immediately.
Toolbit has both directions — a parser that explains an existing expression, and a visual builder that assembles one from the schedule you actually want. Both run in the browser, so a schedule containing internal job names stays private.
Frequently asked questions
- What does */5 * * * * mean?
- Every five minutes, at minutes 0, 5, 10 and so on through 55, every hour of every day.
- How do I schedule a job for the last day of the month?
- Standard cron cannot express it. Some implementations add an L character; otherwise the usual approach is to run daily and exit early unless tomorrow is the first.
- What is the sixth field I sometimes see?
- A leading seconds field, used by Quartz and several application-level schedulers. Unix crontab itself only has five fields.
Tools mentioned in this post
- Cron Expression Parser Translate a cron expression into plain English and preview the next run times. Runs locally in your browser with no…
- Crontab Generator Build a cron expression visually with a live plain-English preview and upcoming run times. Runs locally in your…
- Timestamp Converter Convert Unix timestamps to human-readable dates and back, in seconds or milliseconds, across time zones. Runs locally…