cronuru
Dialect

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.

References

Frequently asked questions

What is the format of a Spring cron expression?
Spring @Scheduled uses six space-separated fields: second, minute, hour, day-of-month, month, day-of-week. That's one more than a standard Unix crontab (the leading seconds field). For example, `0 0 9 * * MON-FRI` runs at 9:00:00 AM on weekdays. Fields accept `*`, ranges (`9-17`), lists (`1,3,5`), steps (`*/5`), the `L`/`W`/`#` special characters, and macros like `@hourly`.
How is Spring @Scheduled cron different from Quartz?
Both have 6 fields with seconds at the front and both support `L`, `W`, and `#`. The differences are: (1) Spring numbers Sunday `0` (or `7`), Quartz uses `1`; (2) Spring does NOT require `?` — both day-of-month and day-of-week can be `*` at once, whereas Quartz makes you use `?` in one of them; (3) Spring has no year field, Quartz has an optional 7th; (4) Spring 5.3+ supports macros like `@hourly` and `@daily`, Quartz does not. The old claim that Spring's `L` only works in day-of-month is outdated — that was the pre-5.3 parser.
How do I write a Spring cron expression for every 5 seconds?
Use `@Scheduled(cron = "*/5 * * * * *")` — the leading `*/5` is the seconds field. For a plain fixed interval, `@Scheduled(fixedRate = 5000)` (milliseconds) is simpler than cron. See the full breakdown on the [every 5 seconds](/every-5-seconds) page.
How do I run a Spring job on the last day of the month?
Use `L` in the day-of-month field: `@Scheduled(cron = "0 0 0 L * *")` fires at midnight on the last calendar day of every month. For the last *weekday*, use `LW` (`0 0 9 LW * *`); for the last Friday, put `L` on the day-of-week value: `0 0 0 * * 5L`.
How do I set the timezone for a Spring @Scheduled job?
Use the `zone` parameter on the annotation: `@Scheduled(cron = "0 0 9 * * MON-FRI", zone = "America/Los_Angeles")`. Without `zone`, the JVM's default timezone is used — which depends on the runtime environment and is often UTC on cloud platforms. Always set `zone` explicitly for predictability.
Can I use Spring @Scheduled with sub-second precision?
Not via cron syntax — Spring cron is capped at 1-second precision. For sub-second scheduling, use `fixedRate` (in milliseconds) instead: `@Scheduled(fixedRate = 100)` runs every 100 ms. Note that `fixedRate` doesn't wait for the previous run to complete; use `fixedDelay` if you want to wait.
What's the difference between @Scheduled cron and @Scheduled fixedRate?
Cron is calendar-based — "every Monday at 9 AM," "every 15 minutes on the quarter-hour." fixedRate is interval-based — "every N milliseconds from the start of the previous run." fixedDelay is also interval-based but measures from the END of the previous run. Use cron when alignment to clock time matters; use fixed-rate/delay for pure interval polling.