⏰

Cron Expression Generator & Descriptor

Build, explain and preview cron schedules

0
minute
0-59
9
hour
0-23
*
day of month
1-31
*
month
1-12 or jan-dec
1-5
day of week
0-6 or sun-sat
In plain English

At 09:00 on Monday, Tuesday, Wednesday, Thursday and Friday

Next runs (UTC)

  • Mon, Aug 31, 2026, 09:00 AM
  • Tue, Sep 1, 2026, 09:00 AM
  • Wed, Sep 2, 2026, 09:00 AM
  • Thu, Sep 3, 2026, 09:00 AM
  • Fri, Sep 4, 2026, 09:00 AM
  • Mon, Sep 7, 2026, 09:00 AM

Shown in your local time zone. Most schedulers — Vercel Cron, GitHub Actions and Kubernetes among them — evaluate cron in UTC, so convert before you ship.

Common schedules

Field Reference

`` ┌───────────── minute (0-59) │ ┌─────────── hour (0-23) │ │ ┌───────── day of month (1-31) │ │ │ ┌─────── month (1-12 or jan-dec) │ │ │ │ ┌───── day of week (0-6 or sun-sat, 0 and 7 = Sunday) │ │ │ │ │ * * * * * `

SyntaxMeaningExample
*Every value* * * * * = every minute
5That value5 * * * * = 5 past every hour
1-5Range0 9 * * 1-5 = 9am on weekdays
1,15List0 0 1,15 * * = 1st and 15th
*/15Step*/15 * * * * = every 15 minutes
5/10From 5, then step5/10 * * * * = 5, 15, 25, 35, 45, 55

The Day-Field Trap

This is the one that catches everyone:

ExpressionWhat people expectWhat cron does
0 0 13 * 5Friday the 13thEvery 13th and every Friday
0 0 1 * 1The 1st, if it is a MondayEvery 1st and every Monday
0 0 * * 1Every MondayEvery Monday ✓
0 0 1 * *Every 1stEvery 1st ✓
When *both* day fields are restricted, cron takes the union. To get an intersection you need a guard in the job itself:

`bash 0 0 13 * * [ "$(date +\%u)" = "5" ] && /run/job.sh `

Shorthands

AliasEquivalent
@yearly / @annually0 0 1 1 *
@monthly0 0 1 * *
@weekly0 0 * * 0
@daily / @midnight0 0 * * *
@hourly0 * * * *

Time Zones Are the Real Bug

PlatformEvaluates cron in
Unix crontabSystem local time
Vercel CronUTC
GitHub ActionsUTC
Kubernetes CronJobUTC unless spec.timeZone is set
AWS EventBridgeUTC unless specified
If a schedule crosses midnight when converted, the day-of-week field shifts too. Weekdays at 5pm in UTC-07:00 is 0 0 * * 2-6, not 0 0 * * 1-5.

Scheduling Sensibly

  • Avoid 0 * * * * for anything that hits a shared API — everyone's hourly job fires
at the same second. Use a random minute.
  • Make jobs idempotent. Cron will double-fire eventually: DST, a restart, a retry.
  • Never rely on the previous run finishing. Overlapping runs are the default; add a
lock file or a distributed lock.

Five Fields, Read Left to Right

` ┌───────── minute (0–59) │ ┌─────── hour (0–23) │ │ ┌───── day of month (1–31) │ │ │ ┌─── month (1–12) │ │ │ │ ┌─ day of week (0–6, Sunday = 0) │ │ │ │ │ * * * * * `

Each field takes a value, a list (1,15), a range (9-17), a step (*/5) or * for every value. Fields combine as an intersection — 0 9-17 * * 1-5 means hours 9 to 17 and Monday to Friday — with one important exception below.

The Traps, in Order of How Often They Bite

1. The two day fields take a union, not an intersection. This is the exception, and it surprises everyone. When both day-of-month and day-of-week are restricted, cron matches *either*:

` 0 0 13 * 5 # every 13th AND every Friday — not Friday the 13th `

Leave one as * unless you genuinely want both sets.

2. Steps are absolute, not relative. */10 matches minutes 0, 10, 20, 30, 40, 50 — not "ten minutes after the last run finished". If a job starting at 10:00 takes nine minutes, the next still starts at 10:10.

3. Steps that do not divide the range leave a gap. */7 in the minute field fires at 0, 7, … 56 and then waits four minutes. The clean hour divisors are 1, 2, 3, 4, 6, 8 and 12; for minutes, 1, 2, 3, 4, 5, 6, 10, 12, 15, 20 and 30.

4. The hour field is 0–23. Noon is 12, midnight is 0, and there is no am or pm. 12 0 * * * is twelve minutes past midnight, which is not what anyone means by it.

5. There is no L in POSIX cron. "Last day of the month" needs a guard in the job. Quartz and AWS EventBridge support L; crontab, Kubernetes, GitHub Actions and Vercel do not.

Time Zones Decide More Than People Expect

Standard crontab evaluates in system local time. **Vercel Cron, GitHub Actions, Kubernetes CronJobs and AWS EventBridge all evaluate in UTC.**

Converting a local time to UTC can move the day, and then the day-of-week field must move too. Weekdays at 5pm in UTC−07:00 is 0 0 * * 2-6 — Tuesday to Saturday — not 0 0 * * 1-5. Deploying the unconverted expression gives you a job that runs on the right clock time and the wrong days.

Local-time schedules also break twice a year: a job at 02:30 does not run at all on the spring-forward date, and may run twice on the fall-back date. Scheduling in UTC avoids both, at the cost of drifting an hour against local working hours.

Write Jobs That Survive Their Own Schedule

Cron guarantees far less than people assume, so the job has to make up the difference:

  • Assume it can run twice. Restarts, retries and DST all cause it. Make the work
idempotent rather than hoping.
  • Assume runs overlap. Cron starts the next one whether or not the last finished. Take a
lock:
flock -n /tmp/job.lock exits rather than queueing, which is what you want.
  • Avoid :00`. Every hourly job on the internet fires at the top of the hour. A random
minute spreads load on any shared dependency and removes a whole class of intermittent failure.
  • Alert on missing success, not on failure. A job that never starts produces no failure
to alert on, and that is the most common way a cron job dies quietly.

Finding the Expression You Want

The pages here are indexed by what you would say out loud rather than by syntax — [every 5 minutes](/dev/cron-expression-generator/cron-every-5-minutes), [every hour](/dev/cron-expression-generator/cron-every-hour), [weekdays at 9am](/dev/cron-expression-generator/cron-every-weekday), [business hours](/dev/cron-expression-generator/cron-business-hours), [first of the month](/dev/cron-expression-generator/cron-first-day-of-month), [last day of the month](/dev/cron-expression-generator/cron-last-day-of-month), [quarterly](/dev/cron-expression-generator/cron-every-quarter). Each parses its own expression field by field and previews the next runs, so you can check the schedule before deploying it rather than by waiting a day to find out.

Frequently Asked Questions

What do the five fields mean?

In order: minute (0-59), hour (0-23), day of month (1-31), month (1-12 or jan-dec) and day of week (0-6 or sun-sat, where both 0 and 7 mean Sunday). Some systems add a sixth seconds field at the front — Quartz and some Node libraries do; standard crontab does not.

Why did my job run on the wrong day?

Because cron ORs the two day fields when both are restricted. "0 0 13 * 5" runs on the 13th AND every Friday, not only on Friday the 13th. If both day-of-month and day-of-week are set, cron fires when either matches.

What time zone does cron use?

System local time for crontab, but UTC for Vercel Cron, GitHub Actions and Kubernetes CronJobs. This tool previews in your local zone and labels it, so convert before you deploy — a 5pm PT schedule is 0 0 * * * the next day in UTC.

What does */5 mean?

A step: every 5th value in the range. In the minute field, */5 means 0, 5, 10 … 55. Note that steps divide the range, they do not mean "every 5 minutes from now" — */7 in the minute field jumps from 56 back to 0, giving a 4-minute gap each hour.

Related Tools

Explore other tools you might find useful:

Specialized Versions

Try our targeted calculators for specific use cases:

Cron Every 5 Minutes
Cron for cron every 5 minutes
Cron Every Hour
Cron for cron every hour
Cron Every Day at Midnight
Cron for cron every day at midnight
Cron Every Weekday at 9am
Cron for cron every weekday at 9am
Cron Every Month
Cron for cron every month
Cron Every Week
Cron for cron every week
Cron Every Minute
Cron for cron every minute
Cron Every 10 Minutes
Cron for cron every 10 minutes
Cron Every 30 Minutes
Cron for cron every 30 minutes
Cron Every 2 Hours
Cron for cron every 2 hours
Cron Every 4 Hours
Cron for cron every 4 hours
Cron Every 6 Hours
Cron for cron every 6 hours
Cron Every 12 Hours
Cron for cron every 12 hours
Cron Daily at 2am
Cron for cron daily at 2am
Cron Daily at Noon
Cron for cron daily at noon
Cron Every Sunday
Cron for cron every sunday
Cron Every Friday at 5pm
Cron for cron every friday at 5pm
Cron Every Saturday
Cron for cron every saturday
Cron First Day of the Month
Cron for cron first day of the month
Cron Last Day of the Month
Cron for cron last day of the month
Cron on the 15th of the Month
Cron for cron on the 15th of the month
Cron Every Quarter
Cron for cron every quarter
Cron Every Year
Cron for cron every year
Cron During Business Hours
Cron for cron during business hours
Cron Every Weekend
Cron for cron every weekend
Cron Every Monday Morning
Cron for cron every monday morning
Cron Every Other Week
Cron for cron every other week
Cron Every Hour at Half Past
Cron for cron every hour at half past
Cron Every 3 Hours
Cron for cron every 3 hours
Cron Twice a Week
Cron for cron twice a week
Cron Every 20 Minutes
Cron for cron every 20 minutes
Cron Every 8 Hours
Cron for cron every 8 hours
Cron Daily at 6am
Cron for cron daily at 6am
Cron Every Wednesday
Cron for cron every wednesday
Cron Every Night at 11pm
Cron for cron every night at 11pm
Cron First Monday of the Month
Cron for cron first monday of the month