UtilityBase logoUtilityBase

3 min read

Cron Syntax for Beginners

The five fields decoded, the patterns you'll actually use, the day-of-month/day-of-week gotcha that surprises everyone, and the timezone trap behind missed jobs.

The five fields

A standard cron expression is five fields separated by spaces: minute (0–59), hour (0–23), day of month (1–31), month (1–12), and day of week (0–6, where 0 is Sunday). Each field answers 'on which values should this run?' A literal number means exactly that value; an asterisk means every value. So 0 9 * * * reads as 'at minute 0 of hour 9, every day, every month, every weekday' — 9:00 AM daily.

Four operators cover almost everything else. A comma lists values (0,30 = on the 0th and 30th minute); a hyphen makes a range (1-5 in the day-of-week field = Monday through Friday); and a slash sets a step (*/15 in the minute field = every 15 minutes). Combine them freely: 0 9-17 * * 1-5 is 'every hour on the hour from 9 AM to 5 PM, Monday to Friday.' Reading a cron line is just translating each field in order.

Patterns you'll actually write

A handful of shapes cover most real jobs. Every fifteen minutes is */15 * * * *. Every day at 2:30 AM is 30 2 * * *. The top of every hour is 0 * * * *. Weekdays at 9 AM is 0 9 * * 1-5. The first of every month at midnight is 0 0 1 * *. Once you can read the five fields, you mostly assemble these from memory rather than deriving them each time.

Where beginners slip is over-specifying or mis-ordering. A common bug is scheduling '0 0 * * *' expecting hourly and getting once-a-day, because the first field is minute, not 'every.' Another is forgetting that cron has no 'seconds' field in the standard five-field form — the finest granularity is one minute. When a pattern doesn't behave, translate it field by field before assuming the scheduler is wrong.

  1. 1Decide the exact times in plain language first ('weekdays at 9 AM').
  2. 2Fill the fields right to left is optional — but always in the order minute, hour, day-of-month, month, day-of-week.
  3. 3Paste the expression into the Cron Explainer to see it read back in plain English.
  4. 4Confirm the next run times it lists match what you intended.
  5. 5Watch specifically for the day-of-month and day-of-week interaction below.

The two traps: OR-days and timezones

The classic gotcha: when you set both day-of-month and day-of-week to specific values, most cron implementations treat them as OR, not AND. So 0 0 13 * 5 does not mean 'Friday the 13th' — it means 'every 13th of the month AND every Friday,' running far more often than you expect. If you need a specific weekday, leave day-of-month as * (and vice versa); getting both to cooperate requires a check inside your job, not cron alone.

The second trap is timezone. Cron runs in the server's configured timezone, which is frequently UTC on cloud hosts — so 0 9 * * * fires at 9 AM UTC, not 9 AM where you live, and can land on the 'wrong' calendar day. Daylight-saving transitions add edge cases where a job is skipped or repeated. Before trusting a schedule, confirm the server's timezone and, if it matters, express your times in that zone or use a scheduler that supports an explicit TZ.

Frequently asked questions

Why does my Friday-the-13th cron run every Friday?

Because when both day-of-month and day-of-week are set to specific values, standard cron treats them as OR, not AND. So it runs on every 13th and every Friday. To hit only Friday the 13th, schedule for the 13th and check the weekday inside your script.

Can cron run a job every 30 seconds?

Not with standard five-field cron — its smallest unit is one minute. To run more often, use a job that loops internally, two staggered cron entries, or a scheduler built for sub-minute intervals. If you see a six-field expression, that extra leading field is a non-standard seconds field.

What timezone does cron use?

The server's configured timezone, which on many cloud hosts defaults to UTC. That means your times may run hours off from local, and daylight-saving changes can skip or repeat a job. Check the host's timezone and set an explicit one if your scheduler supports it.

Tools mentioned in this guide

Keep reading