From cd442e439b73b8de4e0fc1434320a3ed1a465d2f Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Fri, 16 Aug 2024 16:01:04 +0200 Subject: [PATCH] Change handling of unspecified year in QCalendar::daysInMonth() Previously, this was specified to return the usual number of days in the month. What the date-time parser needs, though, is the longest that the relevant month can be, in any year. So change its specification to that. This affects all calendar backends, effectively requiring daysInMonth() to treat Unspecified as if it were a leap year. [ChangeLog][QtCore][QCalendar][Important Behavior Changes] The daysInMonth(month, Unspecified) corner case is now specified to return the greatest number of days in that month across all years, where previously it returned the usual number of days in the month. This means QCalendar().daysInMonth(2) is now 29 rather than 28, with similar for other calendars than the Gregorian default. Change-Id: I165599c655df9fbd77700ed38d8860a4e5cca881 Reviewed-by: Marc Mutz --- src/corelib/time/qcalendar.cpp | 2 +- src/corelib/time/qhijricalendar.cpp | 2 +- src/corelib/time/qjalalicalendar.cpp | 3 +- src/corelib/time/qromancalendar.cpp | 2 +- .../corelib/time/qcalendar/tst_qcalendar.cpp | 29 +++++++++---------- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/corelib/time/qcalendar.cpp b/src/corelib/time/qcalendar.cpp index c87d4b7cf39..769174972ac 100644 --- a/src/corelib/time/qcalendar.cpp +++ b/src/corelib/time/qcalendar.cpp @@ -1259,7 +1259,7 @@ QCalendar::QCalendar(QAnyStringView name) Months are numbered consecutively, starting with 1 for the first month of each year. If \a year is \c Unspecified (its default, if not passed), the - month's length in a normal year is returned. + month's greatest length in any year is returned. \sa maximumDaysInMonth(), minimumDaysInMonth() */ diff --git a/src/corelib/time/qhijricalendar.cpp b/src/corelib/time/qhijricalendar.cpp index 3d5a97c3109..6a0f22d15d3 100644 --- a/src/corelib/time/qhijricalendar.cpp +++ b/src/corelib/time/qhijricalendar.cpp @@ -61,7 +61,7 @@ int QHijriCalendar::daysInMonth(int month, int year) const if (year == 0 || month < 1 || month > 12) return 0; - if (month == 12 && isLeapYear(year)) + if (month == 12 && (year == QCalendar::Unspecified || isLeapYear(year))) return 30; return month % 2 == 0 ? 29 : 30; diff --git a/src/corelib/time/qjalalicalendar.cpp b/src/corelib/time/qjalalicalendar.cpp index fcbdf143958..6b3b6e4e9e5 100644 --- a/src/corelib/time/qjalalicalendar.cpp +++ b/src/corelib/time/qjalalicalendar.cpp @@ -156,7 +156,8 @@ QCalendar::YearMonthDay QJalaliCalendar::julianDayToDate(qint64 jd) const int QJalaliCalendar::daysInMonth(int month, int year) const { if (year && month > 0 && month <= 12) - return month < 7 ? 31 : month < 12 || isLeapYear(year) ? 30 : 29; + return month < 7 ? 31 : (month < 12 || year == QCalendar::Unspecified + || isLeapYear(year)) ? 30 : 29; return 0; } diff --git a/src/corelib/time/qromancalendar.cpp b/src/corelib/time/qromancalendar.cpp index 0a7399ea515..ae113cf8323 100644 --- a/src/corelib/time/qromancalendar.cpp +++ b/src/corelib/time/qromancalendar.cpp @@ -29,7 +29,7 @@ int QRomanCalendar::daysInMonth(int month, int year) const return 0; if (month == 2) - return isLeapYear(year) ? 29 : 28; + return year == QCalendar::Unspecified || isLeapYear(year) ? 29 : 28; // Long if odd up to July = 7, or if even from 8 = August onwards: return 30 | ((month & 1) ^ (month >> 3)); diff --git a/tests/auto/corelib/time/qcalendar/tst_qcalendar.cpp b/tests/auto/corelib/time/qcalendar/tst_qcalendar.cpp index 61999202d2d..3b58f872d21 100644 --- a/tests/auto/corelib/time/qcalendar/tst_qcalendar.cpp +++ b/tests/auto/corelib/time/qcalendar/tst_qcalendar.cpp @@ -11,7 +11,7 @@ class tst_QCalendar : public QObject { Q_OBJECT private: - void checkYear(const QCalendar &cal, int year, bool normal=false); + void checkYear(const QCalendar &cal, int year); private slots: void basic_data(); @@ -75,7 +75,7 @@ static void checkCenturyResolution(const QCalendar &cal, const QCalendar::YearMo } // Support for basic(): -void tst_QCalendar::checkYear(const QCalendar &cal, int year, bool normal) +void tst_QCalendar::checkYear(const QCalendar &cal, int year) { const int moons = cal.monthsInYear(year); // Months are numbered from 1 to moons: @@ -103,8 +103,8 @@ void tst_QCalendar::checkYear(const QCalendar &cal, int year, bool normal) QVERIFY(cal.isDateValid(year, i, last)); QVERIFY(!cal.isDateValid(year, i, 0)); QVERIFY(!cal.isDateValid(year, i, last + 1)); - if (normal) // Unspecified year gets same daysInMonth(): - QCOMPARE(cal.daysInMonth(i), last); + // Unspecified year gets max daysInMonth(): + QCOMPARE_GE(cal.daysInMonth(i), last); checkCenturyResolution(cal, {year, i, (last + 1) / 2}); if (QTest::currentTestFailed()) @@ -114,11 +114,7 @@ void tst_QCalendar::checkYear(const QCalendar &cal, int year, bool normal) QCOMPARE(sum, days); } -#define CHECKYEAR(cal, year) checkYear(cal, year); \ - if (QTest::currentTestFailed()) \ - return - -#define NORMALYEAR(cal, year) checkYear(cal, year, true); \ +#define CHECKYEAR(cal, year) checkYear(cal, year); \ if (QTest::currentTestFailed()) \ return @@ -177,7 +173,7 @@ void tst_QCalendar::basic() } // Either year is non-leap or we have a decade of leap years together; // expect daysInMonth() to treat year the same as unspecified. - NORMALYEAR(cal, year); + CHECKYEAR(cal, year); } void tst_QCalendar::unspecified() @@ -189,15 +185,18 @@ void tst_QCalendar::unspecified() const int thisYear = today.year(); QCOMPARE(cal.monthsInYear(QCalendar::Unspecified), cal.maximumMonthsInYear()); for (int month = cal.maximumMonthsInYear(); month > 0; month--) { - const int days = cal.daysInMonth(month); - int count = 0; + const int maxDays = cal.daysInMonth(month); + bool hitMax = false; // 19 years = one Metonic cycle (used by some lunar calendars) for (int i = 19; i > 0; --i) { - if (cal.daysInMonth(month, thisYear - i) == days) - count++; + int days = cal.daysInMonth(month, thisYear - i); + if (days == maxDays) + hitMax = true; + else + QCOMPARE_LT(days, maxDays); } // Require a majority of the years tested: - QVERIFY2(count > 9, "Default daysInMonth() should be for a normal year"); + QVERIFY2(hitMax, "Default daysInMonth() should be the longest that month gets"); } }