Cron expressions explained, with examples and gotchas
A cron expression is five fields that say when to run something. It reads easily once you know the order; what surprises people is a handful of rules, such as what happens when you set both a day of the month and a weekday. The syntax, examples to copy and the usual traps.
The five fields
A standard cron line has five time fields, followed by the command. Per the crontab(5) manual page, the fields and their allowed values are:
| Position | Field | Allowed values |
|---|---|---|
| 1 | minute | 0–59 |
| 2 | hour | 0–23 |
| 3 | day of month | 1–31 |
| 4 | month | 1–12 (or names) |
| 5 | day of week | 0–7 (0 or 7 is Sunday, or use names) |
The command runs when the minute, hour and month fields match the current time, and the day condition is met (more on that below). cron examines its entries every minute, so the smallest unit is one minute: there is no seconds field in this syntax.
The special characters
*means "every value" ("first to last").,makes a list:1,15is the 1st and the 15th.-makes an inclusive range:8-11in the hour field is 8, 9, 10 and 11./adds a step to a range or to*:*/5is every 5 units, and0-23/2in the hour field is every other hour.
Names work for months and days of week (the first three letters, in any case: jan, mon…). The crontab(5) page also allows ranges and lists of names such as mon,wed,fri, but some older implementations do not, so numbers are the safer choice.
Examples you can copy
| Expression | Runs |
|---|---|
*/15 * * * * | every 15 minutes (at :00, :15, :30, :45) |
0 * * * * | at the top of every hour |
0 9 * * 1-5 | at 09:00, Monday to Friday |
0 9-17 * * * | every hour on the hour from 09:00 to 17:00 inclusive |
0 */2 * * * | every two hours on the hour (00:00, 02:00 … 22:00) |
5 4 * * 0 | at 04:05 every Sunday |
0 0 1 * * | at midnight on the 1st of every month |
0 0 1 1 * | at midnight on 1 January |
To check what an expression you inherited actually means, paste it into the cron expression explainer: it translates it into plain language and lists the next run times, which is the quickest way to catch an expression that does not do what you thought.
Gotcha 1: day of month and day of week are OR, not AND
This one catches almost everyone. If you restrict both the day-of-month and the day-of-week fields (neither is *), the command runs when either matches. The crontab(5) page gives an example: 30 4 1,15 * 5 runs at 04:30 on the 1st and 15th of each month plus every Friday, not only on Fridays that fall on the 1st or 15th. If you want "the first Friday of the month", cron cannot express it directly: schedule it for every Friday and have the script check that the day is 7 or less.
Gotcha 2: steps restart; they do not "carry over"
*/7 in the minute field means minutes 0, 7, 14 … 56, and then it starts again at 0 in the next hour, so the gap between 56 and 0 is only 4 minutes. A step only gives an even interval when it divides the range exactly: */5, */10, */15 and */30 do for minutes; */7 does not. The manual makes the same point with hours: steps are evaluated just within the field, so */23 in the hour field means hour 0 and hour 23 of each day, not "every 23 hours".
Gotcha 3: "last day of the month" does not exist
Months have 28 to 31 days, and standard cron has no "last day" token. The usual workaround is to run daily (0 0 * * *) and have the command check whether tomorrow is the 1st before doing the work. Also remember that in a crontab, an unescaped % in the command is turned into a newline, so a date +%d inside it has to be written as date +\%d.
Gotcha 4: time zones and daylight saving time
cron uses the system's local time unless told otherwise (some implementations accept a CRON_TZ variable). That matters on the nights the clocks change. The crontab(5) manual says it plainly: non-existent times, such as the "missing hour" during the daylight saving conversion, will never match, so jobs scheduled in that hour are not run, and times that occur more than once will cause matching jobs to run twice. Put important jobs outside the 01:00–03:00 window, or run the machine on UTC. For a rundown of when clocks change, see the guide to clock-change dates, and use the time zone converter to translate a schedule into the server's time.
Gotcha 5: not every scheduler speaks the same dialect
The five-field form above is the classic Unix one. Other systems differ. GitHub Actions uses POSIX cron syntax with five fields, runs scheduled workflows in UTC by default (you can optionally give an IANA time zone), runs them on the latest commit of the default branch, and does not allow a shorter interval than every 5 minutes. Others, such as Quartz-style schedulers, add a seconds field (and sometimes a year), shifting every position by one. Always check which dialect your tool uses before copying an expression from somewhere else.
A short checklist before you ship a schedule
- Read it back in words, or use the explainer, and check the next five run times.
- If you set both day-of-month and day-of-week, confirm you really want OR.
- Avoid
* * * * *unless you truly need every minute. - Decide the time zone on purpose, and keep jobs away from the daylight-saving hour.
- Make the job safe to run twice, because sooner or later it will.
Sources and further reading
- man7.org: crontab(5), the cron table file format
- GitHub Docs: schedule event and POSIX cron syntax in workflows
Figures checked on 3 October 2026.
Do it now, free, in your browser. Your files are not uploaded.
Build a cron schedule and see what it means and when it will run next.
Frequently asked questions
What do the five fields of a cron expression mean?
How do I run a cron job every 5 minutes?
What happens if I set both day of month and day of week?
Does cron run jobs during the daylight saving time change?
What time zone does cron use?
Can cron run every second?
Related guides
Tools used in this guide
They run in your browser, so nothing is uploaded.