The usual cron expression has five fields, separated by spaces:
┌───── minute (0-59)
│ ┌───── hour (0-23)
│ │ ┌───── day of month (1-31)
│ │ │ ┌───── month (1-12)
│ │ │ │ ┌───── day of week (0-6, 0 = Sunday)
│ │ │ │ │
* * * * *
The crucial part: the five fields are combined with AND. A moment triggers the job only when all five match it.
What each field accepts
| Syntax | Meaning | Example |
|---|---|---|
* | Any value | * in the hour field = every hour |
5 | A specific value | 5 in minutes = the 5th minute of each hour |
1-5 | A range | 1-5 in day of week = Monday to Friday |
1,15 | A list | 1,15 in day of month = the 1st and the 15th |
*/10 | A step | */10 in minutes = every 10 minutes |
9-17/2 | A step inside a range | In hours = every 2 hours between 09:00 and 17:00 |
A few expressions you will actually meet
0 * * * * every hour, on the hour
*/5 * * * * every 5 minutes
0 3 * * * every day at 03:00
0 3 * * 0 every Sunday at 03:00
0 0 1 * * the 1st of every month at midnight
30 9 * * 1-5 weekdays at 09:30
0 */6 * * * every 6 hours
The trap: day-of-month OR day-of-week
This is the least intuitive rule in cron. When both day-of-month and day-of-week are restricted — neither is * — most implementations, including Vixie cron and essentially every Linux distribution, treat them as an OR, not an AND.
0 0 1 * 1
Intuition says "midnight on the 1st of the month, when it is also a Monday". The actual meaning is "the 1st of the month, or any Monday". To express the AND you have to set one field to * and filter inside the job itself.
This rule catches a fresh batch of people every year, particularly on billing and reporting jobs where the date matters.
The other trap: time zones
Cron uses the server's local time zone. The same configuration deployed to two different regions can fire hours apart. On the day a daylight-saving transition happens, jobs inside the skipped hour may not run at all.
If timing matters, either standardise your servers on UTC and do the arithmetic yourself, or move to a scheduler that lets you name a time zone explicitly.
How to check what you wrote
The quickest way is to look at when it will actually run. The cron expression tool reads your expression back as a plain sentence and lists the next eight trigger times — the expression above reveals its real behaviour immediately.