Skip to content

nW in day of month throws DateTimeException when the month is shorter than n #715

Description

@austek

nW (nearest weekday to the nth of the month) throws java.time.DateTimeException instead of skipping months that have fewer than n days. Affects QUARTZ and SPRING53 (any definition with supportsW() on day of month).

Reproduction

CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ));
ExecutionTime et = ExecutionTime.forCron(parser.parse("0 0 0 31W * ?"));
et.nextExecution(ZonedDateTime.parse("2025-06-01T00:00:00Z"));

Actual

java.time.DateTimeException: Invalid date 'JUNE 31'

Same for SPRING53. 30W evaluated from a 30-day month works fine, so the failure is specifically "requested day exceeds the length of the candidate month".

Expected

Quartz skips such months. Reference behaviour from org.quartz.CronExpression 2.5.0, same expression and start instant:

0 0 0 31W * ?  ->  2025-07-31, 2025-08-29, 2025-10-31, 2025-12-31, 2026-01-30

June, September and November (30 days) and February are skipped; 2025-08-29 and 2026-01-30 show the weekday adjustment applied after the month is accepted.

Cause

OnDayOfMonthValueGenerator.generateValue, case W: constructs the date before checking the month length:

case W: // First work day of the week
    final LocalDate doM = LocalDate.of(year, month, dayOfMonth);

LocalDate.of throws for dayOfMonth > lengthOfMonth. The case L: branch above it reads lengthOfMonth() first and is unaffected. A guard that reports no value for the month (so the generator moves to the next one) would line up with the reference behaviour.

Version: reproduced on master (bac6e86).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions