Cron Expression Cookbook: 25 Schedules People Actually Search For

Updated 2 Sep 2026 · 9 min read

Cron's five fields are simple in theory and a constant source of off-by-one mistakes in practice. Below are 25 real schedules — the ones people actually type into a search box, not a tour of every possible field combination — each with the exact expression, a one-line explanation, and a live link into Cron Master prefilled with that schedule so you can see its next 10 run times before you commit it to a crontab.

Field order, always: minute hour day-of-month month day-of-week. Minutes and hours use 0-indexed 24-hour values; day-of-week is 0-6 with Sunday as 0 (7 is also accepted as Sunday by most implementations, but 0 is the safe default to assume).

Quick-copy reference

ScheduleExpressionMeaning
Every minute* * * * *Runs 1,440 times a day — almost always a debugging/testing schedule, not a production one
Every 5 minutes*/5 * * * *:00, :05, :10 … aligned to the clock
Every 10 minutes*/10 * * * *:00, :10, :20, :30, :40, :50
Every 15 minutes*/15 * * * *:00, :15, :30, :45 — four runs an hour
Every 30 minutes*/30 * * * *:00 and :30
Every hour0 * * * *At minute 0 of every hour
Every 2 hours0 */2 * * *Midnight, 2am, 4am … starts counting from 0, not from install time
Every 6 hours0 */6 * * *Midnight, 6am, noon, 6pm
Every 6 hours, offset to start at 3am0 3,9,15,21 * * *3am, 9am, 3pm, 9pm — the step syntax can't express an offset, so list the hours explicitly
Every 12 hours0 */12 * * *Midnight and noon
Daily at midnight0 0 * * *The default "nightly job" schedule
Daily at 9am0 9 * * *Every day, including weekends
Daily at noon0 12 * * *12:00, 24-hour format — not 12 12 * * *, which is 12:12pm
Twice daily, 9am and 9pm0 9,21 * * *Comma-separated hour list, both in 24-hour format
Weekdays at 9am0 9 * * 1-5Monday through Friday only
Weekdays at 6pm0 18 * * 1-5End-of-business-day job, skips weekends
Every 15 minutes during business hours on weekdays*/15 9-17 * * 1-59am–5pm, Mon–Fri — the hour range and the step syntax combine cleanly
Every Monday at 9am0 9 * * 1Weekly job, single day
Every Friday at 5pm0 17 * * 5End-of-week job
Weekends at 10am0 10 * * 0,6Saturday and Sunday only
Weekly reset, Sunday midnight0 0 * * 0Common for weekly usage counters and report resets
First day of the month at midnight0 0 1 * *Billing cycles, monthly reports
Twice a month, 1st and 15th0 0 1,15 * *Semi-monthly payroll and reconciliation jobs
Last day of every monthnot directly expressibleSee the worked example below — standard cron has no "last day" token
Quarterly, 1st of Jan/Apr/Jul/Oct at midnight0 0 1 1,4,7,10 *Fiscal-quarter jobs
Yearly, Jan 1st at midnight0 0 1 1 *Annual license/certificate rotation reminders

Worked examples

1. Every 6 hours, but not starting at midnight

The most common surprise with step syntax: */6 in the hour field doesn't mean "every 6 hours from whenever this job starts running." It means "every hour value that's a multiple of 6" — 0, 6, 12, 18. If you actually want the cycle offset (say, a job that should first run at 3am so it doesn't collide with a midnight backup), you have to abandon the step syntax and list the exact hours:

# Runs at 0, 6, 12, 18 — not what you want if 3am was the intent
0 */6 * * *

# Runs at 3, 9, 15, 21 — the actual offset schedule
0 3,9,15,21 * * *

See it live

Open the offset version in Cron Master and check the next 10 execution times — they land on 3am/9am/3pm/9pm, not the clock-aligned hours the step syntax alone would give you.

Open this example in Cron Master

2. The last day of the month, without a native token

This is the single most-searched cron schedule that standard cron simply cannot express directly. Day-of-month is a fixed field with no concept of "however many days this particular month has" — there's no way to write one expression that means the 28th in February and the 31st in a month like January. Two portable workarounds, depending on what your scheduler supports:

If your specific scheduler is Quartz, Jenkins, or a cron fork that documents an L token in the day-of-month field, that solves it natively — but that's a scheduler-specific extension, not standard POSIX cron, so verify against your own tool's docs rather than assuming it's portable.

See it live

The "run on the 1st, process yesterday" version — check that it lands on the 1st of every month regardless of how long the prior month was.

Open this example in Cron Master

3. Why "the first Monday of the month" isn't one field combination

A schedule like 0 9 1-7 * 1 looks like it should mean "9am on the first Monday of the month" — restrict the day-of-month to the first week, restrict the day-of-week to Monday. It doesn't work that way. When both the day-of-month and day-of-week fields are restricted (anything other than *), standard cron treats them as an OR, not an AND: this expression actually fires at 9am on the 1st through the 7th of every month and at 9am on every Monday, which in most months is six or seven runs, not one.

# Looks like "first Monday of the month at 9am" — it isn't.
# Fires on the 1st–7th (any weekday) AND every Monday (any date).
0 9 1-7 * 1

The portable fix is to run daily and check inside the job: schedule 0 9 1-7 * * (9am, every day 1st–7th) and have the job itself verify new Date().getDay() === 1 before doing real work, so it only actually executes on whichever of those seven days is the Monday.

Common gotchas, in one place

  1. Day-of-month and day-of-week combine with OR, not AND, whenever both are restricted. See worked example 3 above — this single misunderstanding accounts for a large share of "why did my cron job run on the wrong day" reports.
  2. Cron runs on the server's system timezone, not UTC and not the browser reading this page. Check with date on the actual machine, or set an explicit TZ= line in the crontab if your implementation supports it — don't assume.
  3. Step syntax (*/N) always counts from the field's zero point, never from whenever the job happens to start. */6 in the hour field is 0/6/12/18, full stop — see worked example 1 for the offset workaround.
  4. There's no native "last day of month" token in standard cron. See worked example 2 for the two portable workarounds.
  5. A missing environment does not mean a broken expression. If a job's schedule fires correctly (confirm with Cron Master's execution list) but the job itself fails, the cron expression isn't the bug — check PATH and other environment variables, since cron doesn't inherit your interactive shell's environment.

Frequently asked questions

What is the cron expression for every 15 minutes?

*/15 * * * * runs at minutes 0, 15, 30 and 45 of every hour — four times an hour, aligned to the clock. It is not "15 minutes from whenever the job was installed"; the step syntax always resets at the top of the hour.

How do I run a cron job on the last day of every month?

Standard cron (vixie-cron, the format used by crontab on Linux and most schedulers) has no "last day of month" token — months have 28 to 31 days and cron's day-of-month field can't express "whichever number that is this month." The portable fix is to schedule the job for the 1st of the following month at 00:00 and have it operate on the previous day, or run it daily and exit immediately unless tomorrow's date rolls into a new month. Some schedulers (Quartz, certain cron forks) support an L token for this directly — check your specific implementation before assuming it's unavailable.

Does cron run on UTC or my local time?

Neither, by default — cron runs on whatever timezone the server's system clock is set to, which is often UTC on cloud infrastructure but not guaranteed. It has nothing to do with the timezone of whoever is reading the crontab. Check with the date command on the actual machine running the job, or set an explicit TZ= line in the crontab (supported by most modern cron implementations) rather than assuming.

What happens if both the day-of-month and day-of-week fields are set?

Standard cron treats them as OR, not AND, whenever both are restricted (not *). A schedule like 0 9 1 * 1 doesn't mean "the 1st, if it's a Monday" — it fires on the 1st of every month AND every Monday, which is almost never what someone intended. If you need an actual AND (e.g. "the first Monday of the month"), you need scheduler-level logic or an application check inside the job, not a single cron field combination.

How do I schedule something every 6 hours starting at 3am instead of midnight?

0 */6 * * * runs at 00:00, 06:00, 12:00 and 18:00 — the step syntax always starts counting from 0, not from whenever you want the first run to land. To offset the whole cycle, list the exact hours instead: 0 3,9,15,21 * * * runs every 6 hours starting at 3am.

🧪 Paste any schedule and see exactly when it runs

Cron Master parses the expression entirely client-side and lists the next 10 execution times in any timezone — the fastest way to confirm a schedule does what you think before it's live in a crontab. The natural-language generator and AI logic breakdown send your prompt to Gemini; the parsing and execution list above them run locally and don't.

Open Cron Master →

← Back to Blog