Reading a cron expression
A cron expression is five fields, left to right: minute (0–59),
hour (0–23), day-of-month (1–31), month
(1–12 or JAN–DEC) and day-of-week (0–7 or SUN–SAT — 0 and 7 are both Sunday).
A * means "every value"; a list (1,15) picks several; a range
(9-17) picks a span; and a step (*/5, 9-17/2) picks every
Nth value. Put together, 0 3 * * 1-5 reads "at 03:00 on Monday through Friday" and
*/5 * * * * is simply "every 5 minutes".
The one rule that trips up nearly everyone is the day-of-month / day-of-week OR.
When both fields are restricted, standard (Vixie) cron runs the job when either matches:
0 0 1 * MON fires on the 1st of every month and on every Monday — not just on
Mondays that happen to be the 1st. If either field is *, only the other constrains
the day. This explainer flags the OR case whenever your expression triggers it, because a job that
quietly runs four extra times a month is exactly the kind of surprise you want to catch on this
page rather than in production.
Two smaller gotchas worth knowing. Shortcuts like @daily and @hourly are
fine — they expand to plain five-field schedules — but @reboot has no schedule at all,
and 6-field expressions with a leading seconds field belong to Quartz or systemd timers, not
crontab. And daylight-saving time can genuinely skip or repeat a wall-clock hour: a job at
02:30 simply doesn’t run on the night clocks spring forward, which is why the run times above are
computed in your timezone rather than naively added in UTC.
Here is the uncomfortable part: even a perfect expression tells you nothing about whether the job
ran. Cron fails silently — a broken PATH, an expired credential, a full disk or a server
that never came back from a reboot, and the backup you thought was running nightly quietly stopped
months ago. We wrote up
why cron jobs fail silently and how to catch it;
the short version is to
give this job a heartbeat —
it pings a unique URL on success, and CompleteStatus alerts you the moment a ping goes missing.
Set one up free — it takes about a minute, which is less time
than you just spent decoding the expression.