Cron expression parser
Explain a cron expression in plain English and show exactly when it will next run.
The rule that catches everyone
When both the day-of-month and the day-of-week fields are restricted — neither is * — cron fires when either matches, not both. So 0 0 1 * MON runs on the first of every month and on every Monday, not on Mondays that happen to fall on the first.
This is not a quirk of one implementation. It is written into the crontab manual page, it has behaved this way since Vixie cron, and it is still the single most misread rule in the format. Expressions like 0 3 1 * 0 get written expecting a handful of runs a year and produce sixty. When both fields are set, this page says so explicitly and the schedule below shows you what it really means.
Real next-run times, not a description
Plenty of tools translate an expression into English. Far fewer tell you when it will actually fire, which is the question you usually have. The upcoming runs here are computed by walking forward through the calendar and applying the same matching rules cron does — including the OR rule — so a schedule that fires once a year shows you the date, and one that never fires says so instead of showing an empty box.
They are shown in your local time, because that is the frame you are reading them in. Do check what timezone the machine running the job is in: a container almost always runs UTC, and "runs at 02:30" means something different there.
What is supported
Five fields, or six with seconds first as Quartz and several schedulers use. Ranges (1-5), lists (1,3,5), steps (*/15, 0-20/2), three-letter month and day names (JAN, MON), ? as a synonym for *, and the shortcuts @yearly, @monthly, @weekly, @daily and @hourly. Both 0 and 7 mean Sunday.
@reboot is recognised and honestly refused: it fires when the machine starts, so there is no schedule to predict.
Invalid expressions are rejected with a reason
A minute of 60, an hour of 24, a range that runs backwards, a step of zero, the wrong number of fields — each gets a specific message rather than a shrug. This matters here more than usual: the old version of this tool on this site answered "Every minute" for every expression it was ever given, because the form and the handler disagreed about a field name and it was silently parsing an empty string. A cron parser that always agrees with you is worse than no parser.
29 February
A schedule of 0 0 29 2 * fires only in leap years. The upcoming-runs list makes that immediately obvious, which is a good deal quicker than reasoning about it.
Common questions
What does 0 0 1 * MON actually do?
It runs on the first of every month AND every Monday. When both day fields are restricted, cron treats them as OR. It is the most common misunderstanding in the format.
What is the difference between 5 and 6 fields?
Five is standard Unix cron: minute, hour, day of month, month, day of week. Six adds seconds at the front and is used by Quartz and several job schedulers. Both are accepted.
Is 0 or 7 Sunday?
Both. Cron accepts either, and they are treated as the same day here.
What timezone are the runs shown in?
Yours. Check what the machine running the job uses — containers are almost always UTC, and that shifts every time you see here.
Why does my expression never fire?
Usually an impossible date, like 31 February, or a month and day combination that never coincides. The tool says so rather than showing an empty list.
Does @reboot work?
It is recognised but has no schedule to show — it fires when the machine boots, which is not a time this or anything else can predict.