Spring @Scheduled Cron
Spring Framework's `@Scheduled` annotation uses a 6-field cron expression with seconds at the front. Sunday can be `0` or `7`, day and month names work (`MON-FRI`, `JAN-DEC`), and — since the CronExpression parser landed in Spring 5.3 — it supports the full set of special characters: `L` (last), `W` (nearest weekday), and `#` (nth weekday). Set the timezone with the `zone` parameter. Verified against Spring Framework 7.0.
Quick reference
- Fields
- second minute hour day-of-month month day-of-week
- Second range
- 0–59
- Minute range
- 0–59
- Hour range
- 0–23
- Day-of-month range
- 1–31, plus L, L-n, W, LW
- Month range
- 1–12 or JAN–DEC
- Day-of-week range
- 0–7 (Sun=0 or 7, Sat=6) or MON–SUN, plus L (5L) and # (5#2)
- Year
- Not supported (Quartz has it; Spring does not)
- Special chars
- * ? , - / L W # — plus @hourly @daily @midnight @weekly @monthly @yearly macros
- Default timezone
- JVM default — set explicitly with `@Scheduled(zone = "America/Los_Angeles")`
- Minimum interval
- 1 second
Examples
| Expression | Description |
|---|---|
* * * * * * | Every second |
*/5 * * * * * | Every 5 seconds |
*/30 * * * * * | Every 30 seconds |
0 * * * * * | Every minute (at :00 seconds) |
0 */5 * * * * | Every 5 minutes |
0 */15 * * * * | Every 15 minutes |
0 0 * * * * | Every hour, on the hour |
0 30 * * * * | Every hour at :30 |
0 0 9 * * * | Every day at 9:00 AM |
0 0 0 * * * | Every day at midnight |
0 0 9-17 * * * | Every hour from 9 AM to 5 PM |
0 0 9 * * MON-FRI | Weekdays at 9 AM |
0 0 8-18 * * MON-FRI | Hourly during business hours, weekdays only |
0 0 0 * * MON | Every Monday at midnight |
0 0 0 * * SAT,SUN | Weekends at midnight |
0 0 0 1 * * | Midnight on the 1st of every month |
0 0 0 1,15 * * | 1st and 15th of every month |
0 0 0 L * * | Last day of every month (L) |
0 0 0 L-2 * * | 2 days before the end of the month (L-2) |
0 0 9 1W * * | 9 AM on the nearest weekday to the 1st (1W) |
0 0 9 LW * * | 9 AM on the last weekday of the month (LW) |
0 0 0 * * 5L | Midnight on the last Friday of the month (5L) |
0 0 9 * * MON#1 | 9 AM on the first Monday of the month (MON#1) |
0 0 0 1 1 * | Midnight on Jan 1st (yearly) |
@hourly | Macro — equivalent to `0 0 * * * *` |
@daily | Macro — equivalent to `0 0 0 * * *` (also `@midnight`) |
@weekly | Macro — equivalent to `0 0 0 * * 0` (Sunday midnight) |
@monthly | Macro — equivalent to `0 0 0 1 * *` |
Gotchas
- **Spring is NOT Quartz.** They look similar (both 6-field with seconds) but Spring's `@Scheduled` cron is a separate parser. The real differences: Spring numbers Sunday `0` (or `7`) while Quartz uses `1`; Spring does not require `?` (both DoM and DoW can be `*`); and Spring has no year field, while Quartz has an optional 7th. Both support the full `L` / `W` / `#` special characters.
- **`L`, `W`, and `#` are all supported** (since the CronExpression parser in Spring 5.3). `L` = last day-of-month or, in the DoW field, last-of-that-weekday (`5L` = last Friday); `L-n` = n days before month end; `W` = nearest weekday (`1W`, `LW`); `#` = nth weekday of the month (`MON#1` = first Monday). Older docs and Stack Overflow answers claiming Spring only supports `L` in day-of-month describe the pre-5.3 parser and are out of date.
- Spring 5.3+ supports macros: `@hourly`, `@daily`, `@midnight`, `@weekly`, `@monthly`, `@yearly`, `@annually`. Earlier Spring versions don't.
- Default timezone is the JVM's default, which is often a surprise on cloud containers. Always set `zone = "UTC"` (or your preferred zone) explicitly on the annotation.
- Sunday accepts both `0` and `7`. The Spring docs use `7` in some examples and `0` in others — either works.
- Spring also supports `fixedRate` and `fixedDelay` for simple interval scheduling without cron syntax. Use those for "every N seconds/minutes" when you don't need calendar-based scheduling.
Used by
- Spring Framework `@Scheduled` annotation (Spring Boot, Spring Web, Spring Cloud)
- Spring Batch scheduled jobs
- Spring Integration scheduled triggers
- Spring Cloud Stream binders with cron triggers
Spring @Scheduled borrowed Quartz’s 6-field-with-seconds shape but kept its own simpler semantics — no mandatory ?, no Sunday-numbering surprise (it matches Unix at 0), and a small set of special chars. Most Spring teams use it as a more powerful Unix cron rather than as a Quartz substitute.
The seconds field is the practical reason to reach for Spring cron over a plain crontab — it unlocks sub-minute schedules that Unix cron simply can’t express: every 5 seconds (*/5 * * * * *), every 10 seconds, and every 30 seconds. For a fixed interval that tight, though, @Scheduled(fixedRate = ...) is usually cleaner than a cron string — see the Spring @Scheduled guide.