From 684f5eadaecc6ee7d88da390b3d4b43fb142cf25 Mon Sep 17 00:00:00 2001 From: sahvx655-wq Date: Mon, 22 Jun 2026 20:27:08 +0530 Subject: [PATCH] compare week-year not calendar year in compareWeeks AbstractCalendarValidator.compare ordered WEEK_OF_YEAR on Calendar.YEAR, but a week belongs to its week-year, which differs from the calendar year at the year boundary, so compareWeeks treated 31 Dec and 1 Jan of the same calendar year as the same week. Compare the week-year (getWeekYear, falling back to YEAR when week dates are unsupported) before the week number. --- .../routines/AbstractCalendarValidator.java | 26 +++++++++++++++---- .../routines/CalendarValidatorTest.java | 21 +++++++++++++++ 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/apache/commons/validator/routines/AbstractCalendarValidator.java b/src/main/java/org/apache/commons/validator/routines/AbstractCalendarValidator.java index a2b2e9a2b..ae01d5afd 100644 --- a/src/main/java/org/apache/commons/validator/routines/AbstractCalendarValidator.java +++ b/src/main/java/org/apache/commons/validator/routines/AbstractCalendarValidator.java @@ -117,17 +117,23 @@ protected int compare(final Calendar value, final Calendar compare, final int fi int result; + // Week of Year is relative to its own week-year, which at the year boundary can differ + // from the calendar year (for example 31 December may fall in week 1 of the following + // week-year), so the week-year is compared rather than YEAR for this field. + if (field == Calendar.WEEK_OF_YEAR) { + result = Integer.compare(weekYear(value), weekYear(compare)); + if (result != 0) { + return result; + } + return calculateCompareResult(value, compare, Calendar.WEEK_OF_YEAR); + } + // Compare Year result = calculateCompareResult(value, compare, Calendar.YEAR); if (result != 0 || field == Calendar.YEAR) { return result; } - // Compare Week of Year - if (field == Calendar.WEEK_OF_YEAR) { - return calculateCompareResult(value, compare, Calendar.WEEK_OF_YEAR); - } - // Compare Day of the Year if (field == Calendar.DAY_OF_YEAR) { return calculateCompareResult(value, compare, Calendar.DAY_OF_YEAR); @@ -416,4 +422,14 @@ protected Object parse(String value, final String pattern, final Locale locale, */ @Override protected abstract Object processParsedValue(Object value, Format formatter); + + /** + * Returns the week-year of a calendar, which a {@code WEEK_OF_YEAR} value is relative to. + * + * @param calendar The calendar to read the week-year from. + * @return the week-year, or the calendar year if week dates are not supported. + */ + private int weekYear(final Calendar calendar) { + return calendar.isWeekDateSupported() ? calendar.getWeekYear() : calendar.get(Calendar.YEAR); + } } diff --git a/src/test/java/org/apache/commons/validator/routines/CalendarValidatorTest.java b/src/test/java/org/apache/commons/validator/routines/CalendarValidatorTest.java index 2d835aff0..172022769 100644 --- a/src/test/java/org/apache/commons/validator/routines/CalendarValidatorTest.java +++ b/src/test/java/org/apache/commons/validator/routines/CalendarValidatorTest.java @@ -232,6 +232,27 @@ void testCompare() { assertEquals("Invalid field: -1", e.getMessage(), "check message"); } + /** + * Test compareWeeks() at the week-year boundary, where WEEK_OF_YEAR is relative to a + * week-year that differs from the calendar year. + */ + @Test + @DefaultLocale(country = "US", language = "en") + void testCompareWeeksAcrossYearBoundary() { + final int noon = 120000; + // 31 Dec 2018 (Monday) is in week 1 of week-year 2019 (US: first day Sunday, minimal days 1) + final Calendar dec31y2018 = createCalendar(TimeZones.GMT, 20181231, noon); + final Calendar jan01y2018 = createCalendar(TimeZones.GMT, 20180101, noon); + final Calendar jan01y2019 = createCalendar(TimeZones.GMT, 20190101, noon); + + // both are calendar year 2018 and week-of-year 1, but lie ~52 weeks apart + assertEquals(1, calValidator.compareWeeks(dec31y2018, jan01y2018), "Dec 31 2018 is weeks after Jan 1 2018"); + assertEquals(-1, calValidator.compareWeeks(jan01y2018, dec31y2018), "Jan 1 2018 is weeks before Dec 31 2018"); + + // 31 Dec 2018 and 1 Jan 2019 share week 1 of week-year 2019, so they are the same week + assertEquals(0, calValidator.compareWeeks(dec31y2018, jan01y2019), "Dec 31 2018 is the same week as Jan 1 2019"); + } + /** * Test Date/Time style Validator (there isn't an implementation for this) */