Cron Expression Parser
Paste any cron expression to get a plain-English description of when it runs, plus the next several fire times - validated and computed in your browser.
- Free, no account
- No watermark
- No usage limit
About the Cron Expression Parser
Paste a cron line and this parser reads it back in plain English, then lists the next five times it actually fires as real dates. Free, no sign-up, and the whole thing runs in your browser so nothing gets uploaded. Type 0 9 * * 1 and you get back "At 09:00, on Monday" plus the next five Mondays it'll trigger.
That next-run list is the point, more than the translation. Most of us can half-read a cron line and feel sure we've got it, and cron has one rule that runs backwards from how everyone reads it. So the real test is the next five dates. If they match what you pictured the line is right, and if they don't you just caught a bug before it shipped instead of at 3 AM when the backup ran twelve hours off.
Take 0 0 13 * 5. Read it out loud and most people land on "midnight on Friday the 13th," which is not what it does. Neither day field starts with a *, and in that case cron fires whenever either one matches. So that line runs at midnight on every 13th of the month and again every Friday, which can be five or six nights instead of the single one you pictured. This parser is built around catching exactly that: it writes OR into the description on purpose, the panel says why, and the next-run list computes the real OR schedule, so the dates on screen are the dates your scheduler will actually pick.
How to use
- Paste your expression into the box. Standard five fields, space-separated: minute, hour, day-of-month, month, day-of-week. Something like
30 8 * * 1-5. - Read the plain-English line. It comes back as a sentence, "At 08:30, Monday through Friday," so you can sanity-check the meaning in a second.
- Scan the next five run times. Real dates, computed from right now. This is where a misread shows itself, if the dates look wrong the expression is wrong.
- Flip the time zone. Toggle between your local zone and UTC (more on why that matters below).
- If a field is out of range or malformed you get a specific message naming the field and the problem, not a stack trace.
The day-field trap, in full
This is the most misread rule in cron, and it's worth slowing down on because your eyes will lie to you here.
Normal intuition says a schedule with a day-of-month AND a day-of-week both filled in should mean "only when both line up", and cron often reads it the other way entirely. crontab(5) puts it like this: "If both fields are restricted (i.e., aren't *), the command will be run when either field matches the current time."
The code is narrower than that sentence, and this is where even careful readers get caught. Vixie cron decides the operator from the FIRST CHARACTER of each day field, before it parses the field at all. If either field begins with a * it uses AND, and only if neither does will it use OR. That splits two cases the man page's wording puts on the same side:
0 0 */2 * 5looks restricted in both day fields, so the sentence predicts OR. But*/2begins with a star, so cron ANDs: odd-numbered days that are also Fridays, roughly 26 nights a year rather than the 212 an OR would give.0 0 1-31 * 5also looks restricted in both, and here cron really does OR.1-31covers every day there is, so the union is every day, and the job runs nightly rather than on Fridays.
This parser reads the raw tokens the same way cron does, so the word in the description and the dates in the list both follow the implementation rather than the paraphrase.
The practical upshot: leave one of the two day fields as a plain * and you're safe, because an AND against "every day" is just the other field deciding, exactly as you'd expect. Restrict both with fixed values only when you actually want the union. And if what you really need is "Friday the 13th, and only then," plain cron can't say it in a single line. You schedule the looser trigger, 0 0 13 * * for every 13th, and add an "is it Friday?" check at the top of the script.
The reason this tool exists is to make that invisible rule visible. It names the operator in words, says which character decided it, and proves it in dates, so a schedule that would have quietly fired five extra times a month gets caught while you're still looking at it.
"9 AM" where, exactly?
Your line says 0 9 * * * and you're picturing 9 in the morning. The question the machine cares about is 9 AM on whose clock. Cron fires against the clock of the box that runs it, and that box is very often not set to your zone. GitHub Actions cron runs in UTC, no exceptions. AWS EventBridge scheduled rules default to UTC. Piles of cloud servers ship set to UTC by convention. So 0 9 * * * on GitHub Actions goes off at 9 AM UTC, which could be 4 AM or 1 AM where you sit.
That's the reason for the UTC toggle. By default the run list is in your browser's local zone, which answers "when does this hit me." Switch it to UTC to see what a UTC-based scheduler does with the same string. When those two disagree with your intention, you've found a time-zone bug before it fired at the wrong hour, and setting the right hour is just arithmetic from there (0 14 * * * for a 9 AM run at UTC minus 5).
The step that doesn't step evenly
One more reading mistake worth knowing, because it looks fine until you check the dates. A step like */15 in the minute field means every 15 minutes, and it lands clean at :00, :15, :30, :45. But steps count from the field's minimum and reset at the wrap, they don't space themselves evenly around the clock. So */40 fires at :00 and :40, then the hour rolls over and it starts again at :00. The real gap between :40 and the next run is 20 minutes, not 40. You'd never guess that from the string, and it's the kind of thing the next-run list surfaces on sight because the timestamps come out uneven.
Frequently asked questions
Is Sunday 0 or 7 in the day-of-week field?
Sunday is 0 in the standard numbering, with Monday through Saturday as 1 through 6. A lot of systems also take 7 for Sunday, so both point at the same day, and this parser reads either and folds 7 back to 0. If you're writing for a system you don't know well, use 0. It's accepted everywhere while 7 isn't guaranteed.
Can it read a six-field expression with seconds?
No, it reads the standard five fields that Linux crontab, GitHub Actions, and most cloud schedulers use. A few tools (Quartz, Spring's @Scheduled, some node-cron setups) put a seconds field at the front, so the string looks the same but every value shifts one place. Paste one of those and the parser spots the extra field and tells you, rather than silently reading your minute as seconds. Drop the leading value and it parses.
It's a valid expression but shows no upcoming runs. What gives?
You've most likely written a date that can't happen, like 0 0 30 2 * for February 30th. The syntax is legal so the parser accepts it, but there's no real moment that matches, so it reports nothing in the next fifty years instead of hanging. Check the day-of-month against the month, that's usually where an impossible combination hides.
Does daylight saving time move my schedule?
If your scheduler runs in UTC, no. UTC has no DST, so the job stays put on the absolute timeline while your local clock shifts under it, and a "9 AM" run quietly becomes 8 or 10 twice a year. If it runs in a local zone that observes DST, the spring-forward can skip a time and the fall-back can repeat one. Either way, keep anything time-sensitive out of the roughly 2 to 3 AM window where the clock jumps.
Does it handle `L`, `W`, or `#`?
No. Those are non-standard extensions, mostly from Quartz: L is the last day of the month, W the nearest weekday to a date, # the nth weekday (6#3 is the third Saturday). Standard Unix cron has none of them, so neither does this. For an expression that leans on those, reach for your platform's own validator.
What about `@reboot`?
@reboot runs once when the machine starts, not at any clock time, so there's no future timestamp to list. The parser recognizes it and says so rather than pretending it can predict a run. The other @ shortcuts (@daily, @hourly, @weekly, @monthly, @yearly) do map to real clock times, and the tool expands each to its five-field form so you can see that @weekly is just 0 0 * * 0.