← Blog

Cron expression cheat sheet (with real examples)

The five fields

A cron expression is five space-separated fields, in this order:

* * * * *
│ │ │ │ │
│ │ │ │ └── day of week (0-6, Sunday = 0)
│ │ │ └──── month (1-12)
│ │ └────── day of month (1-31)
│ └──────── hour (0-23)
└────────── minute (0-59)

* means "every value" for that field. So * * * * * runs every minute, 0 * * * * runs at the top of every hour, and 0 0 * * * runs once a day at midnight.

Common patterns

# Every 15 minutes
*/15 * * * *
 
# Every weekday at 9am
0 9 * * 1-5
 
# Every Sunday at midnight
0 0 * * 0
 
# First day of every month at 3am
0 3 1 * *
 
# Every 6 hours
0 */6 * * *

*/N means "every N units," and 1-5 is an inclusive range - both are standard and supported almost everywhere cron expressions show up (actual cron, most job schedulers, GitHub Actions' schedule trigger, etc.).

Gotchas worth knowing

  • Day-of-month and day-of-week are OR'd, not AND'd, when both are restricted. 0 0 15 * 1 doesn't mean "the 15th, if it's a Monday" - it means "the 15th of the month, OR every Monday," whichever comes first. If you actually want an AND condition, you generally need to check for it in the job itself rather than in the cron expression.
  • Timezone is almost never what you assume. Most schedulers run cron in UTC by default regardless of where you or your server are physically located - if a job runs at the "wrong" hour, this is very often why.
  • 0 0 31 * * silently skips most months. Not every month has a 31st, and most cron implementations just won't fire that month rather than rolling over to the 1st.

Pasting an expression into Cron Checker shows you the next 10 actual run times, which is a faster way to confirm what an expression really does than working it out by hand - especially once ranges and steps are combined.

Try Cron Checker - free, and it never leaves your browser.

Open Cron Checker