Cron Syntax Cheat Sheet

Cron expressions look the same everywhere until they do not: Linux crontab, Quartz, Spring, AWS EventBridge and GitHub Actions each read the fields slightly differently. This reference covers the shared core and every place the dialects diverge.

The five standard 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)
│ │ │ │ │
* * * * *  command

This is the format of Vixie cron and cronie on Linux, of macOS cron, Kubernetes CronJobs and GitHub Actions. Month and weekday names are case-insensitive three-letter abbreviations. Some older cron implementations reject names inside ranges or lists, so numbers (1-5 rather than MON-FRI) are the most portable choice for crontab files that must run anywhere.

Operators

  • * — every value of the field
  • , — a list: 0,30 means minute 0 and minute 30
  • - — an inclusive range: 9-17 is 09 through 17
  • / — a step: */15 in the minute field is 0, 15, 30, 45; 5-59/15 is 5, 20, 35, 50

Steps count from the start of the range and restart for every larger unit, which has two consequences. */7 in the day-of-month field gives the 1st, 8th, 15th, 22nd and 29th, then starts again on the 1st of the next month — not “every seven days”. And intervals that do not divide 60 or 24 evenly, like every 90 minutes, cannot be written as one expression.

Ranges must run from low to high. An overnight window such as 22:00 to 06:00 is written as a list: 22-23,0-5.

The day-of-month / day-of-week OR rule

When both day fields are restricted (neither is *), standard cron runs the job when either matches. 0 0 13 * 5 does not mean “Friday the 13th”; it means every 13th of the month and every Friday. If only one day field is restricted, only that one applies.

To get “Friday the 13th” in standard cron, restrict one field and test the other in the command, for example 0 0 13 * * [ "$(date +\%u)" = 5 ] && /path/to/job. Quartz-style schedulers avoid the ambiguity by requiring ? in one of the two fields.

Macros

Vixie cron, cronie and many libraries accept shortcuts in place of the five fields:

  • @reboot — once, when the cron daemon starts
  • @yearly or @annually — 0 0 1 1 *
  • @monthly — 0 0 1 * *
  • @weekly — 0 0 * * 0 (Sunday at midnight)
  • @daily or @midnight — 0 0 * * *
  • @hourly — 0 * * * *

Not every scheduler understands them; Kubernetes accepts most of them, while GitHub Actions and AWS do not. Library-specific forms such as @every 5m (from Go’s robfig/cron) are not cron at all.

Six and seven fields: seconds and years

Six fields with seconds first — second minute hour day-of-month month day-of-week — are used by Spring’s @Scheduled(cron = ...), node-cron and several other libraries. 0 */10 * * * * is every ten minutes on the zero second.

Quartz uses six or seven fields: seconds, minutes, hours, day of month, month, day of week and an optional year. Two differences catch people out:

  • day of week runs 1–7 starting on Sunday, so 2 is Monday and 6 is Friday
  • one of the two day fields must be ? (“no specific value”): 0 0 12 ? * MON-FRI

AWS EventBridge rules use six fields with no seconds — minutes, hours, day of month, month, day of week, year — wrapped as cron(0 12 ? * MON-FRI *), with Quartz-style ? and 1–7 Sunday-first weekdays.

Special characters: L, W, # and ?

These come from Quartz and are supported by Quartz, EventBridge, Spring and many libraries — but not by classic Vixie cron or cronie, which reject them.

  • L in day of month — the last day of the month: 0 0 L * *. Quartz also accepts offsets such as L-3 for the third-to-last day.
  • L after a weekday — the last such weekday of the month: 5L is the last Friday in 0–6 numbering (6L in Quartz numbering).
  • W — the weekday (Monday–Friday) nearest the given day, without crossing into another month: 15W. LW is the last weekday of the month.
  • # — the nth occurrence of a weekday: 5#3 is the third Friday with Sunday = 0, while in Quartz the same day is 6#3.
  • ? — no specific value, allowed only in the two day fields.

Ready-to-copy schedules (5 fields)

*/5 * * * *       every 5 minutes
0 * * * *         every hour, on the hour
0 */6 * * *       every 6 hours (00, 06, 12, 18)
0 9-17 * * 1-5    hourly from 09:00 to 17:00, Monday to Friday
30 2 * * *        daily at 02:30
0 0 * * 0         Sundays at midnight
0 9 1 * *         09:00 on the first day of every month
0 0 1 1,4,7,10 *  midnight on the first day of each quarter
0 0 1 1 *         once a year, 1 January

Crontab and platform gotchas

  • System crontabs have a user column. Lines in /etc/crontab and /etc/cron.d/* take a username between the time fields and the command; personal crontabs edited with crontab -e do not.

  • % is special in crontab commands: it ends the command and starts standard input. Escape it as \%, a common surprise with date +%F.

  • Minimal environment. Jobs run with a short PATH and /bin/sh. Use absolute paths, set variables at the top of the crontab, and redirect output (>> /var/log/job.log 2>&1) or set MAILTO.

  • Time zones and daylight saving. Cron uses the system zone. Jobs between roughly 01:00 and 03:00 local time may be skipped or repeated on transition days, depending on the implementation; schedule critical jobs outside that window or run servers in UTC. cronie supports CRON_TZ, and Kubernetes CronJobs accept .spec.timeZone.

  • GitHub Actions schedules run in UTC, the shortest interval is five minutes, and runs can start late when load is high.

  • Overlapping runs. Cron starts a job on schedule whether or not the previous run has finished. For jobs that can run long, wrap the command in flock -n /tmp/job.lock or use a scheduler with a concurrency policy, such as a Kubernetes CronJob with concurrencyPolicy: Forbid.

To check any of these expressions, paste it into the cron expression explainer: it describes the schedule in English and lists the next runs in the time zone you choose.

Frequently asked questions

What are the five fields of a cron expression?

Minute (0–59), hour (0–23), day of month (1–31), month (1–12) and day of week (0–7, where 0 and 7 are Sunday).

What does */5 mean in cron?

Every fifth value of the field, starting from its minimum. In the minute field it means minutes 0, 5, 10 and so on up to 55.

Why did my job run on the wrong days?

If both day of month and day of week are restricted, standard cron runs on days matching either field, not both.

Does Linux cron support L, W and #?

No. Vixie cron and cronie reject them. They work in Quartz, Spring, AWS EventBridge and many scheduling libraries.

Is Sunday 0 or 1?

In standard cron Sunday is 0 (and also 7). In Quartz and AWS EventBridge, Sunday is 1 and Saturday is 7.

Related