Skip to content
Appachi Tools

Cron Expressions Explained: A Plain-English Guide to `* * * * *`

Five fields, a handful of special characters, and one genuinely surprising gotcha about how day-of-month and day-of-week combine. Everything you need to stop guessing at cron syntax.

Cron syntax is one of those things every developer eventually needs and nobody quite remembers between uses. Five fields, a few symbols, and one rule that trips up almost everyone the first time they hit it. Here's the whole thing.

The five fields

A standard cron expression is five space-separated fields, in this order:

┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, Sunday = 0)
│ │ │ │ │
* * * * *

So 0 9 * * 1 reads as: minute 0, hour 9, any day of month, any month, day-of-week 1 (Monday) — every Monday at 9:00 AM.

(Some systems, including Kubernetes CronJobs and most standard Unix cron, use exactly this 5-field format. A few tools add a sixth "seconds" field at the front — check your specific system's docs if a schedule isn't firing when you expect.)

The special characters

  • * — "any value." * * * * * means every minute, of every hour, of every day.
  • , — a list. 0 9,17 * * * runs at 9:00 AM and 5:00 PM.
  • - — a range. 0 9-17 * * * runs every hour, on the hour, from 9 AM through 5 PM.
  • / — a step. */15 * * * * runs every 15 minutes; 0 */2 * * * runs every 2 hours, on the hour.

Combined: 0 9-17/2 * * 1-5 runs at 9 AM, 11 AM, 1 PM, 3 PM and 5 PM, Monday through Friday.

Common patterns

Schedule Expression
Every minute * * * * *
Every 5 minutes */5 * * * *
Every hour, on the hour 0 * * * *
Every day at midnight 0 0 * * *
Every day at 9:00 AM 0 9 * * *
Every Monday at 9:00 AM 0 9 * * 1
First day of every month, midnight 0 0 1 * *
Every weekday at 6:00 PM 0 18 * * 1-5

The gotcha: day-of-month and day-of-week are OR'd, not AND'd

This is the single most common source of "why did my job run on a day I didn't expect" confusion. If both the day-of-month and day-of-week fields are restricted (not *), most cron implementations treat them as an OR, not an AND — the job runs if either condition is true.

So 0 0 15 * 1 does not mean "the 15th, but only if it's a Monday." It means "midnight on the 15th of every month, and midnight every Monday" — both conditions independently trigger it. If you actually want "only the 15th, and only if it's a Monday," you generally need to leave one of the two fields as * and add the other constraint in your job's own logic, since cron syntax alone can't express a true AND between those two fields.

Two more things worth knowing

Timezone. Cron schedules typically run in the system (or container's) local timezone unless the scheduler is explicitly configured otherwise — daylight saving transitions can shift an "every day at 2 AM" job in ways that surprise people twice a year. If your schedule is timezone-sensitive, check how your specific platform (cron daemon, Kubernetes CronJob, a cloud scheduler) resolves it, since this does vary.

@ shorthand. Many implementations (including standard Unix cron) support named shortcuts: @daily (0 0 * * *), @hourly (0 * * * *), @weekly, @monthly, @yearly. Handy for readability, but not universally supported — check your target system before relying on them.

Building or debugging a schedule right now? Build it visually and get a plain-English description instead of counting fields by hand.