Home โบ Cron errors โบ Quartz
Quartz expression is valid but never fires
Why this happens
February never has 30 days, so the expression is syntactically fine but matches no date. Quartz may throw at schedule time or silently never run it.
Wrong and right
0 0 0 30 2 ?No run times in the next several years.
0 0 0 L 2 ?At 00:00 UTC, on the last day of the month, in Feb. First runs after 1 Jan 2027 (UTC): Sun 28 Feb, 00:00, Tue 29 Feb, 00:00, Wed 28 Feb, 00:00, Thu 28 Feb, 00:00, Fri 28 Feb, 00:00
How to fix it
- Use L to mean the last day of February.
- Check the next-run preview. An empty result means it never fires.
- Remember 31 skips 30-day months and 29 skips non-leap Februarys.
The Quartz format at a glance
Fields in order: second (0-59), minute (0-59), hour (0-23), day-of-month (1-31), month (1-12), day-of-week (1-7, 1 = Sunday), year (1970-2199, optional).
Quartz uses the JVM default time zone unless you set one: CronScheduleBuilder.cronSchedule(expr).inTimeZone(TimeZone.getTimeZone("UTC")).
The fixed schedule in other systems
If you are moving this schedule to another scheduler, these are the equivalents of 0 0 0 L 2 ?:
| System | Expression |
|---|---|
| Spring | 0 0 0 L 2 * |
| AWS EventBridge | 0 0 L 2 ? * |
| node-cron | 0 0 L 2 * |
| Apache Airflow | 0 0 L 2 * |
Try it yourself
The tester below starts with the fixed expression. Change it and watch the schedule update.
Your week at a glance
Upcoming runs
| # | Local | UTC | From now |
|---|
Copy-ready code
Frequently asked questions
Will Quartz warn me?
Often only when you call getFireTimeAfter and get null. Preview your expression before shipping.
More Quartz fixes
See the full Quartz cron builder or convert between formats.