Methodology · Cron Syntax
Cron expression syntax methodology
Reviewed by Byron Malone · Last reviewed .
Cron is the standard Unix job scheduler — a daemon that reads a crontab file and executes commands at times specified by five-field (or six-field, in Quartz) expressions. The syntax is deceptively compact: it looks like punctuation but encodes a precise scheduling algebra with field ranges, step values, lists, and platform-specific special characters. This page explains the validation rules, algorithm, and platform dialect differences behind the Dev Utilities Pro Cron Expression Builder and Validator.
POSIX field specification (IEEE Std 1003.1)
The canonical cron specification is defined in IEEE Std 1003.1 (POSIX.1-2017), section “crontab — schedule periodic background work.” A POSIX crontab entry has exactly five whitespace-separated fields followed by the command:
Field 1 — minute Range: 0–59 Field 2 — hour Range: 0–23 Field 3 — day-of-month Range: 1–31 Field 4 — month Range: 1–12 (or: jan feb mar apr may jun jul aug sep oct nov dec) Field 5 — day-of-week Range: 0–7 (0 and 7 are both Sunday per POSIX §7.3.5) Each field accepts: * — any value (wildcard) N — exact value N N-M — range from N to M, inclusive */N — step: every N units across the full range N-M/N — step: every N units within range N–M N,M,P — list: exactly these values
The POSIX specification is explicit that both 0 and 7 mean Sunday in the day-of-week field. This is a deliberate inclusion to accommodate both zero-indexed (0 = Sunday) and ISO 8601 weekday numbering (7 = Sunday, 1 = Monday) conventions. Named abbreviations (SUN, MON, TUE, WED, THU, FRI, SAT) are also valid in POSIX-compliant implementations and are the safest form for readability.
Month names (JAN–DEC) are accepted in most implementations as aliases for 1–12. They are case-insensitive in Vixie cron (the reference implementation, Paul Vixie, 1988) and in systemd timers.
Next-execution time algorithm
Computing the next time a cron expression fires, given a reference time T, requires forward iteration: start at T + 1 minute and advance field by field until all five (or six) constraints are simultaneously satisfied. The algorithm is:
function nextExecution(expr, referenceTime):
t = referenceTime + 1 minute // start one minute ahead
loop until solution found or 4-year limit exceeded:
if minute(t) not in expr.minutes:
advance t to next matching minute
// advancing minute may roll over to next hour — recheck all fields
if hour(t) not in expr.hours:
advance t to start of next matching hour
continue // restart from minute field
if month(t) not in expr.months:
advance t to first day of next matching month at 00:00
continue
if dayOfMonth(t) not in expr.daysOfMonth AND dayOfWeek(t) not in expr.daysOfWeek:
// POSIX: both dom and dow must independently not match
// Exception: if BOTH fields are unrestricted (*), skip this check
advance t to next day at 00:00
continue
return t // all constraints satisfiedThe day-of-month / day-of-week interaction is the most subtle part of the algorithm. POSIX specifies that if both day-of-month and day-of-week are restricted (not *), the cron daemon fires when either constraint is satisfied — not both. This is the Vixie cron behavior and is codified in Linux cron(8). AWS EventBridge explicitly prohibits this: it requires one of the two to be ? (unspecified), making the semantics unambiguous.
The 4-year limit in the algorithm guards against expressions that never fire (e.g., 0 0 30 2 *— February 30 does not exist). The calculator surfaces a “no future execution found within 4 years” error for such expressions.
Platform dialect comparison
The Dev Utilities Pro validator recognizes five platform dialects. Key differences are summarized below:
| Feature | POSIX/Linux | Quartz | AWS EventBridge | GitHub Actions |
|---|---|---|---|---|
| Field count | 5 | 6 (seconds first) | 6 (year last) | 5 (POSIX) |
| Seconds field | No | Yes (field 1) | No | No |
| Year field | No | No | Yes (field 6) | No |
| ? (unspecified) | No | dom or dow | Required in dom or dow | No |
| L (last) | No | Yes | Yes (limited) | No |
| W (nearest weekday) | No | Yes | No | No |
| # (nth weekday) | No | Yes | No | No |
| Timezone | System/CRON_TZ | Application TZ | UTC (Rules); TZ param (Scheduler) | UTC only |
| dow=0 meaning | Sunday | Saturday (Quartz 1-indexed) | Sunday (1-indexed, 1=SUN) | Sunday (POSIX) |
The day-of-week numbering is a frequent cross-platform migration bug. Quartz uses 1 = Sunday through 7 = Saturday. AWS EventBridge also uses 1 = Sunday through 7 = Saturday. POSIX uses 0 = Sunday through 6 = Saturday (with 7 also meaning Sunday). GitHub Actions follows POSIX. The calculator flags any day-of-week value that would produce a different result across dialects.
Quartz special character semantics
Quartz (used in Java/Spring applications via org.quartz.CronTrigger) extends POSIX cron with four special characters that require calendar-aware computation:
- ? (no specific value). Used in dom or dow when you want to leave one field unconstrained. Required precisely because Quartz does NOT implement the POSIX “fire when either matches” semantics — it requires one field to be explicitly unset.
0 0 15 * ?= 15th of every month, any day of week. - L (last). In dom: L = last day of the month (28, 29, 30, or 31 as appropriate). In dow: 6L = last Friday of the month; 2L = last Monday. L-3 in dom = three days before month end. Computing L requires knowing the month length, which requires knowing whether the year is a leap year for February.
- W (nearest weekday). 15W = the nearest weekday to the 15th. If the 15th is a Saturday, fire on Friday the 14th. If Sunday, fire on Monday the 16th. If the 15th is already a weekday, fire on the 15th. LW = last weekday of the month.
- # (nth weekday). 6#3 = the third Friday of the month (6 = Friday in Quartz 1-indexed convention; #3 = third occurrence). If the month has fewer than three Fridays, the trigger does not fire that month.
None of these characters are available in POSIX cron, GitHub Actions schedule, or standard Kubernetes CronJob expressions. AWS EventBridge supports L in dom for “last day of month” but does not support W or #.
Assumptions
- Next-execution time computation uses the IANA timezone name provided by the user; if no timezone is provided, UTC is assumed.
- The Vixie cron dom/dow “either satisfies” rule is applied for POSIX/Linux dialect. AWS EventBridge's mutual-exclusion requirement is enforced separately.
- Named month (JAN–DEC) and day-of-week abbreviations (SUN–SAT) are normalized to numeric values before validation.
- Step values must be positive integers;
*/0is rejected as a division-by-zero condition.
Limitations
The following expressions cannot be computed as “next execution time” and are flagged with explanatory notes:
@reboot— depends on daemon start time, not a calendar schedule. The calculator recognizes and translates it (“once when cron daemon starts”) but cannot compute a future execution time.- Expressions where the day-of-month does not exist in some months (e.g.,
0 0 29-31 * *) — the calculator shows next occurrences and notes which months will be skipped. - Quartz L, W, and # characters — next-execution computation requires full month-calendar lookup (Zeller's congruence or equivalent). The calculator computes these correctly but notes the calendar dependency.
- DST transitions — if a cron expression is set to fire at a time that does not exist (spring-forward gap) or fires twice (fall-back overlap), behavior depends on the cron daemon implementation. The calculator flags expressions in the 02:00–03:00 window in timezones with DST transitions.
Primary sources
- IEEE Std 1003.1 (POSIX.1-2017) — crontab utility specification
- Linux cron(8) man page — Vixie cron (Paul Vixie, 1988), maintained by ISC
- Quartz Scheduler 2.3.0 Documentation — Cron Trigger Tutorial
- AWS EventBridge — Schedule Expressions Using Cron (AWS Documentation)
- GitHub Actions — Events that trigger workflows: schedule (GitHub Docs)
- Kubernetes CronJob — POSIX cron syntax reference (Kubernetes Documentation)
Last reviewed by Byron Malone, 2026-05-23. This methodology document explains the validation and computation approach used by the Dev Utilities Pro Cron Expression Builder. Always verify cron behavior in your target environment — cron daemon implementations differ in edge cases.
Back to methodology overview.