Five fields, left to right
A cron expression is five space-separated fields — minute, hour, day-of-month, month, day-of-week — each naming which values of that unit make the schedule fire this tick. Take */15 9-17 * * MON-FRI: the minute field */15 expands to 0, 15, 30 and 45; the hour field 9-17 expands to every hour from 9 through 17; day-of-month and month are both left as *, matching everything; and MON-FRI narrows the day-of-week field to Monday through Friday. Put together, that's every 15 minutes, from 9am to 5pm, Monday to Friday — a typical business-hours job.
| Field | Position | Range | * means |
|---|---|---|---|
| Minute | 1st | 0–59 | every minute |
| Hour | 2nd | 0–23 | every hour |
| Day of month | 3rd | 1–31 | every day of the month |
| Month | 4th | 1–12 or JAN–DEC | every month |
| Day of week | 5th | 0–7 (0 and 7 both mean Sunday) or SUN–SAT | every day of the week |
A step counts from where the range starts, not from zero
9-17/4 reads as "every 4th hour starting at 9, up to 17" — 9, 13, 17. A bare */4 is different: with no explicit start, it steps from the field's minimum, so */4 on the hour field is 0, 4, 8, 12, 16, 20. The two forms look similar but answer different questions — one steps through a slice of the field starting where you told it to, the other steps through the whole field from its own zero.
* steps from the field's own zero, and a range steps from that range's own start. 9-17/4 and */4 on the same field land on entirely different hours.The rule everyone gets backwards: day fields are OR'd, not AND'd
Cron ANDs every field against every other — except day-of-month and day-of-week: those two OR together whenever neither day field is *. 0 0 13 * FRI fires at midnight on the 13th of the month or on any Friday — not on a Friday that happens to be the 13th. Walk it forward from 1 January 2026: the schedule fires Friday 2 January, Friday 9 January, then the 13th itself (a Tuesday, matched purely on day-of-month), then Friday 16 January, and on. Only when one of the two fields is * does the rule collapse back to something that reads like AND: 0 0 * * FRI leaves day-of-month as *, so the OR has nothing on the other side, and the schedule is simply every Friday.
Time zone: what it changes, and the two days it complicates
A cron expression names a wall-clock time, not a fixed instant — 30 9 * * * means "9:30, in whichever zone you tell it," and picking a different zone changes which moment in UTC that resolves to while leaving the local reading untouched. Run that expression against 1 January 2026 in Asia/Ho_Chi_Minh and the first match lands at 02:30 UTC; run the identical expression in America/New_York and it lands at 14:30 UTC — twelve hours apart, both reading 09:30 on the wall clock they were asked about.
Two days a year make that resolution genuinely awkward, and only in a zone that observes DST. On 8 March 2026, clocks in America/New_York jump from 01:59 straight to 03:00, so 02:30 never happens that day — a daily job set for 30 2 * * * simply has no run on the 8th, then resumes on the 9th as normal. On 1 November 2026 the same zone falls back an hour, so 01:30 happens twice; a daily 30 1 * * * job still lists it once, resolved to the earlier of the two passes.