Cron Expressions Explained

A cron expression is a five-field string — minute, hour, day of month, month, day of week — that tells a scheduler when to run a job. The same syntax drives Linux crontab, Kubernetes CronJobs, GitHub Actions schedules, Cloudflare Workers cron triggers, AWS EventBridge and most CI systems, so reading and writing it is a skill you use everywhere.

This guide walks through each field and operator, gives the schedules people search for most, and explains the traps — time zones, day-of-month versus day-of-week, and the extra seconds field in some systems — that cause a job to fire at the wrong time or not at all.

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)
│ │ │ │ │
* * * * *   → every minute
30 2 * * *  → at 02:30 every day
0 9 * * 1-5 → at 09:00 Monday to Friday

Try it: Cron Expression Explainer

The operators: *, /, - and ,

  • * (asterisk) — every value. * in the hour field means every hour.
  • , (comma) — a list. 0,30 in the minute field means at minute 0 and minute 30.
  • - (hyphen) — a range. 9-17 in the hour field means 9, 10, … 17.
  • / (slash) — a step. */15 in the minute field means every 15 minutes (0, 15, 30, 45); 1-31/2 means every second day.
  • Names — JAN–DEC and SUN–SAT are accepted in most implementations and are easier to read than numbers.
  • Extensions — some schedulers accept L (last), W (nearest weekday), # (nth weekday) and ? — these are Quartz/Spring features, not standard cron.

Try it: Cron Expression Generator

Common schedules

*/5 * * * *      every 5 minutes
0 * * * *        every hour, on the hour
0 */6 * * *      every 6 hours (00:00, 06:00, 12:00, 18:00)
0 0 * * *        every day at midnight
0 9 * * 1-5      weekdays at 09:00
0 9 * * 1        every Monday at 09:00
0 0 1 * *        first day of every month at midnight
0 0 1 1 *        once a year, 1 January
30 23 * * 0      Sundays at 23:30
0 8,20 * * *     twice a day, 08:00 and 20:00
15 3 */2 * *     every second day at 03:15
0 0 * * 5        every Friday at midnight

Try it: Cron Expression Generator Try it: Cron Expression Validator

Time zones: the most common cron bug

A cron expression has no time zone of its own; it runs in whatever zone the scheduler uses. Linux crontab uses the system zone, Kubernetes and Cloudflare Workers use UTC, GitHub Actions uses UTC, and cloud services vary. A job meant for 09:00 Riyadh time (UTC+3) must be written as 0 6 * * * on a UTC scheduler — and 09:00 in a zone that observes daylight saving shifts by an hour twice a year. Always document the zone next to the expression and convert explicitly.

Try it: Timezone Converter

Day of month vs day of week

When both day fields are restricted, standard cron runs the job if either matches (OR), not both. 0 0 13 * 5 fires on every 13th and on every Friday, not only on Friday the 13th. To express "second Tuesday of the month" or "last day of the month" you need Quartz-style extensions or a small check inside the job itself.

Try it: Cron Expression Explainer

Six-field cron and other variants

  • Quartz, Spring and some Java schedulers put a seconds field first: 0 */5 * * * ? — six or seven fields. Pasting a five-field expression there shifts every field by one.
  • Cloudflare Workers, Kubernetes, GitHub Actions and Vercel use the standard five fields.
  • Some systems accept @hourly, @daily, @weekly, @monthly and @yearly as shorthand.
  • Minimum resolution is one minute; sub-minute schedules need a different mechanism.

Try it: Cron Expression Validator

Testing a cron expression

Before deploying, paste the expression into a validator that lists the next several run times in your zone. Check that the first run is when you expect, that the interval between runs is right, and that month-end and weekend cases behave. Then make the job itself idempotent — safe to run twice — because every scheduler will eventually run it twice or skip it once.

Try it: Cron Expression Validator Try it: Unix Timestamp Converter

Frequently asked questions

What does * * * * * mean in cron?

Every minute of every hour of every day. Each asterisk means "every value" for its field.

How do I run a cron job every 5 minutes?

Use */5 * * * *. The step operator in the minute field fires at 0, 5, 10 … 55.

How do I schedule a job every Monday at 9 am?

0 9 * * 1 — minute 0, hour 9, any day of month, any month, weekday 1 (Monday).

Is Sunday 0 or 7 in cron?

Both work in most implementations: 0 and 7 mean Sunday. Use SUN if the scheduler accepts names, to avoid the ambiguity.

Which time zone does cron use?

Whatever the scheduler is configured with — the system zone for crontab, UTC for Kubernetes, GitHub Actions and Cloudflare Workers. Convert your local time to that zone when writing the expression.

Why does my cron job not run?

The usual causes: the expression is in the wrong zone, a six-field expression was given to a five-field scheduler (or vice versa), the day-of-month and day-of-week fields combine as OR, or the job runs but fails silently — check the scheduler's logs and the next-run preview.

Tools mentioned in this guide

More guides

More guides →