Spring Cron Tool
Parse and validate Spring @Scheduled 6-field cron — seconds first, ? equals *, 0 or 7 = Sunday — with next runs in any timezone, entirely on this device.
The plain-English description appears here.
Token legend
- * — every value
- ? — same as * in Spring; day fields only, whole field only
- , — list; day fields may mix plain days with L / # entries
- - — inclusive range of values
- / — step: start/interval or range/interval
- L — last day of the month; L-3 = 3 days before month end; 5L or FRIL = last Friday
- W — nearest weekday to a day; LW = last weekday; never crosses the month
- # — nth weekday of the month: FRI#3 = third Friday; months without the nth are skipped
- Spring counts weekdays 0 or 7 = SUN, 1 = MON … 6 = SAT; Quartz counts 1 = SUN
| # | UTC | UTC time | DST |
|---|---|---|---|
| Next runs for a valid expression appear here. | |||
—History
Valid expressions you run are kept here — on this device only.
Press ? for shortcuts
Do it offline:$ npx cronstrue "0 0 9-17 * * MON-FRI"
How to use it
- Paste a six-field expression or a macro like @hourly — whatever sits inside cron = "…" belongs here, unquoted.
- Read the badge and the plain-English line; problems are named beside your input, which stays put.
- Pick a timezone above the run table; a DST mark means that run's UTC offset differs from a day earlier.
- Copy the expression, or the @Scheduled snippet carrying your chosen zone.
Spring's @Scheduled annotation takes a six-field cron line, seconds in front, and turns down anything shaped for another scheduler. Here ? is plain * under another name, Sunday answers to 0 and 7 alike, and no year field exists. Paste an expression to read it in plain English, project next runs per timezone, and copy a snippet back — nothing leaves this tab.
How it works
Validation mirrors Spring's CronExpression class: exactly six fields, per-field ranges, three-letter names, specials only where Spring allows them. Five fields or a trailing year route to the crontab and Quartz pages instead of half-parsing.
Descriptions come from a describer built for Spring's numbering — a weekday 5 always reads Friday — golden-pinned so the wording cannot drift between releases.
Plain schedules ride the cron-parser iterator with weekdays expanded to explicit values; L, W, # and lines with both day fields set walk the calendar month by month in your zone, intersecting day sets.
Each run's UTC offset is compared with 24 hours earlier; a difference flags spring-forward or fall-back — where wall-clock schedules shift or would repeat.
Examples
0 0 9-17 * * MON-FRIEvery hour from 09:00 through 17:00, on Monday through FridayThe leading 0 is the seconds column; without it Spring reads five-field crontab and declines. Nine runs a day here, the last at 17:00.
@hourlyEvery hour, on the hourSpring stores the six-field expansion 0 0 * * * * and the macro chip keeps your shorthand. No @reboot: that macro is crontab's.
0 0 0 * * THULAt 00:00, on the last Thursday of the monthTHUL is THU plus L: the last Thursday. Its numeric twin is 4L — java.time counts Thursday as 4 — where Quartz spells the same day 5L.
0 0 0 13 * 5At 00:00, on day 13, and only on FridayWith both day fields set, Spring runs only when the 13th is a Friday: three dates in 2026, then August 2027. Crontab would add every Friday and every 13th.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
0 and 7 both mean Sunday
Weekday numbering is java.time's: MON=1 through SAT=6, Sunday as 0 or 7. Quartz counts 1=SUN through 7=SAT — one digit, two days; names carry one meaning everywhere.
? adds nothing that * does not
Spring rewrites ? to * — no rule forces a day field to yield. Set both: Spring intersects, Quartz refuses, classic cron runs on either match.
No year field exists
A seventh field makes the line Quartz cron; the tool offers that page, input intact. Spring schedules recur every year; expiry belongs in code.
Bare L needs a weekday in front
Write 5L or FRIL for the last Friday. A lone L in day-of-week is refused; only Quartz reads a bare L, as Saturday.
FRI#6 and L-31 parse, then never run
Spring caps neither # ordinals nor L-n offsets: FRI#6 is legal text no month satisfies. The run table shows a never-matches notice; Quartz rejects #6 at parse time.
Macros expand with a seconds column
@daily becomes 0 0 0 * * *, six fields wide. All seven Spring macros expand here; @reboot is not among them — machine startup is a crontab concept.
@Scheduled defaults to the server's zone
Omit the zone attribute and cron triggers fire in the JVM's default timezone. The snippet here always writes zone=, so pasted code matches the table.
fixedRate and fixedDelay are not cron
The annotation also schedules plain millisecond intervals via fixedRate, fixedDelay and initialDelay. Those attributes never parse cron text; nothing here applies to them.
Common errors
This is a classic 5-field crontab expression, not Spring — Spring cron has 6 fields with seconds first.- Crontab starts at minutes; Spring starts at seconds. Prefix a 0 to keep your timing, or follow the hand-off to the classic parser.
This looks like a 7-field Quartz expression — the 7th field is Quartz's optional year; Spring cron has exactly 6 fields and no year field.- Quartz appended an optional year; Spring never adopted it. Trim the final field, or carry the line into the Quartz tool unchanged.
Field 6 (day of week): 8 is out of range 0–7.- Weekday numbers stop at 7, and 0 and 7 name the same Sunday. A day's three-letter name says the same thing in every dialect.
Bare L is not a Spring day-of-week — write 5L or FRIL for the last Friday of the month; only Quartz reads bare L as Saturday.- Last-of-month in day-of-week names its weekday first. Spring refuses to guess; Quartz silently supplies Saturday.
"FRI#0" — # takes an occurrence of 1 or more: write FRI#1 for the first Friday of the month.- Ordinals start at one — no month has a zeroth Friday. The top end is unchecked: FRI#6 parses and never matches.
Input is larger than the 1,024 character limit for this tool. For a quick description use the CLI: npx cronstrue "0 0 9-17 * * MON-FRI"- Oversized input is declined whole, never trimmed. The CLI describes long lines but does not enforce Spring's six-field or no-year rules — validation happens here.
FAQ
What happens when both day fields are set?
Spring intersects them: 0 0 0 13 * 5 runs only when the 13th is also a Friday — the run table above computes those dates. crontab(5) documents the opposite, either field sufficing; Quartz refuses the line outright.
Why does Spring cron need exactly six fields?
The grammar starts at seconds and stops before any year. Five fields is crontab, seven is Quartz — this page recognizes both shapes and offers the matching tool, input carried over.
Does @Scheduled honor timezones?
Yes, through the zone attribute; omitted, the JVM default applies. The zone picker rewrites the copied snippet to match, so annotation and table agree.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Recompute the description and the run table from the present moment.
- ⌘/Ctrl + S
- Save expression, reading and runs together as a .txt file.
- ⌘/Ctrl + C
- Copy the expression while nothing is selected.
- ⌘/Ctrl + Shift + C
- Copy the expression even over an active selection.
- t
- Step to the next theme; typing in the input is never intercepted.
- ? or ⌘/Ctrl + /
- Open the shortcut overlay listing exactly these bindings.
- Esc
- Close whichever dialog is open and hand focus back to its trigger.