Cron Explainer

Paste a cron expression and get two things: a sentence saying what it means, and the next ten times it actually fires, computed in a timezone you pick. The second half is what catches the mistakes, because "at 00:30 every day" reads fine right up until you see the runs land at 20:00 in the timezone your users are in.

Try an example loads */15 9-17 * * MON-FRI, a business-hours schedule.

The next ten runs are the half that catches errors

Every free cron tool translates the fields into English. Almost none of them run the schedule forward, and the translation on its own hides three whole categories of mistake.

  • The timezone. Your expression is evaluated in the timezone of the box it runs in, which is usually UTC and almost never the one you were thinking in. 30 0 * * * means half past midnight, but half past midnight where? Pick New York from the dropdown and the runs come back as 04:30Z during daylight saving and 05:30Z outside it. Seeing those two different UTC times in one list is the fastest way to understand what your schedule really does.
  • Dates that never happen. 0 0 30 2 * translates cleanly to "at 00:00, on the 30th of the month, in February". It also never fires, ever. The run list comes back empty with a note, which is unmissable in a way that a well-formed English sentence is not.
  • The two-day-field rule. More on that below, and the run list is the only thing that makes it obvious.

The runs are computed by walking the calendar forward, not by approximating. Month lengths, leap years and daylight saving transitions are all handled: a slot that a spring-forward skips is skipped, because it genuinely does not exist that day.

Worked example

Paste */15 9-17 * * MON-FRI and this comes back:

Every 15 minutes, during hours 9 through 17, on Monday, Tuesday,
Wednesday, Thursday and Friday

FIELDS
minute            */15         every 15 minutes
hour              9-17         9 through 17
day of the month  *            every day of the month
month             *            every month
day of the week   MON-FRI      Monday through Friday

NEXT 10 RUNS (UTC)
Thu 2026-09-03 09:00:00
Thu 2026-09-03 09:15:00
Thu 2026-09-03 09:30:00
Thu 2026-09-03 09:45:00
...

The per-field table matters as much as the sentence. When an expression is wrong, it is wrong in one field, and a table that shows each field's raw text next to what it resolved to points straight at it.

The two-day-field rule, which almost nobody knows

When both the day-of-month and the day-of-week fields are restricted, standard cron treats them as OR, not AND. 0 0 1 * MON does not mean "the first of the month, if it is a Monday". It means "the first of the month, or any Monday", which is roughly five times as many runs as most people expect.

This behavior is in the POSIX specification and in every crontab implementation, and it surprises nearly everyone the first time. When both fields are restricted, this page raises a note saying so, and the run list follows the real rule so you can see the consequence rather than take it on trust.

Quartz sidesteps the whole thing with ?, which means "no opinion" and goes in whichever of the two day fields is not doing the work. 0 0 1 * ? is unambiguously the first of the month. ? is accepted here and treated as a wildcard.

Five fields, six fields, and the Quartz extensions

Five fields is plain crontab: minute, hour, day of month, month, day of week. Six fields puts seconds in front, which is the Quartz and Spring convention. Both are accepted, and which one it read is stated in a note rather than assumed silently, because a six-field expression misread as five is off by a factor of sixty.

The Quartz extensions are understood in the fields where they are legal:

WrittenFieldMeans
Lday of monththe last day of the month
LWday of monththe last weekday of the month
15Wday of monththe weekday nearest the 15th
FRILday of weekthe last Friday of the month
6#3day of weekthe third Saturday of the month

Used in a field where they are not legal, they get an error naming which field they belong in. Month and day names work everywhere: JAN, JUL, MON-FRI, SAT,SUN. Sunday is accepted as both 0 and 7. The nicknames @daily, @hourly, @weekly, @monthly, @yearly and @midnight are expanded, with a note saying what they expanded to. @reboot gets a sentence explaining that it fires once at boot and therefore has no schedule to list.

Validation with reasons

Every field is range-checked, and the error says what was wrong rather than that something was:

  • 0 25 * * *: "25 is outside the hour range 0 to 23."
  • 0 0 * * 9: "9 is outside the day of the week range 0 to 7."
  • bogus 0 * * *: "bogus is not a number the minute field understands."
  • 0 0 *: "A cron expression has five fields, or six with seconds in front. This one has 3."
  • */0 * * * *: "has a step of 0, which must be a whole number of at least 1."

Wrapping ranges are legal and handled: FRI-MON in the day-of-week field means Friday, Saturday, Sunday and Monday, not an error. So is a step from a starting value, 5/20, which means "from 5, every 20" and gives minutes 5, 25 and 45.

Frequently Asked Questions

Why do the next runs not match what my server does?

Almost always the timezone. Change the dropdown to whatever your scheduler runs in, which for a container is usually UTC. If they still differ, check whether your scheduler reads five fields or six: a six-field expression handed to a five-field scheduler shifts every field by one position.

What does the OR warning about the two day fields mean?

That when both the day-of-month and the day-of-week fields are restricted, cron fires on a matching day of the month or a matching day of the week, not only on days matching both. 0 0 1 * MON runs on the first of every month and on every Monday. Use ? in the field you do not care about if your scheduler is Quartz.

Does it handle daylight saving?

Yes. The runs are computed against the real calendar for the timezone you chose, so a spring-forward skips the slot that does not exist that day and an autumn fall-back does not double it. This is precisely the case where reading the English sentence tells you nothing useful.

Which seconds convention does the six-field form use?

Seconds first, which is what Quartz, Spring and most Java schedulers use. Some systems put seconds last instead. The note above the result says how it read the expression, so a mismatch is visible straight away.

Why is my run list empty?

Because the schedule never fires. The usual cause is a day-and-month combination that does not exist, such as the 30th of February, or the 31st of a month that has only 30 days combined with a single-month restriction. The note under the empty list points at those two fields.

Can I paste a whole crontab file?

The first non-blank, non-comment line is read. Crontab lines carry a command after the schedule, and that is ignored, so pasting a full line from a crontab works. For several schedules, run them one at a time.

Does anything I paste leave my computer?

No. There is no upload endpoint on this page and no network request in the code that does the work. JavaScript in your own tab reads the text, processes it and hands back the result. Nothing is stored between visits either, so reloading gives you an empty box again. You can confirm it by opening your browser's network panel and watching it stay quiet while you work.

See when it actually runs

Free, no account, no upload. Plain English, plus the next ten fire times in your timezone.

Back to the explainer