Cron Syntax Explained: 20 Schedules You Can Copy, and the Traps to Avoid
Developers · Updated October 2, 2026 · 4 min read
Cron has scheduled Unix jobs since the 1970s, and its five-field syntax now drives CI pipelines, Kubernetes CronJobs and cloud schedulers. It is compact and powerful, and a handful of its rules surprise even experienced engineers.
The five fields
┌──────── minute 0–59 │ ┌────── hour 0–23 │ │ ┌──── day of month 1–31 │ │ │ ┌── month 1–12 (or JAN–DEC) │ │ │ │ ┌ day of week 0–6, Sunday = 0 (or SUN–SAT; many systems accept 7 for Sunday) │ │ │ │ │ * * * * * command
Each field accepts * (any value), a number, a list (1,15), a range (9-17), or a step (*/15, or 0-30/10 for a stepped range).
Copy-ready schedules
*/5 * * * * every 5 minutes 0 * * * * every hour, on the hour 15 * * * * every hour at :15 0 */6 * * * every 6 hours (00:00, 06:00, 12:00, 18:00) 0 0 * * * daily at midnight 30 2 * * * daily at 02:30 0 9 * * 1-5 weekdays at 09:00 */15 9-17 * * 1-5 every 15 min in office hours (last run 17:45) 0 9,13,17 * * * at 09:00, 13:00 and 17:00 0 0 * * 0 Sundays at midnight 0 8 * * 1 Mondays at 08:00 0 0 1 * * first day of every month 0 0 15 * * 15th of every month 0 0 1 1 * once a year, 1 January 0 0 1 */3 * quarterly: Jan, Apr, Jul, Oct 0 22 * * 5 Fridays at 22:00 0 3 * * 6,0 weekends at 03:00 45 23 * * * daily at 23:45 0 12 1-7 * 1 12:00 on the 1st–7th AND every Monday (see below) @reboot once at boot (Vixie cron extension)
The cron generator builds these from dropdowns and describes the schedule in plain English before you deploy it.
The day-of-month OR day-of-week rule
When both day fields are restricted, standard cron runs the job if either matches — not both. 0 12 1-7 * 1 does not mean “the first Monday of the month”; it runs at noon on the 1st to the 7th and on every Monday. To run only on the first Monday, schedule 0 12 1-7 * * and have the script exit unless today is Monday ([ "$(date +%u)" = 1 ] || exit 0).
The same trick covers “last day of the month”, which standard cron cannot express: run daily on the 28th–31st and exit unless tomorrow is the 1st.
Time zones and daylight saving
- System crontab uses the server’s local time zone. Servers set to UTC avoid daylight-saving surprises entirely.
- In a zone with DST, a job at 02:30 may be skipped on the spring-forward night or run twice on the fall-back night, depending on the cron implementation.
- GitHub Actions schedules always run in UTC and may start late when the platform is busy; the shortest allowed interval is every 5 minutes.
- Kubernetes CronJobs accept a timeZone field, so a schedule can follow local business hours explicitly.
Dialects
- Quartz and Spring use six or seven fields with seconds first, and ? for “no specific value” in one of the day fields.
- AWS EventBridge uses six fields including a year, requires ? in one day field, and evaluates in UTC unless you use EventBridge Scheduler with a time zone.
- Some systems support L (last), W (nearest weekday) and # (nth weekday) — useful, but not portable to standard cron.
Making jobs reliable
- Use absolute paths; cron runs with a minimal environment and a short PATH.
- Redirect output to a log: >> /var/log/job.log 2>&1.
- Prevent overlapping runs with a lock: flock -n /tmp/job.lock command.
- Make jobs safe to re-run (idempotent), so a duplicate run after a DST change or a retry does no harm.
- Alert on failure — and on silence: a monitoring check that expects a heartbeat catches jobs that stopped running altogether.
systemd timers: an alternative on Linux
On modern Linux distributions, systemd timers can replace crontab entries. A timer unit uses OnCalendar= expressions such as Mon..Fri 09:00 or *-*-01 00:00, logs every run to the journal, and with Persistent=true runs a missed job at the next boot — something classic cron does not do. Timers also make it easy to add a random delay so that many machines do not hit a server at the same moment.
Testing a schedule before you rely on it
- Read the plain-English description the cron generator produces, and check it says what you mean.
- Temporarily schedule the job a few minutes ahead and confirm it runs once, with the expected user and environment.
- Check the logs or the CI run history the next day — and again after the next daylight-saving change if the server uses local time.
Spreading the load
Thousands of systems run jobs at exactly 00:00 or on the hour, which creates traffic spikes for shared services and APIs. Picking an unusual minute — 0 3 becomes 17 3 — avoids the rush. Jenkins supports an H symbol that spreads jobs automatically based on a hash of the job name, and systemd timers offer RandomizedDelaySec. For jobs that call third-party APIs, a little randomness also makes rate limits less likely.
Where crontabs live
- crontab -e edits the current user’s schedule and crontab -l lists it; jobs run as that user.
- System files in /etc/crontab and /etc/cron.d/ have an extra field after the five time fields: the user to run the command as.
- Directories such as /etc/cron.daily run scripts at a time chosen by the system, often via anacron, which also catches up on jobs missed while the machine was off.
- Container platforms usually do not run a cron daemon inside the container — use the platform’s scheduler instead.