/
Application Framework

Quartz Scheduler Cron Guide

Quartz is the most widely used job scheduling library in the Java ecosystem, and its CronExpression class defines a cron dialect that's become influential enough that AWS EventBridge and Spring both adopted variations of it. Quartz cron is more expressive than standard cron, at the cost of a stricter, less forgiving syntax.

Syntax Notes

6 required fields plus an optional 7th: seconds, minutes, hours, day-of-month, month, day-of-week, year (optional). Exactly one of day-of-month/day-of-week must be ? — both can't be * simultaneously, the same constraint AWS EventBridge inherited from Quartz.

Examples

Every day at 8:30:00 AM
0 30 8 * * ?
Last day of every month at midnight
0 0 0 L * ?
First Friday of every month at noon
0 0 12 ? * 6#1
Java: scheduling with CronScheduleBuilder
CronTrigger trigger = TriggerBuilder.newTrigger()
  .withSchedule(CronScheduleBuilder.cronSchedule("0 0 2 * * ?"))
  .build();

Gotchas

  • Quartz throws a ParseException at trigger-creation time (not silently) if both day-of-month and day-of-week are * — you must set one of them to ? — this is a frequent first-time error for anyone used to standard cron's OR semantics.
  • The L (last) and W (nearest weekday) characters can be combined (LW means "last weekday of the month") but have specific restrictions — L can't be used with a list or range of values in the same field, which throws a runtime error if attempted.
  • The # character (nth weekday, e.g. 6#3 for the third Friday) only accepts values 1–5, and there's no way to express "last occurrence of weekday X" other than combining it with L in the day-of-month field in specific ways — the syntax here is genuinely more complex than the L/W characters alone suggest.

Best Practices

  • Always set day-of-month or day-of-week to ? (never both to *), and treat that as a required first check whenever a Quartz expression fails to parse.
  • Use Quartz's own CronExpression.isValidExpression() (or an equivalent validator) at application startup or in tests, rather than discovering a malformed expression when the trigger fires the first time in production.
  • Keep a comment next to any expression using L, W, or # explaining the intended date in plain English — these characters are powerful but not immediately readable at a glance.

Frequently Asked Questions

What does the ? character mean in Quartz cron?
It means "no specific value" and is required in either the day-of-month or day-of-week field whenever the other field has a specific value — it exists specifically to avoid the ambiguous OR-logic that standard cron uses when both fields are restricted.
Can I use Quartz cron syntax in a Linux crontab?
No — the seventh (year) field, the ? character, and L/W/# are all Quartz-specific extensions that standard Vixie/POSIX cron doesn't understand. Quartz expressions need to be translated to standard syntax (dropping unsupported characters) to run on Linux cron.
Is the year field required?
No, it's optional — if omitted, Quartz treats the year as unrestricted (matches any year), which is the correct default for the overwhelming majority of recurring schedules.