Skip to content

Cron Expression Generator: Build Cron Schedules Without Guesswork

Free cron expression generator and explainer — see the next run times in plain English, and avoid the day-of-month/day-of-week OR-not-AND mistake.

Try it now: Cron Expression Parser Explain a cron expression in plain English and list the next times it will actually run, in UTC or your own timezone — step values and weekday ranges included.

The Five Fields, in Order

Building a cron expression by hand means getting five space-separated fields right, always in the same order: minute hour day-of-month month day-of-week. A cron expression generator exists because that ordering, plus the syntax each field accepts, is easy to get subtly wrong under time pressure — no seconds field in standard cron, no year field. Each position accepts a number, a *wildcard meaning “every value,” a step (*/5), a range (1-5), or a comma-separated list of any of those. The expression below runs a job at 6:30 in the morning, every day of the month, every month, but only on weekdays.

30 6 * * 1-5
30 6 * * 1-5
│  │ │ │ │
│  │ │ │ └─ day-of-week: 1-5 = Monday through Friday
│  │ │ └─── month: * = every month
│  │ └───── day-of-month: * = every day of the month
│  └─────── hour: 6 = 6am
└────────── minute: 30 = the 30th minute

→ runs at 06:30, Monday-Friday

Day-of-week is numbered 0-6, and both 0 and 7 mean Sunday depending on the implementation — one more reason to check what a cron schedule actually resolves to rather than trust a mental read of it.

Steps and Ranges: */5 and 1-5 Are Not the Same Shape

A step value (*/N) means “every N units, starting from the field's minimum.” A range (A-B) means “every value from A through B, inclusive.” They're easy to mix up because both use a small amount of punctuation to compress a lot of meaning, and a crontab generator that only lets you type the raw string gives you no feedback if you reach for the wrong one.

  • */15 * * * * — every 15 minutes, every hour, every day: runs at :00, :15, :30, :45.
  • 0 9-17 * * * — the top of every hour from 9am through 5pm inclusive: nine runs a day, not a continuous range.
  • 0 0 1,15 * * — midnight on the 1st and the 15th of the month, using a list instead of a range.

The Field Everyone Gets Wrong: Day-of-Month and Day-of-Week Are OR'd, Not AND'd

This is the single most consequential thing to understand about cron syntax, and it's the opposite of what most people assume. If you restrict both the day-of-month field and the day-of-week field in the same expression — leaving neither one as *— standard cron semantics do not treat that as “this day-of-month, and only if it also happens to fall on this weekday.” They treat it as “this day-of-month, or this weekday, whichever occurs” — an OR, not an AND.

0 0 15 * 1 — what it looks like it means vs. what it runs on
0 0 15 * 1

It looks like it should mean:
  "Midnight on the 15th, but only if the 15th is a Monday."
  → intended: roughly once every few months

What it actually means (day-of-month OR day-of-week):
  "Midnight on the 15th of every month, OR midnight on every Monday."
  → actual: runs on the 15th every single month, AND on every Monday
     — dozens of runs a year, not the handful that were intended

The rule flips only when one of the two fields is left as *. 0 0 15 * * means exactly what it looks like — midnight on the 15th, every month, day-of-week unrestricted. 0 0 * * 1 means midnight every Monday, day-of-month unrestricted. The OR behavior only kicks in once you restrict both fields at the same time, which is precisely the case someone reaches for when they're trying to express an AND condition — and precisely why this is a recurring, real source of jobs firing far more often than intended, silently, until someone notices the logs.

Why a Next-Run Preview Beats Reading the Expression

The day-of-month/day-of-week gotcha above is exactly the kind of mistake that's easy to make while reading a raw expression and hard to make while looking at a list of concrete timestamps. Five fields of punctuation take real effort to mentally parse correctly every time; a list of the next ten actual run times — dates and hours, not symbols — is much harder to misjudge, because you're checking a prediction against your intent instead of decoding a small grammar under time pressure.

That's the reason an expression should be validated against its next few actual occurrences before it ships anywhere, not just checked for correct syntax. GenKitLab's Cron Expression Parser explains a cron expression in plain English and lists the next times it will actually run, in UTC or your own timezone — step values and weekday ranges included — and it runs entirely client-side, so no schedule or expression you type is ever uploaded anywhere.

Cron Runs in a Timezone — and DST Transitions Break the Simple Model

“This job runs at 9am” is an incomplete sentence. A cron daemon evaluates every schedule against whatever timezone it's configured for — often the server's local time, sometimes UTC by default depending on the platform — and the same expression produces a different wall-clock result depending on which one is in effect. Stating the timezone alongside the expression isn't optional precision; without it, “9am” and “the next run” are both genuinely ambiguous claims.

The subtler failure mode shows up twice a year, at a Daylight Saving Time transition, and only for schedulers configured to a local timezone rather than UTC. During the “spring forward” transition, an hour is skipped entirely — a job scheduled to run at 2:30am on that date may simply never fire, because 2:30am never happens. During “fall back,” an hour repeats — the same job can run twice, once for each occurrence of that local time. Both are silent by default: nothing errors, the job just runs zero times or two times instead of once. Scheduling in UTC sidesteps the problem entirely, which is the same reason UTC is the sane default for storing any timestamp — a topic covered in full in the Unix timestamp guide, alongside GenKitLab's Timestamp Converter.

Frequently asked 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, where both 0 and 7 can mean Sunday depending on the implementation). Standard cron has no seconds field and no year field.

What's the difference between a step value and a range in cron?

A step (*/N) means 'every N units starting from the field's minimum' — */15 in the minute field runs at :00, :15, :30, :45. A range (A-B) means every value from A through B inclusive — 9-17 in the hour field means the top of every hour from 9am through 5pm, nine runs a day.

If I restrict both day-of-month and day-of-week, does cron AND or OR them?

It ORs them. 0 0 15 * 1 does not mean 'the 15th, only if it's a Monday' — it means 'the 15th of every month, OR every Monday,' which runs far more often than an AND interpretation would. The OR behavior only applies when both fields are restricted; leaving either one as * gives the straightforward, expected result.

Why not just read the cron expression to check it's correct?

Because the OR-not-AND rule and similar edge cases are easy to misjudge on a quick read of the raw punctuation, and much harder to misjudge when you're looking at a concrete list of the next several actual run times instead. Checking the expression against its own predicted output catches mistakes that checking the syntax alone does not.

What timezone does a cron schedule run in?

Whatever timezone the scheduler is configured for — often the server's local time, sometimes UTC by default, depending on the platform. 'Runs at 9am' is ambiguous without naming the timezone, since the same expression produces a different wall-clock result under each.

Can a cron job get skipped or run twice because of Daylight Saving Time?

Yes, for schedules evaluated in a local timezone that observes DST. During the 'spring forward' transition an hour is skipped, so a job scheduled inside that missing hour may not run at all that day. During 'fall back' an hour repeats, so the same job can run twice. Scheduling in UTC avoids both failure modes entirely.

Last updated