Read and write a cron expression

Five fields with no labels, and one of them counts from a different starting number than the rest. Cron is read wrongly more often than almost any other syntax in common use.

The five fields

*  *  *  *  *
│  │  │  │  └── day of week   (0-7, both 0 and 7 mean Sunday)
│  │  │  └───── month        (1-12)
│  │  └──────── day of month (1-31)
│  └─────────── hour         (0-23)
└────────────── minute       (0-59)

Minutes and hours start at zero; days and months start at one. That inconsistency is the source of a great many mistakes.

The trap that actually bites

When both day-of-month and day-of-week are restricted, cron treats them as OR, not AND. So 0 0 1 * 1 does not mean "the first of the month, if it is a Monday" — it means "the first of the month, and also every Monday".

This is the single most common cron bug, because the wrong reading is the intuitive one and the job appears to work. It simply runs far more often than intended.

The syntax worth knowing

  • * — every value.
  • */15 — every fifteenth, so at 0, 15, 30 and 45 minutes past.
  • 1-5 — an inclusive range. In the day-of-week field, Monday through Friday.
  • 1,15 — a list of specific values.
  • 0 9 * * 1-5 — nine in the morning, on weekdays.

Which time zone it runs in

Traditional cron uses the system time zone of the machine it runs on, which means a job scheduled for 02:30 may run twice or not at all on the days that clocks change. Scheduling in UTC avoids it entirely; if that is not possible, avoid the hour around the transition.

Not every scheduler agrees on the syntax either. Quartz, used by many Java schedulers, takes six or seven fields with seconds at the front, so an expression copied between the two will be silently misread.

Seeing the next runs

The only reliable way to check a schedule is to look at when it would actually fire. Bellows lists the next run times for an expression, which turns a guess into a fact — and makes the day-of-week trap obvious the moment it appears.

How to check the claim rather than trust it

Bellows is signed without a network entitlement. That is not a policy someone wrote down — it is a permission the binary does not have, and macOS enforces it whether the app wants to connect or not. You can read the entitlements it was signed with:

codesign -d --entitlements - /Applications/Bellows.app

Neither com.apple.security.network.client nor com.apple.security.network.server appears in the output. Without them the sandbox refuses to open a socket.

Cron Builder is one of 41 tools in Bellows

A native Mac app that ships with no network entitlement, so macOS blocks it from connecting at all. One-time purchase, every future update included.

What Bellows is →

Questions

What does */15 mean in cron?

Every fifteenth unit of that field. In the minute field it fires at 0, 15, 30 and 45 minutes past the hour.

Does 0 0 1 * 1 run only on a Monday the 1st?

No. When both day-of-month and day-of-week are restricted, cron combines them with OR. That expression runs on the first of every month and on every Monday.

What time zone does cron use?

The system time zone of the machine running it, unless the scheduler supports setting one explicitly. Jobs scheduled during a daylight-saving transition can run twice or be skipped.

Related