PlayTools

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

  1. Use absolute paths; cron runs with a minimal environment and a short PATH.
  2. Redirect output to a log: >> /var/log/job.log 2>&1.
  3. Prevent overlapping runs with a lock: flock -n /tmp/job.lock command.
  4. Make jobs safe to re-run (idempotent), so a duplicate run after a DST change or a retry does no harm.
  5. 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

  1. Read the plain-English description the cron generator produces, and check it says what you mean.
  2. Temporarily schedule the job a few minutes ahead and confirm it runs once, with the expected user and environment.
  3. 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.

Tools used in this guide