Quartz cron expression syntax
A Quartz cron expression uses 7 fields — seconds minutes hours day-of-month month day-of-week year — and is the cron flavor used by the Quartz Java scheduler, Spring Framework’s @Scheduled annotation, and any JVM application that depends on quartz-scheduler. It is NOT the same as Unix cron (5 fields, no seconds) or AWS EventBridge cron (6 fields, no seconds, with year).
Quick reference
| Field | Position | Allowed values | Special chars |
|---|---|---|---|
| Seconds | 1st | 0–59 | , - * / |
| Minutes | 2nd | 0–59 | , - * / |
| Hours | 3rd | 0–23 | , - * / |
| Day-of-month | 4th | 1–31 | , - * ? / L W |
| Month | 5th | 1–12 or JAN–DEC | , - * / |
| Day-of-week | 6th | 1–7 (SUN=1) or SUN–SAT | , - * ? / L # |
| Year (optional) | 7th | 1970–2099 | , - * / |
How does Quartz cron differ from Unix cron?
Three structural differences.
Seconds field at the front. Unix cron has no seconds — minute is the smallest unit. Quartz adds a leading seconds field, so the same “every 5 minutes” expression that’s */5 * * * * in Unix becomes 0 */5 * * * ? in Quartz: a literal 0 in seconds, then */5 in minutes, then ? in dow because dom is *.
The ? rule. Quartz forbids both day-of-month and day-of-week being concrete values (or both being *) at the same time. Exactly one of them must be ? (“no specific value”). This is because the two day fields can conflict — “the 5th of the month AND a Monday” rarely intersects, and Quartz wants you to be explicit about which day type matters. Unix cron treats dom-and-dow as logical OR; Quartz makes you pick.
Day-of-week numbering. Quartz uses 1–7 starting Sunday (Sun=1, Mon=2, …, Sat=7), inheriting Java’s Calendar.SUNDAY constant. Unix Vixie cron uses 0–6 starting Sunday. So 0 0 0 ? * 2 in Quartz means “midnight every Monday”; the same 0 0 0 * * 1 in Unix also means “midnight every Monday” — different number for the same day. Use named days (SUN, MON, …) whenever you can.
Special operators (Quartz adds three over Unix)
| Operator | Meaning | Example |
|---|---|---|
? | ”No specific value” — required in dom or dow | 0 0 12 ? * MON (noon every Monday) |
L (in dom) | Last day of the month | 0 0 0 L * ? (midnight on last day) |
L (in dow) | Last X-day of the month | 0 0 0 ? * 6L (last Friday of month) |
W | Nearest weekday to a date | 0 0 0 15W * ? (weekday closest to the 15th) |
# | Nth weekday of the month | 0 0 0 ? * MON#2 (2nd Monday of month) |
These operators don’t exist in standard Unix cron. AWS EventBridge inherited L, W and # from Quartz; Vixie cron does not.
Variations
| Schedule | Quartz expression |
|---|---|
| Every minute (top of the minute) | 0 * * * * ? |
| Every 5 minutes | 0 */5 * * * ? |
| Every 30 seconds | */30 * * * * ? |
| Every hour at :00 | 0 0 * * * ? |
| Every day at 9 AM | 0 0 9 * * ? |
| Every weekday at 9 AM | 0 0 9 ? * MON-FRI |
| Every Monday at 9 AM | 0 0 9 ? * MON |
| First day of every month at midnight | 0 0 0 1 * ? |
| Last day of every month at 11:59 PM | 0 59 23 L * ? |
| Second Tuesday of every month at noon | 0 0 12 ? * TUE#2 |
| Nearest weekday to the 15th | 0 0 12 15W * ? |
| Every January 1st at midnight | 0 0 0 1 1 ? * |
How do I use a Quartz cron expression?
Spring Framework @Scheduled:
@Component
public class WeeklyDigestJob {
// 9 AM every Monday — Quartz syntax
@Scheduled(cron = "0 0 9 ? * MON", zone = "America/New_York")
public void sendDigest() {
// ...
}
}
The zone parameter on @Scheduled is critical — without it, Spring uses the JVM default timezone, which on most container deployments is UTC.
Standalone Quartz Scheduler (Java):
JobDetail job = JobBuilder.newJob(WeeklyDigest.class)
.withIdentity("weeklyDigest")
.build();
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity("mondayMorning")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 9 ? * MON")
.inTimeZone(TimeZone.getTimeZone("America/New_York")))
.build();
scheduler.scheduleJob(job, trigger);
Quartz.NET (.NET equivalent):
await scheduler.ScheduleJob(job,
TriggerBuilder.Create()
.WithCronSchedule("0 0 9 ? * MON",
x => x.InTimeZone(TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time")))
.Build());
Common mistakes
Pasting a Unix cron expression into Spring @Scheduled. Spring expects 6-field Quartz syntax (the year is optional, but seconds is required). A Unix */5 * * * * is parsed as a 5-field expression in Spring’s parser and rejected. Add the seconds field: 0 */5 * * * * or 0 */5 * * * ? — the ? form is safer because it follows the Quartz rule.
Both dom and dow as *. Quartz throws ParseException: Support for specifying both a day-of-week AND a day-of-month parameter is not implemented. One of them must be ?. Pick ? for dow when you care about month-day; pick ? for dom when you care about week-day.
Treating Quartz numbers as Unix numbers. 0 0 9 ? * 1 in Quartz means Sunday 9 AM (Sun=1 in Quartz). The same expression in Unix doesn’t even parse (5 vs 7 fields), but if you mentally translate field-by-field you’d think “Monday” — wrong. Use named days to dodge this entirely.
Using 0 in the dow field. Quartz day-of-week is 1–7. 0 is rejected as out of range. The historical “Sunday=0” convention is Unix-only.
Pasting a Quartz expression into AWS EventBridge. AWS uses 6 fields, not 7 — drop the seconds field. The dow numbering matches Quartz (1–7 starting Sunday) and the special operators (L, W, #) work, so the rest usually ports cleanly.
For Unix cron schedules see common cron schedules, or build a standard expression with the Cron Expression Builder.
Frequently asked questions
- What's the difference between Quartz cron and Unix cron?
- Three big things. (1) Quartz has 7 fields including a leading **seconds** field and a trailing **year** field; Unix has 5 (no seconds, no year). (2) Quartz forbids both day-of-month and day-of-week being `*` at once — you must use `?` in one of them. (3) Quartz numbers days 1–7 starting Sunday; Unix is 0–6 starting Sunday. The same expression in the two flavors generally produces different schedules.
- Is AWS EventBridge cron the same as Quartz cron?
- No, but they're close enough to confuse. AWS EventBridge uses 6 fields (no seconds, but has year), inherits Quartz's `?` rule and 1–7 dow numbering, and supports the `L`, `W` and `#` special operators. The big differences from Quartz: no seconds field, and the year is at the end (year is also at the end in Quartz — same position, but Quartz has 7 fields total). If you're porting a Quartz expression to AWS, drop the seconds field and you're usually 90% there.
- How do I run a job every 30 seconds in Quartz?
- Quartz supports it natively — `*/30 * * * * ? *` runs every 30 seconds (the leading `*/30` is in the seconds field). This is the main reason teams reach for Quartz: standard Unix cron has no seconds field, so sub-minute schedules need workarounds. Quartz is also commonly used because Spring Framework's `@Scheduled` annotation accepts Quartz-style expressions out of the box.
Need a different schedule?
Build cron expressions for Unix, Kubernetes, AWS EventBridge and Quartz — with a human-readable description and the next 5 run times.
Open the Cron Expression Builder →Related
What is a cron job?
A cron job is a scheduled command that runs at fixed times on Unix-like systems. The schedule is a one-line cron expression of five space-separated fields.
Cron expression for every 5 minutes
The cron expression `*/5 * * * *` runs every 5 minutes in Linux crontab, Kubernetes, GitHub Actions; `cron(*/5 * * * ? *)` in AWS EventBridge.
Cron expression for every 15 minutes
The cron expression `*/15 * * * *` runs every 15 minutes — at :00, :15, :30, :45 — across Linux, Kubernetes, GitHub Actions and AWS.
Cron expression for every 30 minutes
The cron expression `*/30 * * * *` runs every 30 minutes — at :00 and :30 of every hour. Same in Linux, Kubernetes and GitHub Actions; `cron(*/30 * * * ? *)` in AWS.
Cron expression for every hour
The cron expression `0 * * * *` runs once per hour on the hour. Same syntax in Linux, Kubernetes and GitHub Actions; `cron(0 * * * ? *)` in AWS EventBridge.
Cron expression for daily at midnight
The cron expression `0 0 * * *` runs once daily at midnight. Watch the timezone — Kubernetes < 1.25 and AWS EventBridge default to UTC, not local time.