Seconds come first
second minute hour day-of-month month day-of-week [year]. A standard 0 9 * * * (9am daily) becomes 0 0 9 * * ? in Quartz — note the extra leading zero for seconds.
Pasting a 5-field expression into Spring's @Scheduled(cron=...) shifts every field by one position. The job will run, at entirely the wrong time, which makes this a nasty bug to spot.
The ? placeholder
Like EventBridge, Quartz forbids specifying both day-of-month and day-of-week. One must be ?. This is why nearly every Quartz example ends in * ? or ? *.
Special characters worth knowing
L— last.0 0 0 L * ?is midnight on the last day of the month, which standard cron simply cannot express.6Lin day-of-week means the last Friday.W— nearest weekday.15Wfires on the weekday closest to the 15th, useful for business-day billing.#— nth weekday.6#3is the third Friday of the month./— steps, as in standard cron.
Spring's own variant
Spring accepts Quartz-style 6-field expressions but does not support L, W or # in its default CronExpression parser — those need a real Quartz scheduler. Spring does add its own @yearly-style macros and a zone attribute on @Scheduled, which is the cleanest way to pin a Java job to a local timezone.
Frequently asked questions
How many fields does a Quartz cron expression have?
Six or seven: seconds, minutes, hours, day-of-month, month, day-of-week, and an optional year.
Why does my Spring @Scheduled cron run at the wrong time?
Most likely you pasted a 5-field standard cron expression. Spring expects seconds first, so every field shifts by one position.
How do I schedule the last day of the month in Quartz?
0 0 0 L * ?. The L character means 'last' and has no equivalent in standard POSIX cron.
Related cron expressions
Browse the full cron expression reference, or build your own expression from scratch.