Month end that skips four months
A hard Java puzzle in the scheduling and cron mistakes family. One line below contains a real bug. Try to spot it first, then read why it fails and how to fix it.
Highlighted: line 7. Play this one as a puzzle without the answer.
What is wrong
Day 31 exists only in seven months. In April, June, September, November and February the job never runs, so customers are not invoiced. Spring cron has no L for last day in older versions; the dialects differ.
The fix
How to avoid it next time
Use L (last day) where the dialect supports it, or schedule daily and decide in code. Test the schedule with a cron tool.
Want the background? Read Cron expressions in Java in the Java concepts library.
About scheduling and cron mistakes
Cron dialects differ in field count and meaning. Spring has six fields starting with seconds, Unix has five, Quartz needs a question mark in one day field, and time zones decide when midnight actually is.
In code review: Count the fields and check which dialect the framework expects. Confirm the time zone and what the day-of-week field numbers mean in that dialect.
More puzzles in this family
Frequently asked questions
What is the bug in "Month end that skips four months"?
Day 31 exists only in seven months. In April, June, September, November and February the job never runs, so customers are not invoiced. Spring cron has no L for last day in older versions; the dialects differ. The faulty line is line 7: @Scheduled(cron = "0 0 2 31 * *")
How do I fix it?
Replace it with: @Scheduled(cron = "0 0 2 L * *") // Spring 5.3+, or run daily at 02:00 and check LocalDate.now().lengthOfMonth(). Use L (last day) where the dialect supports it, or schedule daily and decide in code. Test the schedule with a cron tool.
How do I catch scheduling and cron mistakes in code review?
Count the fields and check which dialect the framework expects. Confirm the time zone and what the day-of-week field numbers mean in that dialect.
Is there a new puzzle every day?
Yes. The daily Spot the Bug puzzle picks one of these snippets for each UTC day, with the difficulty set by the weekday. Your streak is stored only in your browser.