Skip to content
YAS.SH
Developers

Cron Expressions Demystified: A Field-by-Field Guide

Every cron field explained with examples, the five rules that trip everyone up (day-of-month vs day-of-week, timezones, DST), and a parser that computes the next runs.

yas-team5 min readcronschedulingdevops
Cron Expressions Demystified: A Field-by-Field Guide
Featured imageCron Expressions Demystified: A Field-by-Field Guide

Cron is the oldest automation tool still in daily use — and the one most people configure by copy-paste. The syntax is small enough to learn in ten minutes and weird enough to cause a 3 AM incident when you get it wrong.

The Cron Parser computes the next run times for any expression, which makes every rule in this article testable in seconds instead of learnable through outages.

The five fields

* * * * *
│ │ │ │ │
│ │ │ │ └── day of week (0–7, 0 and 7 = Sunday)
│ │ │ └──── month (1–12, or jan–dec)
│ │ └────── day of month (1–31)
│ └──────── hour (0–23)
└────────── minute (0–59)

The order is the thing everyone gets wrong at least once: minute comes first. 30 2 * * * is 02:30, not 30:02.

The building blocks

Syntax Meaning Example
* Every value * * * * * — every minute
5 Exact value 0 9 * * * — 09:00 daily
a-b Range 9-17 — 9 through 17
*/n Step */15 * * * * — every 15 minutes
a-b/n Range with step 9-17/2 — 9, 11, 13, 15, 17
a,b,c List 0,30 * * * * — at :00 and :30
jan–dec, sun–sat Names 0 9 * jan mon * — January Mondays (some implementations)

Rule 1: the classic gotcha — two day fields

Both day of month and day of week have * defaults, and when both are restricted, either matching counts. So:

0 0 1 * 1

runs every Monday AND on the 1st of every month — not "the first Monday". This is the single most common cron surprise. If you want "the first Monday", you need the # extension (0 0 * * 1#1 in extended syntaxes) or a wrapper script that checks the date.

Rule 2: timezone is the server's, always

Cron has no timezone field in the classic 5-field form. A server running UTC runs your "8 AM" job at 8 AM UTC — which is 10 AM in Cairo in summer and 11 AM in winter. Fix: run servers in UTC and schedule in UTC, or use CRON_TZ where supported.

Rule 3: DST is a lie detector

When clocks jump forward, an hour simply doesn't exist; when they jump back, it happens twice. Most cron implementations handle this by running at the (possibly shifted) wall-clock time — but "once daily at 02:30" can become zero or two runs. For anything that must be exactly-once, prefer UTC (no DST).

Rule 4: no backfill

If the server was down at 02:30, the 02:30 job doesn't run at 03:00. Cron is fire-and-forget. Mission-critical jobs need catch-up logic or an external scheduler.

Rule 5: minute granularity is the floor

Cron's smallest unit is one minute. Sub-minute scheduling (every 30 seconds) is not cron's job — that's a systemd timer with OnUnitActiveSec=30s or a proper queue.

Test before you trust

The parser is one POST away:

curl -X POST https://yas.sh/api/v1/tools/cron-parser -d '{"input":"*/15 * * * *","count":5}'
{ "expression": "*/15 * * * *", "valid": true,
  "next": ["2026-08-08T12:15:00.000Z", "2026-08-08T12:30:00.000Z", "..."] }

Run your expression, read the next five times, and ask: is this what I meant? If it is, schedule it. If not, the parser just saved you a 3 AM pager call — which is exactly what a ten-minute investment in cron syntax is worth.

The five fields and their traps

A cron expression is five whitespace-separated fields: minute (0–59), hour (0–23), day of month (1–31), month (1–12), and day of week (0–7, where both 0 and 7 are Sunday). Getting the fields right is only half the battle; the traps are where most mistakes live:

  • Day of month and day of week are OR-ed in most implementations. 0 0 1 * 1 runs on the first of the month and on every Monday — not "the first Monday." This is the single most surprising cron behavior.
  • Minute zero is the default and the one most people forget. * * * * * runs every minute; leaving the minute field as * when you want hourly produces a much noisier schedule than intended.
  • Weekday indexing. Both 0 and 7 are Sunday, and many people write 7 expecting Saturday. When in doubt, pin it down explicitly.
  • Non-standard extensions. Some schedulers add */5 step syntax, H (hash, in Jenkins), or seconds as a sixth field. An expression that parses in one scheduler may not in another, so know your target.

A parser that shows you the next occurrences is the fastest way to catch these traps — an expression that produces "next Monday at 3am" tells you instantly whether you meant what you wrote.

Testing and deploying cron safely

Before a cron job touches production data, verify it the way you would any other change: run the parser, read the next several occurrences, and confirm the timing matches your intent. Then test the job itself on a small, safe scale before letting it run unattended. Schedule a dry-run or a first execution in a controlled way, and make the job idempotent so a re-run does not duplicate work (the webhooks automation guide covers the idempotency and logging discipline that applies here too). Finally, make sure your cron host is the one you think it is — the timezone of the server, not your local time, is what the schedule follows.

Cron is the natural scheduler for link automation. The recurring tasks — refreshing campaign links, running expiry audits, sending summary reports, checking click thresholds — all map cleanly to a five-field schedule, and they pair with the API. For example, a daily 8am job can pull the previous day's analytics and post a summary to your team channel; a weekly job can list links expiring in the next seven days for review. Because these jobs are idempotent and paced, cron plus the API gives you dependable automation without a separate scheduler platform. The webhooks and automation guide shows the end-to-end pattern these cron triggers drive.

Ultimately, a cron expression is a promise about the future: "this will run at these times." The parser is what lets you verify that promise before you rely on it. Verify the next occurrences, test safely, and keep the job idempotent, and your scheduled automation will behave exactly as scheduled.

Conclusion

This guide covered the practical essentials of cron parser cron jobs guide. Apply the discipline, test before relying on it, and revisit when your needs change.

Frequently asked questions

Why does my cron job run at the wrong time?

Cron runs in the server's local timezone. If the server is UTC and you think in local time, everything shifts. Use CRON_TZ if your system supports it, or compute the UTC offset yourself.

What happens if a job is missed during a restart?

Nothing — cron doesn't backfill. Missed runs are simply lost. For jobs that must run exactly once, use a scheduler with catch-up or an idempotent worker.

Is 0 0 1 * * the same as monthly?

Almost — it's midnight on the 1st of every month. But a monthly task on a 31-day month never runs on the 30th/31st if you write it as the last day. cron has no "last day" field (that's what L is for in some implementations).

Was this helpful? Share
Ask YAS AI
🍪 Cookies & privacy. Essential cookies keep you signed in and remember language and theme. Google AdSense and reCAPTCHA are Google technologies: AdSense runs only after Accept All; reCAPTCHA loads on sign-in and contact forms. See how Google uses data: https://policies.google.com/technologies/partner-sites cookie policy · privacy policy.
Settings