Cron vs Quartz Scheduler in Java — Syntax Differences Explained
If you're coming from Unix crontab and picking up Quartz Scheduler for a Java or Spring Boot application, the cron expressions look familiar but are not compatible — copy-pasting a crontab line straight into a @Scheduled(cron = "...") annotation is one of the most common Quartz mistakes. Here's exactly what's different and how to convert between them.
Field-by-field comparison
The biggest structural difference is that Quartz adds a leading seconds field and an optional trailing year field:
Unix cron (5 fields): minute hour day-of-month month day-of-week 0 9 * * 1-5 Quartz cron (6 or 7 fields): seconds minute hour day-of-month month day-of-week [year] 0 0 9 ? * MON-FRI [2026]
Key differences that break naive copy-paste
- Seconds field is mandatory in Quartz. There is no 5-field mode — you must always supply 6 or 7 fields, seconds first.
- Day-of-month and day-of-week can't both be
*-like at once. Quartz requires exactly one of them to be?(meaning "no specific value") because specifying real constraints on both is treated as ambiguous. Unix cron allows* *in both fields simultaneously with no complaint. - Day-of-week values differ. Quartz uses 1–7 where 1 = Sunday (or the names SUN, MON, TUE...), not 0–6 with 0 = Sunday like Unix cron.
- Quartz supports an optional year field and richer expressions like
L(last),W(nearest weekday), and#(nth weekday of month) — for example6#3means "the third Friday." - Quartz has no step shortcut identical to cron's
*/5everywhere — it does support it in most fields, but combined with the mandatory?rule it's easy to write an expression Quartz rejects at startup rather than silently misinterprets.
Side-by-side example expressions
Goal Unix cron Quartz cron Every minute * * * * * 0 * * * * ? * Every 5 minutes */5 * * * * 0 */5 * * * ? Every hour, on the hour 0 * * * * 0 0 * * * ? Weekdays at 9:00 AM 0 9 * * 1-5 0 0 9 ? * MON-FRI Midnight on the 1st of month 0 0 1 * * 0 0 0 1 * ? Every Friday at 6:30 PM 30 18 * * 5 0 30 18 ? * FRI 3rd Friday of every month (not expressible) 0 0 12 ? * 6#3 Last day of every month (not expressible) 0 0 0 L * ?
Using it in Spring Boot
Spring's @Scheduled annotation uses the same 6-field Quartz-style syntax (no year field) via its own cron parser:
@Component
public class ReportJob {
// Runs every weekday at 9:00:00 AM server time
@Scheduled(cron = "0 0 9 ? * MON-FRI")
public void generateDailyReport() {
// ...
}
// Runs every 5 minutes, at second 0
@Scheduled(cron = "0 */5 * * * ?")
public void pollQueue() {
// ...
}
}When to choose Quartz over system cron
- You need in-process scheduling that lives and dies with your JVM application, without depending on the host OS having cron configured.
- You need misfire handling — Quartz can detect a job that should have fired while the app was down and decide whether to fire it immediately, skip it, or run once.
- You need clustered scheduling — Quartz can persist job state to a database so only one node in a cluster executes a given job at a time.
- You need calendar exclusions (e.g. skip public holidays) built into the scheduler itself rather than hand-coded into the job.
Frequently Asked Questions
A Quartz cron expression has 6 or 7 fields: seconds, minutes, hours, day-of-month, month, day-of-week, and an optional year. Standard Unix cron only has 5 fields and has no seconds or year field.
Quartz does not allow both day-of-month and day-of-week to be specified with real values in the same expression, because the two constraints could conflict. One of them must be set to ? to mean "no specific value," leaving the other field in control.
Not directly. You need to prepend a seconds field, and if you use both day-of-month and day-of-week you must replace one with ?. For example, Unix 0 9 * * 1-5 becomes Quartz 0 0 9 ? * MON-FRI.