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.
