Build a cron expression from plain options โ no syntax to memorise.
Cron expression
0 2 * * *Daily โ 02:00
Understanding the five fields
A cron expression has five fields in a fixed order: minute, hour, day of month, month, and day of week. An asterisk means "every value", a number pins an exact value, and */N means "every N". So 30 2 * * 1 runs at 02:30 every Monday.
Two details catch people out. Day of week counts Sunday as 0 (and 7 in most implementations), so Monday is 1. And if you set both day of month and day of week, most cron daemons run the job when either matches, not both โ so keep one of them as an asterisk unless you really want that behaviour.
Why `0 0 13 * 5` does not mean Friday the 13th
A cron expression is five fields describing when a command runs. Most of it is obvious once you have seen it. Two things are not: how the day fields combine, and what a step value actually steps through. Both quietly produce schedules that fire far more often than intended.
How it works
- Builds the five-field expression โ minute, hour, day of month, month, day of week โ from plain choices.
- Shows the next firing times, which is the only reliable way to confirm an expression means what you think.
- Makes the day-of-month and day-of-week interaction visible instead of leaving it to be discovered in production.
โโ minute 0โ59 โ โโ hour 0โ23 โ โ โโ day of month 1โ31 โ โ โ โโ month 1โ12 โ โ โ โ โโ day of week 0โ6 (Sunday = 0) * * * * * if day-of-month AND day-of-week are both restricted, cron runs on EITHER
Worked example
Two expressions that almost everyone reads wrongly the first time.
- `0 0 13 * 5` reads like "midnight on Friday the 13th"
- both day fields are restricted, so cron ORs them
- it actually runs on the 13th of every month AND every Friday โ about 64 times a year, not once or twice
- `0 0 */7 * *` reads like "every seven days"
- the step applies within the 1โ31 range, giving the 1st, 8th, 15th, 22nd and 29th
The second expression resets each month, so the gap from the 29th to the next 1st is three days in a 31-day month โ not seven. Neither expression is weekly. `0 0 * * 5` is how you say every Friday.
Reading the result
- The OR rule only applies when both day fields are restricted. If either is `*`, the other behaves normally โ which is why the trap stays hidden until someone fills in both.
- Steps always count from the start of the range, not from today. `*/7` in a field beginning at 1 lands on 1, 8, 15, 22, 29 regardless of what day you deployed it.
- Cron uses the system or daemon timezone. A job set for 02:30 may run twice or not at all on the days clocks change; scheduling outside 01:00โ03:00 avoids the question entirely.
- `0` and `7` both mean Sunday in the day-of-week field on most implementations, and month and day names like `MON` or `JAN` are widely but not universally supported.
Common questions
- How do I actually schedule something every seven days?
- Use a weekday: `0 0 * * 5` for every Friday. If you genuinely need a fixed seven-day interval independent of the calendar, cron is the wrong tool โ a job that reschedules itself, or a timer unit with a monotonic interval, expresses that properly.
- What runs on the 31st in a short month?
- Nothing. Cron does not roll over to the 1st, so `0 0 31 * *` silently skips February, April, June, September and November. For end-of-month work, schedule the 1st and look backwards.