From 9f8938b89a67ff8da148b7b865576a3d5584c610 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 14 Jun 2018 12:18:20 +0200 Subject: Cope if mktime() deems times in a spring forward gap to be invalid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In tst_QDateTime::springForward(), we test correct handling of times in the gap; these are formally invalid and a mktime() implementation may reasonably reject them causing our date-time code to produce an invalid result. So handle that case gracefully in the tests, only insisting on consistency between the two ways of preparing the date. In one test, package the repeated code I was going to adapt into a macro to save repeitition. Task-number: QTBUG-68832 Task-number: QTBUG-68839 Change-Id: Ib8a16ff007f4e75ab2ccff05b1ccf00a45e50dc8 Reviewed-by: Thiago Macieira Reviewed-by: MÃ¥rten Nordheim --- .../auto/corelib/tools/qdatetime/tst_qdatetime.cpp | 62 ++++++++++++---------- 1 file changed, 35 insertions(+), 27 deletions(-) (limited to 'tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp') diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp index e9d2fba47f..4e77ff9461 100644 --- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp @@ -1868,12 +1868,14 @@ void tst_QDateTime::springForward() QFETCH(int, adjust); QDateTime direct = QDateTime(day.addDays(-step), time, Qt::LocalTime).addDays(step); - QCOMPARE(direct.date(), day); - QCOMPARE(direct.time().minute(), time.minute()); - QCOMPARE(direct.time().second(), time.second()); - int off = direct.time().hour() - time.hour(); - QVERIFY(off == 1 || off == -1); - // Note: function doc claims always +1, but this should be reviewed ! + if (direct.isValid()) { // mktime() may deem a time in the gap invalid + QCOMPARE(direct.date(), day); + QCOMPARE(direct.time().minute(), time.minute()); + QCOMPARE(direct.time().second(), time.second()); + int off = direct.time().hour() - time.hour(); + QVERIFY(off == 1 || off == -1); + // Note: function doc claims always +1, but this should be reviewed ! + } // Repeat, but getting there via .toLocalTime(): QDateTime detour = QDateTime(day.addDays(-step), @@ -1881,7 +1883,11 @@ void tst_QDateTime::springForward() Qt::UTC).toLocalTime(); QCOMPARE(detour.time(), time); detour = detour.addDays(step); - QCOMPARE(detour, direct); // Insist on consistency. + // Insist on consistency: + if (direct.isValid()) + QCOMPARE(detour, direct); + else + QVERIFY(!detour.isValid()); } void tst_QDateTime::operator_eqeq_data() @@ -2901,38 +2907,40 @@ void tst_QDateTime::daylightTransitions() const QCOMPARE(utc.date(), QDate(2012, 3, 25)); QCOMPARE(utc.time(), QTime(2, 0, 0)); - // Test date maths, if result falls in missing hour then becomes next hour + // Test date maths, if result falls in missing hour then becomes next + // hour (or is always invalid; mktime() may reject gap-times). QDateTime test(QDate(2011, 3, 25), QTime(2, 0, 0)); QVERIFY(test.isValid()); test = test.addYears(1); - QVERIFY(test.isValid()); - QCOMPARE(test.date(), QDate(2012, 3, 25)); - QCOMPARE(test.time(), QTime(3, 0, 0)); + const bool handled = test.isValid(); +#define CHECK_SPRING_FORWARD(test) \ + if (test.isValid()) { \ + QCOMPARE(test.date(), QDate(2012, 3, 25)); \ + QCOMPARE(test.time(), QTime(3, 0, 0)); \ + } else { \ + QVERIFY(!handled); \ + } + CHECK_SPRING_FORWARD(test); test = QDateTime(QDate(2012, 2, 25), QTime(2, 0, 0)); QVERIFY(test.isValid()); test = test.addMonths(1); - QVERIFY(test.isValid()); - QCOMPARE(test.date(), QDate(2012, 3, 25)); - QCOMPARE(test.time(), QTime(3, 0, 0)); + CHECK_SPRING_FORWARD(test); test = QDateTime(QDate(2012, 3, 24), QTime(2, 0, 0)); QVERIFY(test.isValid()); test = test.addDays(1); - QVERIFY(test.isValid()); - QCOMPARE(test.date(), QDate(2012, 3, 25)); - QCOMPARE(test.time(), QTime(3, 0, 0)); + CHECK_SPRING_FORWARD(test); test = QDateTime(QDate(2012, 3, 25), QTime(1, 0, 0)); QVERIFY(test.isValid()); QCOMPARE(test.toMSecsSinceEpoch(), daylight2012 - msecsOneHour); test = test.addMSecs(msecsOneHour); - QVERIFY(test.isValid()); - QCOMPARE(test.date(), QDate(2012, 3, 25)); - QCOMPARE(test.time(), QTime(3, 0, 0)); - QCOMPARE(test.toMSecsSinceEpoch(), daylight2012); - + CHECK_SPRING_FORWARD(test); + if (handled) + QCOMPARE(test.toMSecsSinceEpoch(), daylight2012); +#undef CHECK_SPRING_FORWARD // Test for correct behviour for DaylightTime -> StandardTime transition, i.e. second occurrence @@ -2954,7 +2962,7 @@ void tst_QDateTime::daylightTransitions() const QVERIFY(msecBefore.isValid()); QCOMPARE(msecBefore.date(), QDate(2012, 10, 28)); QCOMPARE(msecBefore.time(), QTime(2, 59, 59, 999)); -#if defined(Q_OS_MAC) || defined(Q_OS_WIN) || defined(Q_OS_QNX) +#if defined(Q_OS_DARWIN) || defined(Q_OS_WIN) || defined(Q_OS_QNX) || defined(Q_OS_ANDROID) // Win and Mac uses SecondOccurrence here QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue); #endif // Q_OS_MAC @@ -2976,8 +2984,8 @@ void tst_QDateTime::daylightTransitions() const QVERIFY(afterTran.isValid()); QCOMPARE(afterTran.date(), QDate(2012, 10, 28)); QCOMPARE(afterTran.time(), QTime(2, 59, 59, 999)); -#if defined (Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_QNX) - // Linux mktime bug uses last calculation +#ifdef __GLIBCXX__ + // Linux (i.e. glibc) mktime bug reuses last calculation QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue); #endif // Q_OS_UNIX QCOMPARE(afterTran.toMSecsSinceEpoch(), standard2012 + msecsOneHour - 1); @@ -3183,12 +3191,12 @@ void tst_QDateTime::daylightTransitions() const test = test.addMSecs(msecsOneHour); QVERIFY(test.isValid()); QCOMPARE(test.date(), QDate(2012, 10, 28)); -#if defined(Q_OS_MAC) || defined(Q_OS_QNX) +#if defined(Q_OS_DARWIN) || defined(Q_OS_QNX) || defined(Q_OS_ANDROID) // Mac uses FirstOccurrence, Windows uses SecondOccurrence, Linux uses last calculation QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue); #endif // Q_OS_WIN QCOMPARE(test.time(), QTime(3, 0, 0)); -#if defined(Q_OS_MAC) || defined(Q_OS_QNX) +#if defined(Q_OS_DARWIN) || defined(Q_OS_QNX) || defined(Q_OS_ANDROID) // Mac uses FirstOccurrence, Windows uses SecondOccurrence, Linux uses last calculation QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue); #endif // Q_OS_WIN -- cgit v1.2.3