Spring @Scheduled cron expressions
Six fields starting with seconds, read by CronExpression behind @Scheduled. It looks like Quartz, but it numbers the days like Unix cron and requires both day fields to match.
At 09:00, Monday through Friday.
Next 10 runs
Clock changes
In your config
In the other dialects
“Same schedule” means the same clock times. Schedulers still treat a clock change differently, as the table on the home page shows.
Keyboard: / edit the expression, 1 to 7 change dialect, t time zone, n next clock change, c copy the link, Esc leave a field.
Fields
| Field | Values | Special characters |
|---|---|---|
| Second | 0–59 | * , - / |
| Minute | 0–59 | * , - / |
| Hour | 0–23 | * , - / |
| Day of month | 1–31 | * ? , - / L W |
| Month | 1–12 or JAN–DEC | * , - / |
| Day of week | 0–7, where 0 and 7 are Sunday, or MON–SUN | * ? , - / L # |
Special characters
*- First to last. In day of week that is Monday to Sunday, so
*/2means Monday, Wednesday, Friday and Sunday. ?- The same as
*, allowed only in the two day fields. Anywhere else Spring rejects it. /- A step over a range or star, or from a single start:
0/30in minutes is :00 and :30,5/15in seconds is 5, 20, 35, 50. -- An inclusive range. A backwards range such as
FRI-MONor22-2is rejected. A range starting at 7 starts at Sunday 0, so7-2is Sunday to Tuesday. L- In day of month, the last day;
L-3is three days before it. In day of week it needs a day in front:5LorFRILis the last Friday. W- The weekday nearest a day of month:
15W.1Won a Saturday the 1st means Monday the 3rd.LWis the last weekday of the month. #- The nth weekday of the month:
5#2orFRI#2is the second Friday. @daily- Macros with six-field meanings:
@yearly,@annually,@monthly,@weekly,@daily,@midnightand@hourly.
The two day fields
Every field must match, including both day fields. 0 0 0 1 * MON runs at midnight on the 1st only when the 1st is a Monday, which is the opposite of Unix cron’s either-or. ? and * in a day field mean the same thing, so unlike Quartz neither field has to be ?.
Time zones
The scheduler’s clock, which is the JVM’s default zone unless you configure one. Set a zone per task with @Scheduled(cron = "…", zone = "Europe/London"), or new CronTrigger(expression, ZoneId.of("Europe/London")).
Clock changes
Spring walks a ZonedDateTime forward field by field, so clock changes follow java.time’s rules rather than any written promise. Measured against the real library: a daily 02:30 is skipped on the day the clocks go forward, and a daily 01:30 runs twice when they go back, once in each pass. Schedules inside the repeated hour run through both passes. On Lord Howe Island’s half-hour change, hourly schedules make next() return the same time again; the tester stops there and says so. This tool ports CronExpression from Spring Framework 7.0.10, which gives the same results as 6.2.19 on every compared case.
Gotchas
- Five-field Unix expressions are rejected with “Cron expression must consist of 6 fields (found 5 in …)”. Put
0in front for second 0. - Days count from Monday 1 to Sunday 7, with 0 also Sunday. Quartz counts Sunday as 1, so
6Lis the last Friday in Quartz and the last Saturday in Spring. Names such asFRILavoid the trap. - Spring’s reference docs say a bare
Lin day of week means the last day of the week.CronExpressionin Spring 6.2 and 7.0 rejects it with “No day-of-week before 'L'”. - When
nWfalls on a Sunday that is also the month’s last day, Spring moves to the Monday after, which is in the next month, and then skips that month.0 0 0 31W * *has no run in May 2026. Quartz runs on the Friday before. - From
L-28onwards the offset lands before the 1st in February, andCronExpression.next()then keeps returning the same time instead of moving on. - Month and day names are case-insensitive, but
LandWin day of month are not:lis rejected. @Scheduled(cron = "-")turns the task off, which is meant for a${…}placeholder set per environment.
Examples to try
- 0 0 * * * *The top of every hourEvery hour, on the hour
- */10 * * * * *Every ten secondsEvery 10 seconds
- 0 0 8-10 * * *08:00, 09:00 and 10:00 every dayAt 08:00, 09:00 and 10:00
- 0 0/30 8-10 * * *Every half hour from 08:00 to 10:30At 08:00, 08:30, 09:00, 09:30, 10:00 and 10:30
- 0 0 9-17 * * MON-FRIOn the hour, nine to five, on weekdaysOn the hour from 09:00 through 17:00, Monday through Friday
- 0 0 0 25 DEC ?Midnight on Christmas DayAt 00:00, on the 25th of the month, in December
- 0 0 0 L * *Midnight on the last day of the monthAt 00:00, on the last day of the month
- 0 0 0 L-3 * *Midnight on the third-to-last dayAt 00:00, 3 days before the last day of the month
- 0 0 0 * * 5LMidnight on the last Friday of the monthAt 00:00, on the last Friday of the month
- 0 0 0 1W * *Midnight on the first weekday of the monthAt 00:00, on the weekday nearest the 1st of the month
- 0 0 0 ? * MON#1Midnight on the first Monday of the monthAt 00:00, on the first Monday of the month
- 0 0 0 1 * MONThe 1st, but only when it is a MondayAt 00:00, on the 1st of the month, but only when that day is also Monday
Common schedules
- 0 */5 * * * *Every 5 minutes
- 0 */15 * * * *Every 15 minutes
- 0 0 * * * *Every hourEvery hour, on the hour
- 0 0 0 * * *Every day at midnightAt 00:00
- 0 0 9 * * MON-FRIEvery weekday at 9amAt 09:00, Monday through Friday
- 0 0 0 1 * *First day of the monthAt 00:00, on the 1st of the month
- 0 0 0 L * *Last day of the monthAt 00:00, on the last day of the month
- 0 0 9 * * FRILLast Friday of the monthAt 09:00, on the last Friday of the month
Error messages
- Cron expression must consist of 6 fields (found 5 in "*/5 * * * *")Spring: Five or seven fields
- Minimum value must be less than maximum value '22-2' in cron expression "0 0 22-2 * * *"Spring: A range that runs backwards
- Invalid value for HourOfDay (valid values 0 - 23): 24 '24' in cron expression "0 0 24 * * *"Spring: A value outside the field
- For input string: "?" '?' in cron expression "0 ? * * * *"Spring: Something that is not a number
- No day-of-week before 'L' in 'L' in cron expression "0 0 0 * * L"Spring:
Lalone in day of week