Cron expressions explained: the five fields, the special characters, and the traps

0 9 * * 1–5 runs something at nine every weekday, and the notation has looked like that since Unix in the 1970s. Cron expressions are terse, everywhere — servers, CI pipelines, cloud schedulers, Kubernetes — and easy to get subtly wrong. The cron parser translates any expression into English and lists the next runs; this guide teaches the reading.

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

Each field is a set of allowed values; the job runs when the current time matches all five (with one famous exception below). A * means "every value". 30 14 * * * is 14:30 daily; 0 0 1 * * is midnight on the first of every month.

The special characters

  • * — any value.
  • , — a list: 0 9,17 * * * runs at 9:00 and 17:00.
  • - — a range: 0 9 * * 1-5 is weekdays.
  • / — a step: */15 * * * * is every 15 minutes; 0 */2 * * * every two hours on the hour.
  • Names — MON, JAN; case-insensitive in most implementations.

Some implementations add L (last), W (nearest weekday), # (nth weekday: 5#3 is the third Friday) and ? — Quartz (Java) and its descendants have them; classic Unix cron does not.

Common examples

  • */5 * * * * — every five minutes.
  • 0 * * * * — every hour, on the hour.
  • 0 2 * * * — daily at 02:00 (backups love this slot).
  • 0 9 * * 1-5 — weekdays at 09:00.
  • 0 0 * * 0 — Sundays at midnight.
  • 0 0 1 * * — first of the month.
  • 0 6 1 1 * — 06:00 on 1 January.
  • 30 8 * * 1,3,5 — 08:30 Monday, Wednesday, Friday.

The traps

  • Day-of-month OR day-of-week. When both are restricted, classic cron runs if either matches: 0 9 13 * 5 fires on the 13th of every month and every Friday, not on Friday the 13th. Implementations differ; test.
  • Sunday is 0 and 7 in most crons; some accept only 0.
  • Time zone. Cron runs in the system's zone (often UTC on servers and in the cloud). A "9 a.m." job in UTC is 4 a.m. in New York and 10 a.m. in London — and shifts with daylight saving. Jobs scheduled at 02:30 in a zone with DST may run twice or never on changeover nights (Working across time zones).
  • Every minute is 1,440 runs a day. A */1 job that takes two minutes overlaps itself; use a lock or a queue.
  • 31st of the month doesn't exist in most months; 0 0 31 * * runs seven times a year. "Last day" needs L or a script.
  • Missed runs during downtime are simply skipped; cron has no catch-up.

Variants: seconds, years, GitHub, Kubernetes

Quartz and Spring add a leading seconds field (six or seven fields with an optional year), so their expressions don't paste into Unix cron unchanged. GitHub Actions schedules use standard five-field syntax in UTC and may run late under load. Kubernetes CronJobs use five fields with a configurable time zone since 1.27. Systemd timers replace cron on many Linux systems with a different calendar syntax (Mon..Fri 09:00). Whichever you use, paste the expression into the parser and read the next five run times before trusting it; the timestamp converter checks the zone arithmetic, and the time zone converter the human side.

Sources and further reading

The claims in this guide rest on these references, which were checked when the guide was last updated. Spotted an error? The contact page says how to report it.

  1. Cron — Wikipedia

Try the tool

Frequently asked questions

What does * * * * * mean in cron?

Every minute of every hour, every day. The five fields are minute, hour, day of month, month and day of week; * means any value.

How do I run a cron job every weekday at 9?

0 9 * * 1-5 — minute 0, hour 9, any day of month, any month, Monday to Friday.

Why does my cron job run on the wrong day?

Usually the day-of-month/day-of-week rule: when both are set, classic cron runs if either matches. Or the server's time zone differs from yours.

How do I run something on the last day of the month?

Standard cron can't express it. Use an implementation with L (Quartz), or run on the 28th–31st and check the date in the script.