Skip to main content
{/}codefunc
Web & APIJuly 8, 2026 · 5 min read

Cron Expressions Explained: Fields, Syntax, and the Gotchas That Miss Runs

A complete guide to cron syntax — the five fields, special characters, real-world examples, and the timezone, day-of-week, and non-standard pitfalls that silently break schedules.

By codefunc

cronschedulingdevopsautomationlinux

Cron runs the invisible half of most systems: backups, report emails, cache warmers, cleanup jobs. The syntax is compact — five fields and a handful of symbols — but it hides sharp edges. A misread field or an assumption about timezone can mean a job that never fires, or fires far too often. This guide covers the syntax and, more importantly, the gotchas that cause missed runs.

Bottom line: A standard cron expression is five fields — minute, hour, day-of-month, month, day-of-week. Master *, ,, -, and /, remember that day-of-month and day-of-week combine with OR (not AND), and always confirm the timezone your scheduler uses.

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, 0 = Sunday, or SUN-SAT)
│ │ │ │ │
* * * * *

Read left to right, most granular first. 0 9 * * 1-5 means "at minute 0 of hour 9, every day, every month, on weekdays" — 9:00 AM Monday through Friday.

Special characters

Symbol Meaning Example Reads as
* every value * * * * * every minute
, list 0 9,17 * * * at 09:00 and 17:00
- range 0 9-17 * * * hourly from 09:00 to 17:00
/ step */15 * * * * every 15 minutes
names month/day names 0 0 * * SUN midnight on Sundays

Steps combine with ranges: 0 9-17/2 * * * runs every two hours from 09:00 to 17:00.

Examples you will actually write

Expression Meaning
*/5 * * * * Every 5 minutes
0 * * * * Every hour, on the hour
0 0 * * * Every day at midnight
30 2 * * * Every day at 02:30
0 9 * * 1-5 Weekdays at 09:00
0 0 1 * * First day of every month
0 0 * * 0 Every Sunday at midnight
0 22 * * 1-5 Weeknights at 22:00

When in doubt, translate an expression to English with cron to human and preview the next runs with the cron parser.

Gotcha 1: day-of-month and day-of-week are OR, not AND

This surprises almost everyone. If both the day-of-month and day-of-week fields are restricted (neither is *), cron runs when either matches:

0 0 13 * 5    # midnight on the 13th OR any Friday — not "Friday the 13th"

To get "Friday the 13th" you cannot express it in standard cron alone; you check the date inside the job. Keep one of the two day fields as * unless you truly want the OR behavior.

Gotcha 2: timezones

Cron evaluates against a clock — but which clock?

  • Traditional Linux crontab uses the system timezone (often UTC on servers).
  • Managed schedulers (cloud cron, Kubernetes CronJobs) frequently default to UTC regardless of your locale.
  • Daylight-saving transitions can cause a job to run twice or skip once around the change.

Always confirm the scheduler's timezone. 0 9 * * * is 09:00 UTC on most servers — which may be the middle of the night for your users. For DST-sensitive jobs, schedule in UTC and convert intent, or use a scheduler with explicit timezone support.

Gotcha 3: non-standard extensions

Not all cron implementations are equal:

  • Seconds field: Quartz (Java) and some libraries use six fields, adding seconds at the front. A five-field expression pasted into a six-field parser shifts every field by one.
  • Macros: @hourly, @daily, @weekly, @reboot are convenient but not universal — @reboot in particular is unsupported by many managed schedulers.
  • Step edge cases: */7 on minutes runs at 0, 7, 14 … 56, then jumps to 0 next hour — the interval is not preserved across the hour boundary.

Confirm whether your target expects 5 or 6 fields before deploying.

Gotcha 4: missed runs and overlap

Cron does not guarantee execution — it triggers at a time; if the machine is off or busy, the run is simply skipped (no catch-up, except @reboot). And if a job runs longer than its interval, a new instance can start before the last finishes.

Defensive patterns:

  • Use a lock (for example flock) to prevent overlap.
  • Make jobs idempotent so a skipped or repeated run is harmless.
  • For guaranteed delivery, use a queue with retries instead of relying on cron alone.

Testing before you deploy

The cheapest bug to fix is the one you catch before it ships. Before committing a cron line:

  1. Translate it to plain English — does it say what you meant?
  2. Preview the next several run times against your expected schedule.
  3. Double-check the field count (5 vs 6) and the timezone.

You can do all three locally with the cron builder to construct the expression, cron to human to read it back, and the cron parser to list upcoming runs.

Practical takeaway

Cron is five fields and four symbols — learn them and most schedules are trivial. The failures come from assumptions: the OR behavior of the two day fields, the server's timezone, six-field parsers, and the fact that cron never retries. Translate and preview every expression before deploying, add locks for long jobs, and keep jobs idempotent.

Sources

Try it on codefunc

Related articles

3

Search tools

Find a developer tool