How a cron expression works
A cron expression is five fields separated by spaces. Each field says which values of one unit of time a job may run at, and the job runs every minute where all five agree. The order is always the same:
| Field | Allowed values | Example |
|---|---|---|
| Minute | 0 to 59 | 30: at half past |
| Hour | 0 to 23 | 9: 9 in the morning |
| Day of month | 1 to 31 | 1: the 1st |
| Month | 1 to 12 or JAN to DEC | 6: June |
| Day of week | 0 to 7 or SUN to SAT | 1: Monday |
Sunday is both 0 and 7. Names are case-insensitive, so mon and MON are the same.
Special characters
*matches every value of the field.,separates a list:1,15in the day-of-month field is the 1st and the 15th.-is an inclusive range:1-5in the day-of-week field is Monday through Friday./is a step:*/10in the minute field is 0, 10, 20, 30, 40 and 50. Steps work on ranges too, so9-17/2in the hour field is 9, 11, 13, 15 and 17.
That's the whole standard syntax. Characters like ?, L, W and # come from Quartz and Spring, which also add a seconds field at the front (and sometimes a year at the end). Plain cron rejects them; this tool tells you when it sees them.
Macros
Most cron versions accept a few shortcuts in place of the five fields:
@yearlyor@annually:0 0 1 1 *, midnight on January 1.@monthly:0 0 1 * *, midnight on the 1st.@weekly:0 0 * * 0, midnight on Sunday.@dailyor@midnight:0 0 * * *.@hourly:0 * * * *.@reboot: once, when the cron daemon starts. It has no schedule, so there are no next runs to show.
The day-of-month and day-of-week rule
This is the one that surprises people. If both day fields are restricted, cron runs on days that match either of them, not both.0 0 13 * 5 runs on every 13th and on every Friday, not only on Friday the 13th.
If either field starts with *, the usual AND applies. That includes steps like */2, so 0 0 */2 * 1 runs on odd days that are also Mondays. The tool flags the OR case under the description and counts it in the next runs.
Timezones
Cron has no timezone of its own: it uses the local time of the machine it runs on. A server set to UTC runs 0 9 * * * at 09:00 UTC, which may be the middle of the night for you. Some versions, including cronie, read a CRON_TZ=Europe/Rome line at the top of a crontab to run jobs in another zone.
GitHub Actions schedules always run in UTC, and so do most cloud schedulers unless you pick a timezone. Use the UTC toggle above to see when those will fire. Around daylight saving changes, local times can be skipped or repeated: a 02:30 job may not run on the night the clocks go forward.
Common gotchas
- Day 31 doesn't exist in every month, and
0 0 30 2 *(February 30) never runs at all. - Steps restart at each boundary.
*/7in the minute field runs at 0, 7 … 56 and then at 0 again, so two runs are only 4 minutes apart. - In a crontab line,
%means a newline. Escape it as\%inside commands such asdate +\%F. - Cron runs jobs with a minimal environment and
PATH. Use full paths to commands, and redirect output to a log while testing. - A file in
/etc/cron.dor/etc/crontabhas a sixth field, the user, between the schedule and the command.
FAQ
How do I run a cron job every 5 minutes?
Use */5 * * * *. The */5 in the minute field means every minute divisible by 5 (0, 5, 10 and so on up to 55), and the four stars mean every hour, day, month and weekday.
What does */15 mean in cron?
It's a step: start at the lowest value of the field and take every 15th one. In the minute field that's minutes 0, 15, 30 and 45. A step also works on a range, so 9-17/2 in the hour field means 9, 11, 13, 15 and 17.
What timezone does cron use?
Classic cron uses the server's local time, set by the system timezone. Some versions (cronie, for example) read a CRON_TZ line in the crontab to run jobs in another zone. GitHub Actions schedules and most cloud schedulers run in UTC unless you set a timezone explicitly.
Why didn't my cron job run on the 31st?
Day 31 only exists in seven months, so 0 0 31 * * skips February, April, June, September and November. For the last day of every month, run on days 28 to 31 and have the command check that tomorrow is the 1st, or use a scheduler that supports L.
Why does my job run on more days than I expected?
When both the day-of-month and day-of-week fields are restricted, cron runs on days that match either one. 0 0 13 * 5 runs on every 13th and on every Friday, not only on Friday the 13th.