Cron Expression Reference — All Five Fields, Steps, Names and @-Shortcuts
Every cron field explained — minute, hour, day-of-month, month, day-of-week — lists, ranges, steps, JAN–DEC/SUN–SAT names, ? and @-shortcuts.
A cron schedule is five fields and a command:
┌─────────── minute 0–59
│ ┌───────── hour 0–23
│ │ ┌─────── day of month 1–31
│ │ │ ┌───── month 1–12 (or JAN–DEC)
│ │ │ │ ┌─── day of week 0–7 (or SUN–SAT; 0 and 7 are both Sunday)
│ │ │ │ │
* * * * * command to run
Each field independently filters time: the job fires when the current minute, hour, month, and the day rule all match. The day rule — how day-of-month and day-of-week combine — is the famous trap covered in its own article. Here’s every other field, precisely.
The four things every field accepts
| syntax | meaning | example expansion (minute field) |
|---|---|---|
* |
every allowed value | 0–59 |
a |
a single value | 30 → {30} |
a,b,c |
a list | 0,15,30,45 → {0,15,30,45} |
a-b |
an inclusive range | 9-17 → 9 through 17 |
*/n |
every n-th value | */15 → {0,15,30,45} |
a-b/n |
every n-th inside a range | 2-30/5 → {2,7,12,17,22,27} |
a/n |
start at a, step to the max | 1/5 → {1,6,11,…,56} |
A few details that bite in practice:
- Steps count from the range start, not from 0.
2-30/5gives 2, 7, 12 — not 5, 10, 15.*/15is shorthand for0-59/15(or the field’s real minimum —*/2in day-of-month starts at 1, not 0). - Ranges don’t wrap.
17-9andfri-monare invalid — cron wants low-to-high. To span a boundary, use a list:fri,sat,sun,monor22,23,0,1. */0is meaningless — a step of zero gets rejected.- Lists deduplicate silently.
5,5,5is just{5}— harmless but a sign the line was machine-generated.
Month and day-of-week names
The last two fields accept three-letter English names, case-insensitive, anywhere a number would go:
0 9 * jan mon 09:00 on Mondays in January
0 0 * mar-jun fri midnight on Fridays, March–June
0 8 * * mon,wed,fri 08:00 on Monday, Wednesday, Friday
mon in the minute field is an error — names live only in fields 4 and 5. Day-of-week numbers run 0 = Sunday through 6 = Saturday, with 7 as a second Sunday, so 5-7 is a legal Fri–Sun weekend span and 1-5 is the classic weekday range. SAT alone is 6; there’s no “weekend” keyword, you write 0,6 or sat,sun.
? — the Quartz-ism standard cron tolerates
In Quartz-derived schedulers (AWS EventBridge, Spring’s @Scheduled, some CI systems) one of the two day fields must be ? — “no specific value”. Standard cron doesn’t have the character at all; * already covers it. This calculator accepts ? in day-of-month and day-of-week as an alias for * so pasted Quartz expressions don’t silently change meaning — but if you’re writing a real crontab, use *.
What standard cron can’t say (and how Quartz does it)
| Quartz syntax | means | standard cron equivalent |
|---|---|---|
L in dom |
last day of month | no syntax — guard with [ "$(date -d tomorrow +\%d)" = "01" ] on 28-31 |
5L in dow |
last Friday | guard: [ "$(date -d '+7 days' +\%m)" != "$(date +\%m)" ] on 5 |
15W |
nearest weekday to the 15th | no clean equivalent — compute outside cron |
5#3 |
3rd Friday | 0 0 15-21 * 5 + the weekday check below |
0 0 * * * 2026 |
year field | not supported — cron lines have no year |
For “nth weekday”, the portable pattern is restricting the day-of-month to the only week it can fall in, then confirming the weekday in the command (necessary anyway because of the OR rule — see below):
# 3rd Friday of the month, 00:00 — fires only when both agree
0 0 15-21 * 5 [ "$(date +\%u)" -eq 5 ] && my-backup-job
The @-shortcuts
crontab also accepts seven nickname lines that replace all five fields:
| shortcut | expands to | fires |
|---|---|---|
@yearly, @annually |
0 0 1 1 * |
Jan 1, 00:00 |
@monthly |
0 0 1 * * |
1st of each month, 00:00 |
@weekly |
0 0 * * 0 |
Sundays, 00:00 |
@daily, @midnight |
0 0 * * * |
every day, 00:00 |
@hourly |
0 * * * * |
top of every hour |
@reboot |
(none) | once, when the cron daemon starts |
@reboot is the odd one — it has no schedule and can’t appear with fields. It fires when cron starts (boot, or systemctl restart cron), which is why the calculator shows no “next runs” for it: there is no next time, there’s a next boot.
Field-by-field cheat sheet
| field | range | names | gotchas |
|---|---|---|---|
| minute | 0–59 | — | */n counts from 0 |
| hour | 0–23 | — | 24h clock; 0 is midnight, 12 noon |
| day of month | 1–31 | — | no 0; missing days (Feb 30/31) skip silently or never fire |
| month | 1–12 | JAN–DEC | names case-insensitive |
| day of week | 0–7 | SUN–SAT | 0 and 7 = Sunday; OR-combines with dom |
Two closing reminders the calculator above enforces rather than assumes: a day-of-month that can’t exist in the selected months means the job never runs (0 0 31 2 *), and a schedule like 0 0 29 2 * runs but can wait four — or around non-leap century years like 2100, eight — years between firings.
Frequently asked questions
Is */15 the same as 0,15,30,45?
Yes — */15 expands to exactly those minutes. The two forms are interchangeable; */15 is just shorter. Same for */2 in the day-of-week field: it means days 0, 2, 4, 6 — Sun, Tue, Thu, Sat.
What does "1/5" mean (a number with a step but no range)?
Vixie cron reads it as 1-max/5 — start at 1 and step to the top of the field, so 1/5 in the minute field = 1, 6, 11, …, 56. Quartz's a/b means the same thing. If you want a bounded range, write it out: 1-30/5.
Can I mix names and numbers in one field?
Yes — jan,3,jul-sep and mon,wed-fri,0 are both legal. Names are case-insensitive and work inside lists and ranges, in the month and day-of-week fields only.
Is Sunday 0 or 7?
Both — standard cron accepts 0 and 7 for Sunday, including inside ranges (5-7 = Friday, Saturday, Sunday). 1 is always Monday. Be careful the other way: 0-6 covers a whole week, so */2 and 0-6/2 give the same days.
Why doesn't my "L" expression work in crontab?
L (last day / last weekday), W (nearest weekday) and # (nth weekday) are Quartz-scheduler extensions — standard 5-field cron has no syntax for any of them. Cronie will reject the line or ignore it, depending on version. Emulate them with a guard in the command — examples below.
What's the difference between @daily and @midnight?
Nothing — both expand to 0 0 * * *. The seven standard nicknames are @yearly/@annually, @monthly, @weekly, @daily/@midnight, @hourly and @reboot.