Skip to main content

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.

  1. `0 0 13 * 5` reads like "midnight on Friday the 13th"
  2. both day fields are restricted, so cron ORs them
  3. it actually runs on the 13th of every month AND every Friday โ€” about 64 times a year, not once or twice
  4. `0 0 */7 * *` reads like "every seven days"
  5. 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.