Cron Expression Explainer
Decode any cron schedule and preview the next run times.
At 09:00, on Monday, Tuesday, Wednesday, Thursday, and Friday.
| Minute | 0 | 0 |
| Hour | 9 | 9 |
| Day of month | * | every |
| Month | * | every |
| Day of week | 1-5 | 1, 2, 3, 4, 5 |
- Mon, Aug 31, 2026, 09:00 AMin 44 h
- Tue, Sep 01, 2026, 09:00 AMin 3 d
- Wed, Sep 02, 2026, 09:00 AMin 4 d
- Thu, Sep 03, 2026, 09:00 AMin 5 d
- Fri, Sep 04, 2026, 09:00 AMin 6 d
Times are shown in your local timezone. Uses standard 5-field cron with the day-of-month / day-of-week OR rule.
What is a cron expression?
A cron expression is a compact way to describe a recurring schedule. It is used by the classic Unix cron daemon, but also by Kubernetes CronJobs, GitHub Actions, Vercel Cron, AWS EventBridge, and most job schedulers. A single line answers one question: when should this task run?
Because the syntax is terse, it is easy to misread a schedule — and a wrong cron line can mean a job that never fires or one that hammers your system every minute. This tool decodes any expression into plain English, breaks down each field, and previews the next run times so you can confirm the schedule before you ship it.
The format has survived since the 1970s for a good reason: five numbers express almost every schedule an operations team actually needs, in a form short enough to sit in a configuration file. The cost of that compactness is readability, which is exactly the gap this page is here to close.
The five fields
A standard cron expression has five space-separated fields, in this order:
| Field | Range | Example |
|---|---|---|
| Minute | 0–59 | 0, 30, */15 |
| Hour | 0–23 | 9, 0-6, */2 |
| Day of month | 1–31 | 1, 15, L is not standard |
| Month | 1–12 or JAN–DEC | 1, JAN, 6-8 |
| Day of week | 0–7 or SUN–SAT | 1-5, MON, 0 and 7 = Sunday |
A * means “every” value for that field, so * * * * * runs every single minute.
Reading an expression is easiest right to left, because that establishes the calendar before the clock. Take 30 8 * * MON: on Mondays (day of week), in every month, on any day of the month, at hour 8, at minute 30. Half past eight every Monday morning.
Special characters
| Symbol | Meaning |
|---|---|
| * | Every value in the field |
| */n | Every n units — */15 in minutes is every 15 minutes |
| a-b | A range, inclusive — 1-5 for Monday to Friday |
| a,b,c | A specific list of values |
| a-b/n | Stepped range — 0-30/10 gives 0, 10, 20, 30 |
One subtlety catches people out: */n steps from the start of the field’s range, not from the current time. So */20 * * * * fires at minutes 0, 20, and 40 of every hour — not twenty minutes after you deployed it. And when n does not divide evenly into the range, the interval is uneven at the boundary: */7 in the minutes field runs at 0, 7, 14, 21, 28, 35, 42, 49, and 56, then waits only four minutes before 0 comes round again.
Common schedules
| Schedule | Expression |
|---|---|
| Every minute | * * * * * |
| Every 15 minutes | */15 * * * * |
| Every hour, on the hour | 0 * * * * |
| Every 6 hours | 0 */6 * * * |
| Every day at 9:00 AM | 0 9 * * * |
| Twice a day, 6 AM and 6 PM | 0 6,18 * * * |
| Weekdays at 9:00 AM | 0 9 * * 1-5 |
| Every Monday at 8:30 AM | 30 8 * * MON |
| Weekends at midnight | 0 0 * * SAT,SUN |
| First of every month, midnight | 0 0 1 * * |
| Last quarter-hour of business, weekdays | 45 17 * * 1-5 |
| Once a year on 1 January | 0 0 1 1 * |
The mistakes that actually cause outages
Most cron bugs are not exotic. They are a handful of predictable misunderstandings, and they tend to be discovered in production rather than review.
Day-of-month and day-of-week are OR, not AND
This is the single most surprising rule in cron. When both the day-of-month and day-of-week fields are restricted — neither is * — the job runs when either matches, not both. So 0 0 13 * FRIdoes not mean “Friday the 13th”. It means the 13th of every month and every Friday, which is roughly sixty runs a year instead of one or two. If only one of the two fields is *, the other behaves the way you expect.
The timezone is the server’s, not yours
A cron expression carries no timezone. The schedule is interpreted by whatever the host says local time is, which on most servers and nearly all container images means UTC. A job you wrote as “9 AM” while sitting in India will fire at 2:30 PM IST if the host runs UTC. Confirm the environment before trusting a schedule, and prefer being explicit — many modern schedulers accept a timezone setting alongside the expression.
Daylight saving time creates gaps and repeats
On a host with a DST-observing timezone, the clock skips forward once a year and back once a year. A job scheduled at 2:30 AM may be skipped entirely on the spring transition and run twice on the autumn one. This is a genuinely good argument for running schedulers in UTC and converting at the edges.
Overlapping runs
Cron starts a job on schedule regardless of whether the previous run has finished. A task scheduled every five minutes that occasionally takes seven will quietly begin stacking instances, and the failure mode — exhausted connections, duplicated writes — usually shows up under exactly the load that made it slow in the first place. Use a lock file, an advisory lock, or your scheduler’s concurrency policy.
Missing minutes at midnight
0 0 * * * is midnight. * 0 * * * is every minute of the midnight hour — sixty runs. A single misplaced star is the difference between a nightly job and an hourly stampede, which is why previewing next run times before deploying is worth the ten seconds it takes.
Non-standard extensions
Cron implementations vary, and expressions are not always portable between them. Some common extensions are widely supported but not part of the classic five-field standard:
| Syntax | Meaning | Where it works |
|---|---|---|
| @daily, @hourly | Shorthand for 0 0 * * * and 0 * * * * | Most Unix crons, many CI systems |
| @reboot | Run once when the machine starts | Unix cron; not in most hosted schedulers |
| L | Last day of month or last given weekday | Quartz, Spring, AWS EventBridge |
| W | Nearest weekday to a date | Quartz, Spring |
| # | Nth weekday of the month — FRI#3 | Quartz, Spring, AWS EventBridge |
| Seconds field | A sixth leading field for seconds | Quartz, Spring, node-cron |
This tool follows the standard five-field Unix interpretation, which is the safest common denominator. If your scheduler uses a six-field format with seconds, drop the leading field before pasting an expression here, and check your platform’s documentation before relying on L, W, or #.
Writing schedules that behave well
- Avoid the top of the hour for heavy jobs. Everyone schedules at
0. Moving a batch job to minute 7 or 23 spreads load away from the moment every other system on the box also wakes up. - Stagger related jobs. If three tasks all hit the same database, give them different minutes rather than letting them contend.
- Make jobs idempotent. Schedulers retry, hosts restart, and DST repeats an hour. A job that is safe to run twice is a job you do not have to think about.
- Log the start and the finish. A job that silently stopped running looks identical to one that never had anything to do.
- Leave a comment above the expression. The plain-English description this tool generates is exactly what belongs on the line above the cron entry in your config.
Always verify against the real environment
Next run times here are calculated in your browser’s local timezone using standard cron rules. Your scheduler’s timezone, DST handling, and support for extended syntax may differ. Treat this as a check on your understanding, not a guarantee about production. See the disclaimer.