summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2021-02-04 16:47:34 +0100
committerEdward Welbourne <edward.welbourne@qt.io>2021-02-15 23:39:19 +0100
commit8de9fefed89504556e66d9ef17f534ea0b20d42c (patch)
tree2f784982205cfac4b42d5fd774ff8da64ec7ebbe
parent3062902f70c77abdb64ad2afbd02aaf149b3711d (diff)
Fix tst_QDateTime::systemTimeZoneChange() for 32-bit systems
The test verified that a LocalTime's time since Epoch changes when the system time-zone changes. This works when the QDateTime object is in short form and recomputes its offset from UTC every time it is needed, but fails with a pimpled QDateTime, as this caches its offset from UTC when it is created, saving the recomputation which - in the far more usual case where the system time-zone does not change in the lifetime of a QDateTime object - would normally produce the same result. Changed the test to use a newly-created QDateTime constructed with the same parameters, which doesn't have the cached out-of-date knowledge of its zone offset. Removed the XFAIL. Made the test data-driven and added test-cases: one so close to the Epoch that it should be short even on 32-bit systems, one so far that it's pimpled even on 64-bit systems (used in reproducing the issue in order to debug it). This then revealed that Android 5 doesn't seem to support the POSIX zone IDs used by this test, so it now verifies that LocalTime has the expected offset from UTC after zone changes, QSKIP()ping if not. Documented that the behavior of LocalTime is undefined after a change to the system time-zone. Cleaned up the existing doc of Qt::TimeSpec in the process. Fixes: QTBUG-89889 Change-Id: I1058f47a1ff3ee1c326f3579ac80bd8bab242e28 Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> (cherry picked from commit 02ae1b522193b60e7a5c8e5eff7a15d25b0f7aae)
-rw-r--r--src/corelib/global/qnamespace.qdoc22
-rw-r--r--tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp54
2 files changed, 59 insertions, 17 deletions
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index 97d79f4b1e..dd6fccd678 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -728,10 +728,26 @@
/*!
\enum Qt::TimeSpec
- \value LocalTime Locale dependent time (Timezones and Daylight Savings Time).
- \value UTC Coordinated Universal Time, replaces Greenwich Mean Time.
+ \value LocalTime Local time, controlled by a system time-zone setting.
+ \value UTC Coordinated Universal Time.
\value OffsetFromUTC An offset in seconds from Coordinated Universal Time.
- \value TimeZone A named time zone using a specific set of Daylight Savings rules.
+ \value TimeZone A named time zone.
+
+ Both LocalTime and TimeZone will take care of transitions, such as
+ the start and end of daylight-saving time. UTC is the standard
+ time relative to which time-zones are usually specified: Greenwich
+ Mean Time has zero offset from it. Neither UTC nor OffsetFromUTC
+ has any transitions.
+
+ \note After a change to the system time-zone setting, the behavior
+ of LocalTime-based QDateTime objects created before the change is
+ undefined: QDateTime may have cached data that the change
+ invalidates. (This is not triggered by transitions of the system
+ time-zone.) In long-running processes, updates to the system's
+ time-zone data (e.g. when politicians change the rules for a zone)
+ may likewise lead to conflicts between the updated time-zone
+ information and data cached by QDateTime objects created before
+ the update, using either LocalTime or TimeZone.
*/
/*!
diff --git a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp
index 146c6b37a5..700524364e 100644
--- a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp
+++ b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2016 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
@@ -141,6 +141,7 @@ private Q_SLOTS:
void isDaylightTime() const;
void daylightTransitions() const;
void timeZones() const;
+ void systemTimeZoneChange_data() const;
void systemTimeZoneChange() const;
void invalid_data() const;
@@ -3798,35 +3799,60 @@ void tst_QDateTime::timeZones() const
#endif
}
+void tst_QDateTime::systemTimeZoneChange_data() const
+{
+ QTest::addColumn<QDate>("date");
+ QTest::newRow("short") << QDate(1970, 1, 1);
+ QTest::newRow("2012") << QDate(2012, 6, 1); // short on 64-bit, pimpled on 32-bit
+ QTest::newRow("pimpled") << QDate(1150000, 6, 1);
+}
+
void tst_QDateTime::systemTimeZoneChange() const
{
- // Set the timezone to Brisbane time
- TimeZoneRollback useZone(QByteArray("AEST-10:00"));
+ QFETCH(const QDate, date);
+ const QTime early(2, 15, 30);
- QDateTime localDate = QDateTime(QDate(2012, 6, 1), QTime(2, 15, 30), Qt::LocalTime);
- QDateTime utcDate = QDateTime(QDate(2012, 6, 1), QTime(2, 15, 30), Qt::UTC);
+ // Start out in Brisbane time:
+ TimeZoneRollback useZone(QByteArray("AEST-10:00"));
+ if (QDateTime(date, early, Qt::LocalTime).offsetFromUtc() != 600 * 60)
+ QSKIP("Test depends on system support for changing zone to AEST-10:00");
#if QT_CONFIG(timezone)
- QDateTime tzDate = QDateTime(QDate(2012, 6, 1), QTime(2, 15, 30), QTimeZone("Australia/Brisbane"));
+ QVERIFY(QTimeZone::systemTimeZone().isValid());
#endif
- qint64 localMsecs = localDate.toMSecsSinceEpoch();
- qint64 utcMsecs = utcDate.toMSecsSinceEpoch();
+
+ const QDateTime localDate = QDateTime(date, early, Qt::LocalTime);
+ const QDateTime utcDate = QDateTime(date, early, Qt::UTC);
+ const qint64 localMsecs = localDate.toMSecsSinceEpoch();
+ const qint64 utcMsecs = utcDate.toMSecsSinceEpoch();
#if QT_CONFIG(timezone)
- qint64 tzMsecs = tzDate.toMSecsSinceEpoch();
+ const QTimeZone aest("Australia/Brisbane"); // no transitions since 1992
+ // Check that Australia/Brisbane is known:
+ QVERIFY(aest.isValid());
+ const QDateTime tzDate = QDateTime(date, early, aest);
- // check that Australia/Brisbane is known
+ // Check we got the right zone !
QVERIFY(tzDate.timeZone().isValid());
+ QCOMPARE(tzDate.timeZone(), aest);
+ const qint64 tzMsecs = tzDate.toMSecsSinceEpoch();
#endif
// Change to Indian time
useZone.reset(QByteArray("IST-05:30"));
+ if (QDateTime(date, early, Qt::LocalTime).offsetFromUtc() != 330 * 60)
+ QSKIP("Test depends on system support for changing zone to IST-05:30");
+#if QT_CONFIG(timezone)
+ QVERIFY(QTimeZone::systemTimeZone().isValid());
+#endif
- QCOMPARE(localDate, QDateTime(QDate(2012, 6, 1), QTime(2, 15, 30), Qt::LocalTime));
- QVERIFY(localMsecs != localDate.toMSecsSinceEpoch());
- QCOMPARE(utcDate, QDateTime(QDate(2012, 6, 1), QTime(2, 15, 30), Qt::UTC));
+ QCOMPARE(localDate, QDateTime(date, early, Qt::LocalTime));
+ // Note: localDate.toMSecsSinceEpoch() == localMsecs, unchanged, iff localDate is pimpled.
+ QVERIFY(localMsecs != QDateTime(date, early, Qt::LocalTime).toMSecsSinceEpoch());
+ QCOMPARE(utcDate, QDateTime(date, early, Qt::UTC));
QCOMPARE(utcDate.toMSecsSinceEpoch(), utcMsecs);
#if QT_CONFIG(timezone)
- QCOMPARE(tzDate, QDateTime(QDate(2012, 6, 1), QTime(2, 15, 30), QTimeZone("Australia/Brisbane")));
QCOMPARE(tzDate.toMSecsSinceEpoch(), tzMsecs);
+ QCOMPARE(tzDate.timeZone(), aest);
+ QCOMPARE(tzDate, QDateTime(date, early, aest));
#endif
}