What this schedule actually does, and when it runs next
Paste a standard five-field cron expression and this calculator translates it into plain language, expands every field into the exact values it matches, and enumerates the real next run times in the time zone you choose, worked out day by day in that zone’s wall clock so daylight saving is handled honestly. It also implements the rule that surprises everyone once: when both the day-of-month and the day-of-week fields are restricted, cron runs when either matches, not only when both do.
Your expression
Disclaimer: This calculator gives estimates for general information only. It is not financial, medical or other professional advice. It implements standard cron (the Vixie/POSIX dialect used by Linux crontab); other schedulers (systemd timers, Quartz, cloud schedulers) extend or alter the dialect, notably around the day fields.
What this calculator does
It does the three things you actually need from a cron expression: what it says, when it fires next, and what each field is doing. The translation is generated from the parsed fields, not from pattern-matching a few famous expressions, so unusual schedules get a faithful field-by-field expansion instead of a wrong guess at a summary. The next runs are enumerated in your selected time zone’s wall clock, day by day, rather than by adding fixed UTC intervals, which means a 9:00 job stays at 9:00 local across a daylight saving change instead of drifting to 8:00 or 10:00 for half the year, and a run scheduled inside the spring-forward gap, at a wall time that does not exist, is skipped exactly as your server will skip it. The day-of-month and day-of-week interaction follows the standard cron rule (when both are restricted, either matching is enough), and the results flag when your expression triggers that rule, because it is the single most misread behaviour in the whole format.
How to use it
- Check the expanded fields, not just the summary. A summary sentence is a convenience; the field table is the truth. If the minutes field expands to 0, 15, 30, 45 when you meant only the quarter hour at one time of day, the table shows the misunderstanding before your server demonstrates it.
- The time zone is part of the schedule. The same expression on a server set to UTC and one set to your local zone are different schedules with different run times. Match the zone here to the zone your scheduler runs in (for many cloud servers, UTC whatever your laptop says), which is shown on each listed run so a mismatch is easy to spot.
- Start from a fixed moment when checking. “Next runs” from now changes every minute; for verifying a schedule you plan to rely on, set the start explicitly (the start of next month, say) and confirm the runs across a boundary, including across a daylight saving change if your zone has one.
- Preview count is for verification, not discovery. Ten runs expose the pattern and the first irregularity (a missing weekend, a double run on the 31st-following month) in almost every case. If ten clean runs look identical, the schedule is almost certainly what you think it is.
- Respect the flavour warning. This page speaks standard cron. Quartz adds a seconds field and a year field and treats the day fields differently; systemd uses calendar expressions that are not cron at all. An expression valid here may need translation there, and the field table is the safest thing to carry across.
How it is calculated
- Parsing: each field is expanded into the set of values it matches. Asterisk takes the full range; lists, ranges and steps combine as in standard cron; names map to numbers (JAN=1, SUN=0); day-of-week 7 folds to 0 (Sunday). Out-of-range values and malformed fields are rejected with the field named.
- Matching: a minute matches when its minute and hour are in their sets, its month is in the month set, and the day rule passes: if both day fields are restricted, the day passes when either the day-of-month or the day-of-week matches; if only one is restricted, that one must match; if neither is, every day passes.
- Enumeration: days in the chosen zone are examined in order, and for each matching day the matching hour and minute combinations are converted from zone wall time to real instants, sorted, filtered to after the start, and collected until the preview count is reached, searching up to five years ahead.
Worked examples
30 14 * * * from Tuesday 13 October 2026, 09:00 UTC. Every day at 14:30. The next runs are 13, 14 and 15 October 2026, each at 14:30 UTC, and the field table shows minutes {30}, hours {14} and asterisks everywhere else, which is the whole schedule; there is nothing else hiding in it.
0 9 15 * MON, the famous trap. Both day fields are restricted, so the either rule applies: this runs at 9:00 on the 15th of every month AND at 9:00 every Monday. From 13 October 2026 the next runs are Thursday 15 October, then Mondays 19 and 26 October and 2 November. Most people who write this expression mean “the Monday nearest the 15th” or “9:00 on the 15th if it is a Monday”, and standard cron offers neither; the results flag the rule precisely so the surprise happens here rather than in production.
*/15 * * * *. Every quarter hour: minutes {0, 15, 30, 45} of every hour. From 09:00 exactly, the next runs are 09:15, 09:30, 09:45 and 10:00, because runs are listed strictly after the start moment. The humblest expression in cron, and the one whose output best shows why the enumeration is worth having when an expression grows beyond it.
Reading your results
Read the field table first for intent, then the run list for reality. Patterns to catch: runs clustering at month boundaries (day 31 silently absent in shorter months), weekend gaps you did not intend, double runs where the either rule fires on a day that is both the 15th and a Monday, and the drift across a daylight saving change that the zone-aware enumeration shows correctly while a naive every-24-hours reading would not. If the first ten runs match the schedule in your head on all four checks, the expression is the schedule you meant to write.
Limitations
- Standard dialect only. Shortcuts like @daily and @weekly, the L, W and # extensions of Quartz, and seconds fields are not parsed. They are rejected rather than misread, and the error names the problem field.
- Ambiguous fall-back times resolve once. When clocks go back, a wall time like 1:30 occurs twice. Cron implementations differ in their handling; this enumeration resolves the wall time to its first occurrence and does not list the repeat. The spring-forward direction, a wall time that never occurs, is skipped by construction, matching standard behaviour.
- Five-year search horizon. An expression that can only fire on 29 February is found correctly (it recurs within four years); an expression that can never fire (31 April) is reported as finding no runs within five years rather than spinning forever, which is the correct diagnosis delivered politely.
- The scheduler still owns the machine. This page verifies the schedule an expression describes. Whether a given server runs it depends on the daemon being up, the machine being awake and the job itself succeeding, none of which an expression calculator can see.
Frequently asked questions
What does * * * * * mean?
Every minute of every hour of every day: each asterisk leaves its field unrestricted, so the job fires 1,440 times a day. It is almost never what anyone wants outside of testing, and its larger role is as the skeleton every real expression modifies, one field at a time. Changing the first field to */5 makes it every five minutes; pinning the first two fields to 30 14 makes it once a day at 14:30. Reading any expression as edits to that skeleton is the fastest way to fluency in the format.
Why did my job run on the wrong day?
Most often, the either rule: with both day fields set (0 9 15 * MON is the canonical case), cron fires when either matches, so the job runs on every 15th and every Monday, not on the intersection you intended. The second cause is time zone: the server’s zone, frequently UTC on cloud machines, decided what “9:00” meant. Both causes are visible on this page: the either rule is flagged in the results, and every listed run carries its zone.
How do I run something on weekdays only?
Restrict the day-of-week field to 1-5 and leave the day-of-month an asterisk: 0 9 * * 1-5 runs at 9:00 Monday to Friday. Because only one day field is restricted, the either rule never engages and the schedule is exactly the intersection you expect. The same shape handles most real schedules: one day field does the work, the other stays an asterisk, and surprises stay near zero.
Can cron run something every two weeks, or on the last day of the month?
Not in the standard dialect, and any tool claiming otherwise is selling you a workaround as a feature. Fortnightly needs a script that checks the week number itself; last-day needs a wrapper that compares tomorrow’s date (the classic pattern is running on days 28 to 31 with a test inside the job). What this page can do is verify the expression part of such setups exactly, which is the part that silently misfires when it is wrong.
Related calculators
Method: standard five-field cron parsing with the day-field either rule, day-by-day enumeration in the selected zone’s wall clock using the platform time zone database, exactly as defined on this page. Last reviewed: 13 October 2026.
