Spring/Quartz Cron vs Standard crontab — The Seconds Field Trap
If you've operated servers, you're probably comfortable with 5-field crontab expressions like 0 9 * * MON-FRI. But paste @Scheduled(cron="0 9 * * MON-FRI") straight into a Spring Boot project and the app throws an IllegalArgumentException the moment it starts. The expression itself looks perfectly fine, so why does it fail? The answer is the field count — Spring and Quartz add an extra seconds field at the front that plain crontab doesn't have.
1. The field count differs first: 5 vs 6
Standard Linux crontab uses 5 fields — minute hour day month weekday — with "minute" as the smallest unit. Spring's cron parser, on the other hand, expects exactly 6 fields: second minute hour day month weekday. So to express "every day at 9:00 AM sharp, weekdays only" in Spring, you must add a seconds field of 0 at the front: 0 0 9 * * MON-FRI. With only 5 fields, the parser throws an exception immediately. But if you accidentally shift the fields by one — say, putting a minute value where seconds should go — the app starts up fine and silently runs at a completely different time than intended.
| Type | Field order | Field count | Special chars |
|---|---|---|---|
| Standard crontab | minute hour day month weekday | 5 | * , - / |
| Spring @Scheduled | second minute hour day month weekday | 6 | * , - / |
| Quartz Scheduler | second minute hour day month weekday [year] | 6–7 | * , - / L W # |
2. Quartz-only rule: day-of-month and day-of-week can't both be set
Quartz has one more syntax rule beyond the field count. Between the day-of-month and day-of-week fields, exactly one must be a question mark (?) to mean "not specified." In crontab or Spring cron, putting * in both fields is perfectly fine, but Quartz treats that combination as ambiguous and rejects it at parse time. For "the 15th of every month," you use a question mark in the weekday slot: 0 0 9 15 * ?. For "every Monday," you use a question mark in the day slot: 0 0 9 ? * MON.
3. L, W, # — syntax that doesn't exist in crontab
When you want to specify the last day of the month, or the nearest weekday to a given date, Quartz and Spring cron support the L (Last) and W (Weekday) characters. 0 0 L * * means midnight on the last day of every month, and 0 0 15W * * means the nearest weekday to the 15th of every month. But these are extensions that don't exist in the POSIX standard crontab spec, so registering the same expression in a server's crontab gets it ignored or treated as a syntax error. If you need "the last day of the month" in plain crontab, you'll need to work around it with a shell script that computes the actual last date, e.g. via date -d, and register that script instead.
4. Summary
- The field count is different: crontab has 5, Spring/Quartz add seconds at the front for 6 (Quartz can go up to 7 with a year field).
- Copying a crontab expression as-is throws an exception: Spring throws IllegalArgumentException when a field is missing.
- Quartz forbids specifying day-of-month and day-of-week together: exactly one of them must be
?. - L/W/# syntax is Quartz/Spring-only: it doesn't exist in standard crontab, so server-side registration needs a workaround script.
Frequently Asked Questions
Q. What happens if I paste crontab's "0 9 * * MON-FRI" straight into Spring's @Scheduled?
A. You'll get an IllegalArgumentException. Spring's cron parser expects exactly 6 fields (second minute hour day month weekday), so a 5-field standard crontab string is one field short and fails to parse. You need to add a seconds field at the front: "0 0 9 * * MON-FRI" runs every weekday at exactly 9:00:00 AM.
Q. Can Quartz cron specify both day-of-month and day-of-week at the same time?
A. No. Exactly one of the two fields must be a question mark (?) meaning "not specified." "Run on the 15th of every month" uses ? in the weekday slot: "0 0 9 15 * ?". "Run every Monday" uses ? in the day slot: "0 0 9 ? * MON". Using * (or a concrete value) in both fields at once throws a parser exception.
Q. Can standard Linux crontab use L (last) or W (nearest weekday)?
A. No. Special characters like L, W, and #(nth weekday) are extensions defined by Quartz and Spring, and they don't exist in the POSIX crontab spec. Registering "0 0 L * *" with crond will be ignored or rejected as an error, so if you need "run on the last day of the month" in plain crontab, you have to work around it with a separate script that computes the actual last day.
Q. Is the seconds field in the same position for Spring and Quartz?
A. Yes, both put seconds as the first field. The order is second, minute, hour, day, month, weekday for both, and Quartz optionally allows one more field — year — at the very end, for up to 7 fields total.
Q. Can I use an expression like */5 * * * * in Spring as-is?
A. The expression itself is valid syntax, but the fields are interpreted differently. In crontab, */5 * * * * means "every 5 minutes." Paste that same string into Spring and, under the 6-field rule, the first field (seconds) is read as */5, so it means "every 5 seconds" instead. For a 5-minute repeat, you need 0 in the seconds field and */5 in the minute field.
Q. What happens to a Quartz job if the server is down when it's scheduled to run?
A. Quartz lets you configure a misfire policy, so when the server recovers you can choose to immediately fire the missed job once, or simply ignore it. Standard crontab has no concept of replaying missed runs at all — it just waits for the next scheduled time.
Q. When would I use Quartz's year field?
A. For one-off jobs meant to run only in a specific year. For example, "0 0 9 1 1 ? 2027" runs exactly once, at 9:00 AM on January 1, 2027. Omitting it means the job repeats every year.
Q. Can I use an expression built with this site's Cron generator directly in Spring?
A. MODOO HUB's Cron Expression Generator works on the standard 5-field crontab basis. To use it in a Spring project, you need to manually add a seconds field (usually 0) at the front of the generated expression.