Crontab expression explainer
Paste a cron expression. Read what it actually does, and when it actually runs.
Try: every 15 minutes · nightly at 02:00 · weekday mornings · first of the month · the confusing one · @weekly
Monitor this schedule Get told when a run does not happen. Free for ten monitors.
Everything above happens in your browser. The expression is not sent to this server, is not logged and is not stored — a crontab line describes somebody's infrastructure, and it is not ours to collect.
How to read the five fields
┌───────── minute 0–59
│ ┌─────── hour 0–23
│ │ ┌───── day of month 1–31
│ │ │ ┌─── month 1–12 or JAN–DEC
│ │ │ │ ┌─ day of week 0–7 or SUN–SAT (0 and 7 are both Sunday)
│ │ │ │ │
0 2 * * * → every day at 02:00
Within a field: * is every value, 5 is exactly five, 1-5 is a range, 1,15 is a list, and */10 is every tenth value. 5/15 means "from 5 to the end of the field, every 15".
The rule almost everyone gets wrong
When both the day-of-month and the day-of-week fields are restricted, cron runs the job if either matches — not both. 0 0 13 * 5 is not "Friday the 13th". It is "every 13th of the month, and every Friday", which is about 65 days a year rather than one or two.
If one of the two is *, the other simply applies, which is why 0 9 * * 1-5 behaves the way you expect. Try both in the box above and watch the run list change.
Things that catch people out
- The timezone is the machine's, not yours. Servers are usually UTC. Check with
timedatectl. GitHub Actions is always UTC and has no setting. Kubernetes uses the controller-manager's zone unless the CronJob setsspec.timeZone. - A
%becomes a newline. In a crontab, an unescaped%ends the command and the rest becomes standard input.date +%Fhas to be writtendate +\%F. This one silently truncates the command. - Clock changes. In a zone that observes daylight saving, a daily job in the skipped hour does not have a real time to run at on that day. The run list marks those.
- Six fields is a different dialect. Quartz, Spring and n8n accept a leading seconds field. Standard crontab does not, and the same digits mean different things in each.
Knowing it actually ran
A correct expression is not the same as a job that runs. The crontab can be right while the machine is off, the entry is on a host that was rebuilt, the script exits non-zero, or the schedule is on a branch GitHub never looks at. Cron does not tell you about any of that.
Add one line to the job and Vivere tells you when a run does not happen:
0 2 * * * /srv/app/backup.sh && curl -fsS -m 10 --retry 3 -o /dev/null https://vivere.dev/p/<your-monitor-id>
What to check when a cron job stops running · How late should you let it be?