Cron Explainer
Paste a cron expression to read it in plain English, check every field, and see exactly when it will next run in your time zone, including the day-of-month / day-of-week OR rule and DST shifts. Evaluated in your browser.
Five fields (minute hour day-of-month month day-of-week), six with seconds first, or a macro
such as @daily.
Where your data goes
| Using this page | Using the API, MCP or A2A | |
|---|---|---|
| Where it runs | In your browser. Parsing, the English description and the run-time calculation run in the page with cron-parser, cronstrue and Luxon, using your browser's time-zone data. Nothing is sent anywhere. | In a Cloudflare Pages Function at the Cloudflare data centre nearest the caller. |
| What leaves your device | Nothing you enter. After the page and its scripts load, no request
carries your input. The browser enforces this: the page's Content-Security-Policy
sets connect-src 'none' and form-action 'none', which
block fetch, XHR, WebSocket, EventSource, beacons and form posts.
| The server receives the cron expression, zone and start time, evaluates them in memory, and returns the result. Your input is not stored or logged; only the per-call metadata row (operation, time, status, sizes) is recorded. |
| Stored | Nothing leaves the page. No cookies, analytics or third-party scripts; the browser keeps only your View → Inline config choice. | Your inputs and results: never. What is stored is your client record (client ID, a SHA-256 hash of your secret, expiry, and the profile you registered with) and one metadata row per call: operation, time, transport, status, error code, duration, request and response sizes, and country. |
| Logged | Nothing (no requests are made). | Only the per-call metadata above, attributed to your client ID. Never parameters, bodies, results, or credentials. Cloudflare, as the host, also processes request metadata (IP address, full URL including the query string, headers) under its own policies, so put inputs in POST bodies. |
| Access | Open to anyone. | Requires a client ID and secret (how to get one). HTTPS only; TLS terminates at Cloudflare. |
Details and how to verify this yourself: Security & privacy.
User guide
The tool sits in a window that works like a desktop app: menus on the top row and the full-screen icon at its right (Esc leaves full screen). The set-up options described below are in Settings → Options…, an overlay, and the Settings menu also lists the common choices directly. To keep the options in view instead, choose View → Inline config; the page remembers that choice. Help → Keyboard shortcuts… lists the keys.
- Type a cron expression, for example
*/15 9-17 * * 1-5. - Choose the time zone your cron daemon or scheduler runs in. It defaults to your browser’s zone. Servers often run in UTC. Kubernetes CronJobs use the controller’s zone unless
spec.timeZoneis set. - Read:
- the description in plain English;
- the day rule: which of the two day fields decides, and whether they combine with OR or AND;
- the fields table, with every value each field expands to;
- the next runs, with the UTC equivalent of each. Runs moved by a DST change are marked.
The rule that surprises everyone. When both day-of-month and day-of-week are restricted, cron runs on days matching either of them. 0 0 13 * 5 runs at midnight on every 13th and on every Friday, not only on Friday the 13th. To run on a weekday within a range of days, schedule on the weekday and check the date in the job, e.g. [ "$(date +\%d)" -le 07 ] for “first Monday”.
Syntax at a glance.
| Syntax | Meaning | Example |
|---|---|---|
* | every value | * * * * * every minute |
a,b | list | 0 9,17 * * * at 09:00 and 17:00 |
a-b | range (inclusive) | 0 9-17 * * * every hour 09:00 to 17:00 |
*/n, a-b/n | step | */10 * * * * every 10 minutes |
| names | JAN–DEC, SUN–SAT, any case | 0 0 * * MON-FRI |
Specification
Accepted forms.
| Form | Fields |
|---|---|
| Standard (Vixie cron, cronie, Kubernetes) | minute hour day-of-month month day-of-week |
| With seconds (cron-parser, node-cron, Spring style) | second minute hour day-of-month month day-of-week; a warning notes that standard crontab does not accept it |
| Macros (case-insensitive) | @yearly = @annually = 0 0 1 1 *; @monthly = 0 0 1 * *; @weekly = 0 0 * * 0; @daily = @midnight = 0 0 * * *; @hourly = 0 * * * * |
Fields are separated by any whitespace. Any other number of fields is rejected; a 7th (Quartz “year”) field is named in the error.
Field values.
- Ranges: second and minute 0–59, hour 0–23, day-of-month 1–31, month 1–12, day-of-week 0–7.
- Sunday is both 0 and 7; the
valueslist always reports Sunday as 0. - Steps: a step of 0, or a range written backwards (
5-1), is an error.
Extensions. These are accepted, and each use produces a portability warning, because Vixie cron and cronie reject them:
| Syntax | Field | Meaning |
|---|---|---|
L | day-of-month | last day of the month (L, or in a list: 1,L) |
nL | day-of-week | last weekday n of the month (5L = last Friday) |
n#k | day-of-week | k-th weekday n of the month, k = 1–5 (1#2 = second Monday); cannot be combined with a list |
? | day fields | same as * |
Rejected, with an explanation.
H(Jenkins hash),WandLW(nearest weekday);@reboot(it has no schedule), and the non-standard macros@weekdays,@weekends,@minutelyand@secondly;- any value outside the field’s range.
Every syntax and range error starts with the name of the offending field, e.g. minute field "61": ….
Day-of-month and day-of-week (Vixie cron rule).
- Unrestricted field: a day field is unrestricted when it begins with
*(this includes*/2) or is?. - Both restricted (
0 0 13 * 5): a day matches when either field matches.day_rule.ruleiseither. - One field
*or?: only the other field selects days (day-of-monthorday-of-week). If both are, every day matches (every-day). - A
*-prefixed field that still narrows (0 0 */2 * 1): Vixie cron counts it as unrestricted, so a day must match both fields (an odd day that is also a Monday).day_rule.ruleisboth. This matches Vixie cron’sDOM_STAR/DOW_STARflags and robfig/cron (Kubernetes). cron-parser alone would OR these fields; this tool filters its results to apply the Vixie rule.
Run times.
- Search: runs are listed strictly after
from(default: now), in ascending order, at whole-second resolution. count: 1–50 (default 5 on the API, 10 on the page).- Zone: run times are computed in
zonewith cron-parser, then shown as ISO 8601 with offset, UTC, Unix seconds, wall-clock time and weekday. - Never-matching days: a schedule whose day fields can never match (
0 0 30 2 *) is rejected by cron-parser with a 422 error. - Rare schedules: if the search ends before
countruns are found, the list is shorter andwarningssays why. cron-parser stops at its internal loop limit, and the AND filter examines at most 5,000 candidates.
Daylight saving time. Behaviour in a zone with DST, verified for America/New_York:
- Spring forward (gap). A run scheduled at a wall-clock time that does not exist is moved forward by the gap.
30 2 * * *runs at 03:30 EDT on the changeover day and is flaggeddst_shifted: true. Runs every 20 minutes during 02:00–02:59 run at 03:00, 03:20 and 03:40. - Fall back (overlap). A job at a fixed time in the repeated hour runs once, at the first occurrence:
30 1 * * *runs at 01:30 EDT, not again at 01:30 EST. A job whose hour field is*runs in both copies of the hour (30 * * * *runs at 01:30 EDT and 01:30 EST).
Real daemons differ in this. cronie runs skipped jobs immediately after the change; some systems skip them. Check your scheduler if it matters, or run the job in UTC.
Description. The English text comes from cronstrue (24-hour clock). For expressions where both day fields are set, its wording (“on day 13 of the month, and on Friday”) is less precise than day_rule.explanation, which is authoritative.
Limits. Expression up to 200 characters.
API & MCP
The same logic is available over HTTP and as MCP tools. Unlike this page, these run on the server: see where your data goes.