Most of the time you do not need to understand cron from first principles — you need the one line that runs your backup at 3 AM on the first Sunday of the month. This page collects sixty schedules we have actually needed, grouped by how often they fire, with the behaviour worth knowing about each one. Every expression is standard five-field Unix cron unless the table says otherwise, and every one can be pasted into the Explainer to see its next run times.
Every N minutes
Step values in the minute field (*/n) cover almost every sub-hourly schedule. A step divides the whole 0–59 range, so it only lands evenly when n divides 60.
| Expression | Runs | Notes |
|---|---|---|
* * * * * | Every minute | 1,440 runs a day. The fastest standard cron can go. |
*/2 * * * * | Every 2 minutes | Fires on even minutes: :00, :02, :04… |
*/5 * * * * | Every 5 minutes | The most common polling interval. |
*/10 * * * * | Every 10 minutes | :00, :10, :20, :30, :40, :50. |
*/15 * * * * | Every 15 minutes | Four runs an hour, on the quarter. |
*/30 * * * * | Every 30 minutes | Equivalent to 0,30 * * * *. |
*/7 * * * * | Every 7 minutes, resetting each hour | :00, :07…:56, then :00 again — a 4-minute gap at the hour boundary because 7 does not divide 60. |
7 * * * * | At 7 minutes past every hour | Offsetting off :00 keeps you out of the traffic spike every other job creates. |
0,15,30,45 * * * * | Every 15 minutes | An explicit list; identical to */15 but clearer to some readers. |
*/5 * * * 1-5 | Every 5 minutes, Monday to Friday | Nothing at all on Saturday or Sunday. |
A step always restarts at the beginning of its field's range, not from the previous run. */7 does not mean "every 7 minutes forever" — it means "every 7th minute of each hour", so the gap between 23:56 and 00:00 is four minutes, not seven. If you need a true fixed interval that does not divide an hour, use a scheduler with interval support rather than cron.
Hourly and every N hours
Put a fixed value in the minute field and a step or range in the hour field. Leaving the minute as * is nearly always a mistake: * */2 * * * runs sixty times in each of those hours, not once.
| Expression | Runs | Notes |
|---|---|---|
0 * * * * | Every hour, on the hour | 24 runs a day. |
30 * * * * | Every hour at half past | Useful for staggering against hourly jobs on :00. |
0 */2 * * * | Every 2 hours | 00:00, 02:00, 04:00…22:00. |
0 */3 * * * | Every 3 hours | Eight runs a day starting at midnight. |
0 */4 * * * | Every 4 hours | 00:00, 04:00, 08:00, 12:00, 16:00, 20:00. |
0 */6 * * * | Every 6 hours | Four runs a day. |
0 */12 * * * | Twice a day | Midnight and noon. |
0 9-17 * * * | Hourly from 09:00 to 17:00 | Nine runs — the range includes both ends. |
0 8-18/2 * * * | Every 2 hours between 08:00 and 18:00 | 08:00, 10:00, 12:00, 14:00, 16:00, 18:00. A step applied to a range. |
15,45 * * * * | Twice an hour, at :15 and :45 | A list in the minute field. |
Daily at a fixed time
Cron uses 24-hour time. There is no AM/PM and no seconds — 0 18 * * * is 6 PM, and it fires at 18:00:00 in the server's time zone, whatever that happens to be.
| Expression | Runs | Notes |
|---|---|---|
0 0 * * * | Every day at midnight | The classic nightly job. Equivalent to @daily. |
30 2 * * * | Every day at 02:30 | A common backup window — but see the DST warning below. |
0 3 * * * | Every day at 03:00 | Safely past the daylight saving transition hour in most zones. |
0 6 * * * | Every day at 06:00 | Morning report generation. |
0 12 * * * | Every day at noon | |
0 18 * * * | Every day at 18:00 | 6 PM in 24-hour time. |
0 23 * * * | Every day at 23:00 | End-of-day rollup before the date changes. |
0 0,12 * * * | Twice daily, midnight and noon | A list is clearer than */12 when the two times are not evenly spaced. |
In zones that observe daylight saving, a daily job scheduled between roughly 01:00 and 03:00 will be skipped on the spring-forward day, or run twice on the fall-back day, depending on your cron implementation. Scheduling at 0 3 * * * or later sidesteps the whole problem. The time zones and DST guide walks through exactly what each implementation does.
Weekdays, weekends and business hours
Day of week is the fifth field, numbered 0 (Sunday) through 6 (Saturday). Most implementations also accept 7 for Sunday and three-letter names such as MON.
| Expression | Runs | Notes |
|---|---|---|
0 9 * * 1-5 | Weekdays at 09:00 | Monday through Friday. |
0 9 * * MON-FRI | Weekdays at 09:00 | Identical, using names. Names are case-insensitive but less portable than numbers. |
0 18 * * 1-5 | Weekdays at 18:00 | End-of-workday jobs. |
0 0 * * 6,0 | Weekends at midnight | Saturday and Sunday. |
0 2 * * 6 | Saturdays at 02:00 | Weekly maintenance while nobody is working. |
*/15 9-17 * * 1-5 | Every 15 minutes, 09:00–17:59, weekdays | 36 runs per weekday. The 17 covers the whole 17:00 hour, so the last run is 17:45. |
0 9-17 * * 1-5 | Hourly during business hours, weekdays | Nine runs a day, 45 a week. |
*/30 8-18 * * 1-5 | Every half hour, 08:00–18:59, weekdays | Extend the hour range by one if you want coverage through the end of the day. |
Weekly
A weekly schedule is just a daily schedule with the day-of-week field restricted, and the day-of-month field left as *. Restricting both is the single most common cron mistake — see the last section.
| Expression | Runs | Notes |
|---|---|---|
0 0 * * 0 | Every Sunday at midnight | Equivalent to @weekly. |
0 0 * * 1 | Every Monday at midnight | Start-of-week reset. |
0 4 * * 0 | Every Sunday at 04:00 | Weekly full backup. |
0 8 * * 1 | Every Monday at 08:00 | Weekly summary email before the day starts. |
0 17 * * 5 | Every Friday at 17:00 | End-of-week report. |
0 12 * * 1,3,5 | Monday, Wednesday and Friday at noon | A list in the day-of-week field. |
Monthly
Day of month is the third field, 1–31. Standard cron has no "last day of month" token, which is why the workarounds below exist.
| Expression | Runs | Notes |
|---|---|---|
0 0 1 * * | Midnight on the 1st of every month | Equivalent to @monthly. |
0 3 1 * * | 03:00 on the 1st | Monthly billing or archival run. |
0 0 15 * * | Midnight on the 15th | Mid-month. |
0 0 1,15 * * | 1st and 15th | Twice-monthly payroll pattern. |
0 0 28 * * | The 28th of every month | The last day that exists in every month, February included. |
0 0 1 */3 * | The 1st of every third month | January, April, July, October. |
0 9 1-7 * 1 | Not "the first Monday" | This runs on days 1–7 and on every Monday, because of OR logic. See below for the correct form. |
0 0 L * * | Last day of the month | Quartz and some extended dialects only. Standard Unix cron rejects L. |
Running on the last day of the month in standard cron
Because Unix cron has no L, the portable trick is to run daily and let the command decide whether today is the last day:
0 23 28-31 * * [ "$(date -d tomorrow +\%d)" = "01" ] && /usr/local/bin/month-end.sh
The schedule narrows cron to the only four candidate days, and the shell test lets exactly one of them through. Note the escaped \%: inside a crontab, an unescaped % is turned into a newline and everything after it is fed to the command on standard input.
Running on the first Monday of the month
Same idea — restrict day of month to the first week and day of week to Monday, then guard in the shell so the OR logic cannot fire on the wrong day:
0 9 1-7 * * [ "$(date +\%u)" = "1" ] && /usr/local/bin/first-monday.sh
Only days 1–7 are candidates, and date +%u returns 1 only on Monday, so exactly one day a month qualifies. In Quartz you would write this directly as 0 0 9 ? * MON#1.
Quarterly and yearly
| Expression | Runs | Notes |
|---|---|---|
0 0 1 1,4,7,10 * | The 1st of each quarter | January, April, July, October — calendar quarters. |
0 0 1 2,5,8,11 * | Quarters offset by one month | For fiscal years starting in February. |
0 0 1 */6 * | Twice a year | January and July. |
0 0 1 1 * | Midnight on 1 January | Equivalent to @yearly or @annually. |
0 0 31 12 * | Midnight on 31 December | Year-end close. |
0 2 1 JAN,APR,JUL,OCT * | Quarterly at 02:00 | Month names, where supported. |
Special strings
Most cron implementations accept a handful of shorthand strings in place of all five fields. They are readable and portable across Vixie cron, cronie and systemd's cron compatibility, though not across every scheduler — Kubernetes CronJobs accept them, AWS EventBridge does not.
| String | Equivalent | Meaning |
|---|---|---|
@yearly | 0 0 1 1 * | Once a year at midnight, 1 January. @annually is a synonym. |
@monthly | 0 0 1 * * | Midnight on the first of the month. |
@weekly | 0 0 * * 0 | Midnight on Sunday. |
@daily | 0 0 * * * | Midnight every day. @midnight is a synonym. |
@hourly | 0 * * * * | The top of every hour. |
@reboot | — | Once, when the cron daemon starts after a boot. No time equivalent, and not supported everywhere. |
Five examples that do not mean what they look like
These are the expressions that pass review and then behave unexpectedly in production. Each one is syntactically valid, which is why reading the computed run times matters more than reading the syntax.
1. 0 0 13 * 5 — not Friday the 13th
When day of month and day of week are both restricted, standard cron runs when either matches. This fires on the 13th of every month and on every Friday — roughly 16 times a month, not once or twice a year. To get only Friday the 13th, schedule 0 0 13 * * and guard on [ "$(date +\%u)" = "5" ] in the command.
2. * */2 * * * — not every two hours
The minute field is *, so this runs every minute of every second hour: 60 runs at 00:00–00:59, then 60 more at 02:00–02:59, and so on. 720 runs a day. The intended expression is 0 */2 * * *.
3. 0 9-17 * * * — ends at 17:00, not 17:59
This one is correct as written, but the neighbouring case trips people up: */15 9-17 * * * runs through 17:45, because the hour range 9-17 includes the whole of the 17:00 hour. If you want coverage to stop at 17:00 exactly, the minute restriction has to do that work.
4. 0 0 31 * * — silently skips four months
February, April, June, September and November have no 31st, so a job scheduled on the 31st runs seven times a year instead of twelve. Use 28 if you want it every month, or the last-day-of-month pattern above.
5. */90 * * * * — invalid or truncated
A step larger than the field's range is meaningless. Depending on the implementation, cron either rejects the line outright or clamps it to something you did not intend. Cron cannot express "every 90 minutes" at all: the closest honest approximations are 0 */2 * * * or two separate lines such as 0 0,3,6,9,12,15,18,21 * * * plus 30 1,4,7,10,13,16,19,22 * * *.
One page per schedule
Every schedule above also has a dedicated page with live next-run times, usage notes and the specific trap that comes with it — browse them in the schedule reference.
Build your own
If none of these is quite right, compose the schedule field by field in the visual builder and read the next five run times before you commit it — that is the fastest way to catch a wrong schedule while it is still cheap. To decode an expression you inherited from someone else's config file, paste it into the Explainer.