🔧 Operation
🕒 Cron expression
Five fields: minute hour dayOfMonth month dayOfWeek.
Optional six-field form adds a leading seconds column.
Shortcuts @yearly, @monthly,
@weekly, @daily, @midnight,
and @hourly are accepted; @reboot is rejected.
📅 Window
The first run is strictly after the From timestamp (not inclusive). Each subsequent run uses the previous result as its starting point. All output is in UTC.
📤 Result
📝 Description
- Normalized
{{ describeResult.normalized }}- Form
- {{ describeResult.isStandardForm ? '5-field (standard)' : '6-field (with seconds)' }}
- Seconds
{{ describeResult.fields.seconds.raw }}- Minutes
{{ describeResult.fields.minutes.raw }}- Hours
{{ describeResult.fields.hours.raw }}- Day of month
{{ describeResult.fields.dayOfMonth.raw }}- Month
{{ describeResult.fields.month.raw }}- Day of week
{{ describeResult.fields.dayOfWeek.raw }}
⏭️ Next firing times (UTC)
{{ runsResult.fromIso }}, {{ runsResult.runs.length }} runs.
- {{ run }}
ℹ️ About Cron Expression Parser
A cron expression is the schedule part of a crontab line: five space-separated fields
(minute hour dayOfMonth month dayOfWeek) that together select the instants at which the cron
daemon runs a command, as specified by
crontab(5) and the
POSIX crontab
specification. Quartz and Spring put a seconds field in front of those five, giving a six-field
form, and node-cron accepts the same seconds column optionally.
The Cron Expression Parser takes a 5- or 6-field expression and does two things. Describe turns it
into an English sentence (for example 0 9 * * MON becomes "Every Monday at 9:00 AM") and lists the raw
token of every field. Next Runs computes the next N firing times in UTC, strictly after a
start instant you choose. Both operations run in the same pure logic module that powers the public API, so the
page and the API always agree.
Supported inputs
[second] minute hour dayOfMonth month dayOfWeek 0-59 0-59 0-23 1-31 1-12 0-7 (0 and 7 = Sunday)
- Operation: Describe or Next Runs, chosen with the Operation buttons; the API field
operationtakesdescribeornextRuns. - Expression: exactly five fields, or six with a leading seconds column. Fields are separated by one or more spaces or tabs and surrounding whitespace is trimmed. Only the schedule is parsed, never a command.
- Field syntax:
*(every value), a single value, an inclusive rangeA-B, a step*/N(from the field minimum), a stepped rangeA-B/N, an open stepA/N(from A to the field maximum), and comma lists that mix any of these, such as1-5,10,15-30/3. - Named aliases:
JANtoDECfor months andSUNtoSATfor weekdays, case-insensitive, usable in ranges and lists and mixable with numbers (MON,WED,5). Weekday7is folded to Sunday (0). - Shortcuts (case-insensitive):
@yearlyand@annually=0 0 1 1 *,@monthly=0 0 1 * *,@weekly=0 0 * * 0,@dailyand@midnight=0 0 * * *,@hourly=0 * * * *.@rebootis rejected because its meaning depends on the cron implementation and has no deterministic schedule; any other@string is rejected too. - From (Next Runs only, API field
fromIso): an ISO 8601 timestamp such as2026-01-01T00:00:00Z. Empty means the current time. Give it a trailingZor an explicit offset; an offset is converted to UTC. - Count (Next Runs only, API field
count): 1 to 50 runs, default 5.
Output
Describe shows the English description in the Result panel, followed by the normalized expression,
the form (5-field standard or 6-field with seconds) and the raw token of every field. The API returns
data.description, data.normalized, data.isStandardForm (true for
five fields) and data.fields, where each of minutes, hours,
dayOfMonth, month, dayOfWeek and, for six-field input, seconds
carries the raw token and its expanded values as a sorted integer array.
Next Runs lists one UTC timestamp per line in YYYY-MM-DDTHH:MM:SSZ form, ascending,
the first strictly after From and each following one strictly after the previous. The API returns
data.runs with the same strings plus data.fromIso (the resolved start instant as a
Z timestamp) and data.count. Every successful API response is wrapped as
{"operation": ..., "data": ...}. Invalid input returns HTTP 400 with an error message that
names the field, the offending token and the reason (for example minute 60 being out of range 0-59).
Example
Describe 0 9 * * MON returns Every Monday at 9:00 AM with normalized
0 9 * * MON and isStandardForm true. Next Runs for the same expression from
2026-01-01T00:00:00Z with count 3 returns 2026-01-05T09:00:00Z,
2026-01-12T09:00:00Z and 2026-01-19T09:00:00Z. More results from this implementation:
*/15 * * * *: "Every 15 minutes".@daily: "Every day at midnight" (normalized to0 0 * * *).0 9 1 * *: "On day 1 of every month at 9:00 AM".0 30 9 * * MON-FRI(six fields): "Every weekday (Monday to Friday) at 9:30 AM", withisStandardFormfalse.0 0 29 2 *from2026-01-01T00:00:00Z: next runs2028-02-29T00:00:00Zand2032-02-29T00:00:00Z.0 0 1 * MON: fires on every 1st of the month and on every Monday (the OR rule below); the description ends with "(day-of-month OR day-of-week)".
Limitations
- Day-of-month and day-of-week follow the OR rule. When both fields are restricted (neither is
*), the schedule fires on every date that matches either field, as in Vixie cron, BSD cron and crontab.guru. When one of them is*, only the other constrains the day. - Only POSIX and Vixie field syntax is accepted, plus the optional leading seconds column and the open step
A/N. Quartz-only tokens (?,L,W,#) are rejected, as is any expression with fewer than five or more than six fields. A trailing year field turns a five-field line into a six-field one, so0 9 * * 1 2026fails with day-of-week2026out of range 0-7. - Paste only the schedule. A full crontab line such as
0 9 * * MON /usr/bin/backup.shhas six tokens and is read as a six-field expression, which then fails on the month field. - Next Runs is computed purely in UTC. No timezone, DST or
CRON_TZhandling is applied. A date-time From value without aZor offset, such as2026-01-01T09:00:00, is read in the clock of whichever host runs the calculation (your browser on this page, the server via the API), while a bare date such as2026-01-01is read as UTC midnight. - The search gives up after a fixed step budget, about 2.1 million steps for a five-field expression, and reports "Cron expression never fires within search window", which is what an impossible date such as
0 0 31 2 *returns. Whole days and months that cannot match are skipped, so sparse but valid schedules are still found much further out:0 0 29 2 *resolves even across the non-leap year 2100. - The English description is a best-effort summary. Common patterns get an idiomatic sentence; anything else gets a mechanical field-by-field phrase, and a stepped range or open step (
9-17/2,5/15) is summarised as "every N" without its bounds. The expandedvaluesarray returned by the API indata.fieldsis the authoritative reading.
Browser or server processing
The interactive page runs the compiled cron-parser logic module in your browser; the expression, start
instant and count never leave your device. The public API runs the same module on the server through the Node
bridge, so only API calls send an expression to the server, and both paths return identical results for identical
input.
FAQ
Why does my cron job never run?
Check the schedule with Next Runs first. If the parser rejects it, the error names the bad field and value. If the
preview shows no plausible dates, the expression may describe an impossible date such as 0 0 31 2 *
(reported as never firing) or combine day-of-month and day-of-week expecting AND where cron applies OR. If the
preview looks right, the cause lies outside the expression: the daemon's timezone, the job's environment and
PATH, or a command that fails silently. This tool validates and expands the schedule only.
Is the schedule in UTC or local time?
Everything this tool shows is UTC. A real cron daemon fires in the system's local timezone (or CRON_TZ
where supported), so an entry meant for 09:00 local time on a UTC+2 server is previewed here as 09:00 UTC, two
hours away from the wall-clock time. Convert after copying, and always pass From with a trailing Z or
an explicit offset.
Does it support @daily and the other macros?
Yes. @yearly, @annually, @monthly, @weekly, @daily,
@midnight and @hourly expand to their five-field equivalents (@daily becomes
0 0 * * *, "Every day at midnight"). @reboot is rejected because it is an event, not a
schedule, and cannot produce next-run times.
Are six-field expressions with seconds supported?
Yes. When six fields are present the first is seconds (0-59), isStandardForm is false, and
Next Runs advances at one-second resolution. Only the seconds column is added; Quartz-only tokens such as
? are still rejected.
References
- crontab(5) Linux manual page: authoritative grammar for the five-field form, named aliases and shortcut strings.
- POSIX crontab specification: Single UNIX Specification for portable cron syntax.
- crontab.guru: cross-check for human-readable descriptions and the day-of-month OR day-of-week rule.
- systemd.time(7): a calendar-event syntax that overlaps cron but is not handled by this tool.
- Build a new schedule from a form with the Cron Job Generator; for periodic time-window arithmetic see the Time Duration Calculator.
API Usage Example:
POST /api/tools/time/cron-parser
Content-Type: application/json
{
"operation": "describe",
"expression": "0 9 * * MON"
}