Cron Expression Calculator

Translate a cron expression into plain English and list its next scheduled run times, with warnings for the day-of-week trap.

How to use this calculator

  1. 1Paste a cron expression, or use a shorthand like @daily.
  2. 2Read the plain-English summary and check each field was interpreted as you intended.
  3. 3Scan the next run times — they are the fastest way to catch a schedule that fires more often than you meant.

How the calculation works

┌ minute (0-59) ┌ hour (0-23) ┌ day of month (1-31) ┌ month (1-12) ┌ day of week (0-6, Sunday = 0) * * * * *
*
Every value in this field
*/n
Every n-th value, counting from the start of the field's range
a-b
A range, inclusive of both ends. Ranges do not wrap around
a,b,c
A list of specific values
0 and 7
Both mean Sunday in the day-of-week field

When both the day-of-month and day-of-week fields are restricted, cron matches if EITHER is satisfied, not both. This is deliberate historical behaviour, and it is the most common source of cron bugs — "0 0 13 * 5" fires on the 13th and on every Friday, not on Friday the 13th.

Step values count from the start of the field's range, not from the current time. "*/40" in the minute field gives runs at :00 and :40 — the gap from :40 back to :00 is 20 minutes, not 40.

Month and day-of-week fields also accept three-letter names, so "0 0 * jan mon" is valid and often clearer than the numeric form.

Standard Unix cron has no seconds field. Six-field expressions come from Quartz, Spring and some container schedulers, where the extra leading field is seconds.

Worked example

Every weekday at 9:30 am

  1. 1.Minute 30, hour 9 — so 09:30.
  2. 2.Day of month is *, meaning no restriction from that field.
  3. 3.Month is *, so every month.
  4. 4.Day of week 1-5 is Monday through Friday.
  5. 5.Only one day field is restricted, so there is no OR ambiguity here.
  6. 6.Result: 09:30 every Monday to Friday, skipping weekends.

Result: 09:30, Monday to Friday

The Friday the 13th trap

  1. 1.This looks like it means midnight on Friday the 13th.
  2. 2.It does not. Both day-of-month (13) and day-of-week (Friday) are restricted.
  3. 3.When both are restricted, cron matches if EITHER is true — the fields are OR-ed.
  4. 4.So this fires on the 13th of every month, AND on every Friday.
  5. 5.That is roughly 5 runs a month rather than the once or twice a year intended.
  6. 6.Getting true "Friday the 13th" behaviour needs a date check inside the job itself.

Result: Every 13th and every Friday — not Friday the 13th

An uneven step

  1. 1.Minute 0, and hour */5 means every 5th hour counting from 0.
  2. 2.That gives hours 0, 5, 10, 15 and 20 — five runs a day.
  3. 3.The gap from 20:00 to the next run at 00:00 is only 4 hours, not 5.
  4. 4.Steps count from the start of the field range, and 5 does not divide 24 evenly.
  5. 5.For genuinely even spacing, choose a step that divides its range: 2, 3, 4, 6, 8 or 12 hours.

Result: 00:00, 05:00, 10:00, 15:00, 20:00 — then a 4-hour gap

The OR rule that catches everyone

Cron's five fields normally combine with AND: the job runs when the minute matches and the hour matches and the month matches. The two day fields are the exception, and the exception is not intuitive.

When both day-of-month and day-of-week are restricted — neither is * — cron runs the job if either matches. So "0 0 13 * 5" does not mean "midnight on Friday the 13th". It means "midnight on the 13th, or midnight on any Friday", which is around five times a month instead of once or twice a year.

The behaviour dates to Paul Vixie's cron in the 1980s and was kept for compatibility; POSIX subsequently standardised it. It is not a bug, but it surprises nearly everyone, and it is a genuinely common cause of jobs running far more often than intended.

There is no way to express a true AND of the two day fields in standard cron. The usual solution is to schedule the broader pattern and check the date at the top of the script itself.

Steps count from the range, not the clock

A step value like */15 means "every 15th value starting from the beginning of this field's range", which is not the same as "every 15 minutes from now". For minutes, both readings agree, because 15 divides 60 evenly: runs land at :00, :15, :30 and :45.

Choose a step that does not divide evenly and the two readings part company. "*/40" in the minute field gives :00 and :40 only — the gap from :40 to the next :00 is 20 minutes. "*/5" in the hour field gives 0, 5, 10, 15 and 20, leaving a 4-hour gap overnight rather than 5.

The fix is to pick steps that divide their range: 1, 2, 3, 4, 5, 6, 10, 12, 15, 20 or 30 for minutes, and 1, 2, 3, 4, 6, 8 or 12 for hours. Anything else produces a short final interval every cycle.

Time zones and the hours that do not exist

Cron runs in the system time zone, which on servers is usually UTC but not always, and on a developer laptop is usually local. An expression that behaves correctly in testing can fire at the wrong hour in production purely because the zone differs.

Daylight saving makes it worse. When clocks spring forward, the skipped hour simply does not occur — a job scheduled for 02:30 does not run at all that day on many implementations. When clocks fall back, the repeated hour can cause a job to run twice.

The practical advice is unchanged since the problem was first noticed: run servers in UTC, and avoid scheduling anything important between 01:00 and 03:00 local time. If a job absolutely must run once per calendar day in a specific zone, make it idempotent and let it check whether it has already run.

Five fields, six fields, and dialects

Standard Unix cron has five fields and no concept of seconds — the shortest possible interval is one minute. Six-field expressions, where the leading field is seconds, come from Quartz, Spring, and several container schedulers. Pasting one into a Unix crontab shifts every field by one position and produces a schedule bearing no relation to what was intended.

Dialects also differ in extensions. Vixie cron adds the @daily and @hourly shorthands; Quartz adds ? for "no specific value", L for "last", and W for "nearest weekday". None of the Quartz extensions work in a standard crontab.

This calculator reads the five-field standard with the common shorthands, and rejects six-field input explicitly rather than misinterpreting it.

What this assumes, and where it stops

Assumptions

  • Five-field standard Unix cron syntax, as used by Vixie cron and specified by POSIX.
  • Times are calculated and displayed in the browser's local time zone.
  • Day-of-week uses 0 for Sunday, with 7 also accepted for Sunday.
  • Both 0 and 7 in the day-of-week field are treated as the same day.

Limitations

  • Standard five-field syntax only. Six-field expressions with seconds are rejected rather than guessed at, and Quartz extensions such as L, W and # are not supported.
  • Next runs are shown in your local time zone, not the server's. A server running in UTC will fire at different local times.
  • Does not model daylight saving transitions. Jobs scheduled in the skipped or repeated hour may run zero or two times on those two days a year.
  • The search looks four years ahead. An expression matching nothing in that window is reported as never running.

Common questions

What do the five fields in a cron expression mean?

In order: minute (0–59), hour (0–23), day of month (1–31), month (1–12), and day of week (0–6, with Sunday as 0). An asterisk means every value. So "30 9 * * 1-5" is 09:30 on Monday through Friday.

Why does my cron job run more often than expected?

Almost always the day-of-week trap. If both the day-of-month and day-of-week fields are restricted, cron runs the job when either matches, not both. "0 0 13 * 5" fires on the 13th and on every Friday — about five times a month, not on Friday the 13th.

How do I run a job every 15 minutes?

Use "*/15 * * * *", which fires at :00, :15, :30 and :45 past every hour. It works out evenly because 15 divides 60. A step that does not divide its range, such as */40, leaves a short gap at the end of each hour.

Can cron run a job every 30 seconds?

Not in standard Unix cron, which has no seconds field and a one-minute minimum resolution. The usual workarounds are two offset entries with a sleep, a systemd timer, or a scheduler such as Quartz that supports six-field expressions.

Sources

Formula and content last reviewed on .

Results are estimates for information only, not professional advice.

Report an error

Tools people commonly use alongside the cron expression calculator.

See all developer tools calculators →