summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2015-01-14 16:33:03 -0800
committerThiago Macieira <thiago.macieira@intel.com>2015-03-07 19:22:21 +0000
commita8c74ddcf78604c9038ba2a2bea81e445e4b3c58 (patch)
tree766754fbd27e7b18a72c54871f0b2699d2ee5e33 /tests
parent84b9d071630a63a493773f612eefe83c8e68390d (diff)
Fix race condition in QDateTime::timeZone() and other methods
When timezone support for QDateTime was added, we decided it was a good idea to delay creating the QTimeZone object and checking that the time is valid in that timezone (including for local time) until the user requested that information. Unfortunately, QExplicitlySharedDataPointer returns a non-const T* in operator->(), which meant we were accidentally modifying the d pointer's contents in const methods, which in turn means those const methods were not thread-safe when operating on the same object. This commit changes the d pointer to QSharedDataPointer, which is safer in this regard and pointed out where the issues with constness were located. Since we can't lazily calculate QTimeZone anymore, we need to do it whenever the date, time or offset changes. Task-number: QTBUG-43703 Change-Id: Ic5d393bfd36e48a193fcffff13b9686ef4ef1454 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp53
1 files changed, 53 insertions, 0 deletions
diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp
index c6806086d3..446e56e936 100644
--- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp
+++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp
@@ -142,6 +142,9 @@ private slots:
void isDaylightTime() const;
void daylightTransitions() const;
void timeZones() const;
+#if defined(Q_OS_UNIX)
+ void systemTimeZoneChange() const;
+#endif
void invalid() const;
@@ -2984,6 +2987,56 @@ void tst_QDateTime::timeZones() const
QCOMPARE(future.offsetFromUtc(), 28800);
}
+#if defined(Q_OS_UNIX)
+// Currently disabled on Windows as adjusting the timezone
+// requires additional privileges that aren't normally
+// enabled for a process. This can be achieved by calling
+// AdjustTokenPrivileges() and then SetTimeZoneInformation(),
+// which will require linking to a different library to access that API.
+static void setTimeZone(const QByteArray &tz)
+{
+ qputenv("TZ", tz);
+ ::tzset();
+
+// following left for future reference, see comment above
+// #if defined(Q_OS_WIN32)
+// ::_tzset();
+// #endif
+}
+
+void tst_QDateTime::systemTimeZoneChange() const
+{
+ struct ResetTZ {
+ QByteArray original;
+ ResetTZ() : original(qgetenv("TZ")) {}
+ ~ResetTZ() { setTimeZone(original); }
+ } scopedReset;
+
+ // Set the timezone to Brisbane time
+ setTimeZone(QByteArray("AEST-10:00"));
+
+ 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);
+ QDateTime tzDate = QDateTime(QDate(2012, 6, 1), QTime(2, 15, 30), QTimeZone("Australia/Brisbane"));
+ qint64 localMsecs = localDate.toMSecsSinceEpoch();
+ qint64 utcMsecs = utcDate.toMSecsSinceEpoch();
+ qint64 tzMsecs = tzDate.toMSecsSinceEpoch();
+
+ // check that Australia/Brisbane is known
+ QVERIFY(tzDate.timeZone().isValid());
+
+ // Change to Indian time
+ setTimeZone(QByteArray("IST-05:30"));
+
+ 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(utcDate.toMSecsSinceEpoch(), utcMsecs);
+ QCOMPARE(tzDate, QDateTime(QDate(2012, 6, 1), QTime(2, 15, 30), QTimeZone("Australia/Brisbane")));
+ QCOMPARE(tzDate.toMSecsSinceEpoch(), tzMsecs);
+}
+#endif
+
void tst_QDateTime::invalid() const
{
QDateTime invalidDate = QDateTime(QDate(0, 0, 0), QTime(-1, -1, -1));