diff options
-rw-r--r-- | src/corelib/global/qglobal.cpp | 28 | ||||
-rw-r--r-- | src/corelib/global/qglobal_p.h | 10 | ||||
-rw-r--r-- | src/corelib/tools/qdatetime.cpp | 22 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp | 40 |
4 files changed, 51 insertions, 49 deletions
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 6c608dab74..0fba9b309b 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -3252,6 +3252,34 @@ void *qMemSet(void *dest, int c, size_t n) { return memset(dest, c, n); } // add thread-safety for the Qt wrappers. static QBasicMutex environmentMutex; +/* + Wraps tzset(), which accesses the environment, so should only be called while + we hold the lock on the environment mutex. +*/ +void qTzSet() +{ + QMutexLocker locker(&environmentMutex); +#if defined(Q_OS_WIN) + _tzset(); +#else + tzset(); +#endif // Q_OS_WIN +} + +/* + Wrap mktime(), which is specified to behave as if it called tzset(), hence + shares its implicit environment-dependence. +*/ +time_t qMkTime(struct tm *when) +{ + QMutexLocker locker(&environmentMutex); + return mktime(when); +} + +// Also specified to behave as if they call tzset(): +// localtime() -- but not localtime_r(), which we use when threaded +// strftime() -- not used (except in tests) + /*! \relates <QtGlobal> \threadsafe diff --git a/src/corelib/global/qglobal_p.h b/src/corelib/global/qglobal_p.h index 0f092e9006..d52f6268e4 100644 --- a/src/corelib/global/qglobal_p.h +++ b/src/corelib/global/qglobal_p.h @@ -61,6 +61,16 @@ #endif #if defined(__cplusplus) +#include <time.h> + +QT_BEGIN_NAMESPACE + +// These behave as if they consult the environment, so need to share its locking: +Q_CORE_EXPORT void qTzSet(); +Q_CORE_EXPORT time_t qMkTime(struct tm *when); + +QT_END_NAMESPACE + #if !QT_HAS_BUILTIN(__builtin_available) #include <initializer_list> #include <QtCore/qoperatingsystemversion.h> diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 816bd974eb..600bd1e0e5 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -2171,16 +2171,6 @@ int QTime::elapsed() const typedef QDateTimePrivate::QDateTimeShortData ShortData; typedef QDateTimePrivate::QDateTimeData QDateTimeData; -// Calls the platform variant of tzset -static void qt_tzset() -{ -#if defined(Q_OS_WIN) - _tzset(); -#else - tzset(); -#endif // Q_OS_WIN -} - // Returns the platform variant of timezone, i.e. the standard time offset // The timezone external variable is documented as always holding the // Standard Time offset as seconds west of Greenwich, i.e. UTC+01:00 is -3600 @@ -2278,7 +2268,7 @@ static qint64 qt_mktime(QDate *date, QTime *time, QDateTimePrivate::DaylightStat #if defined(Q_OS_WIN) int hh = local.tm_hour; #endif // Q_OS_WIN - time_t secsSinceEpoch = mktime(&local); + time_t secsSinceEpoch = qMkTime(&local); if (secsSinceEpoch != time_t(-1)) { *date = QDate(local.tm_year + 1900, local.tm_mon + 1, local.tm_mday); *time = QTime(local.tm_hour, local.tm_min, local.tm_sec, msec); @@ -2337,10 +2327,10 @@ static bool qt_localtime(qint64 msecsSinceEpoch, QDate *localDate, QTime *localT tm local; bool valid = false; - // localtime() is required to work as if tzset() was called before it. - // localtime_r() does not have this requirement, so make an explicit call. + // localtime() is specified to work as if it called tzset(). + // localtime_r() does not have this constraint, so make an explicit call. // The explicit call should also request the timezone info be re-parsed. - qt_tzset(); + qTzSet(); #if QT_CONFIG(thread) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) // Use the reentrant version of localtime() where available // as is thread-safe and doesn't use a shared static data area @@ -2422,7 +2412,7 @@ static bool epochMSecsToLocalTime(qint64 msecs, QDate *localDate, QTime *localTi if (msecs < 0) { // Docs state any LocalTime before 1970-01-01 will *not* have any Daylight Time applied // Instead just use the standard offset from UTC to convert to UTC time - qt_tzset(); + qTzSet(); msecsToTime(msecs - qt_timezone() * 1000, localDate, localTime); if (daylightStatus) *daylightStatus = QDateTimePrivate::StandardTime; @@ -2485,7 +2475,7 @@ static qint64 localMSecsToEpochMSecs(qint64 localMsecs, } } else { // If we don't call mktime then need to call tzset to get offset - qt_tzset(); + qTzSet(); } // Time is clearly before 1970-01-01 so just use standard offset to convert qint64 utcMsecs = localMsecs + qt_timezone() * 1000; diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp index 943805e228..56792f38fb 100644 --- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp @@ -37,9 +37,6 @@ #ifdef Q_OS_WIN # include <qt_windows.h> -# if defined(Q_OS_WINRT) -# define tzset() -# endif #endif class tst_QDateTime : public QObject @@ -145,9 +142,7 @@ private slots: void isDaylightTime() const; void daylightTransitions() const; void timeZones() const; -#if defined(Q_OS_UNIX) void systemTimeZoneChange() const; -#endif void invalid() const; @@ -174,7 +169,7 @@ private: void reset(const QByteArray &zone) { qputenv("TZ", zone.constData()); - tzset(); + qTzSet(); } ~TimeZoneRollback() { @@ -182,7 +177,7 @@ private: qunsetenv("TZ"); else qputenv("TZ", prior.constData()); - tzset(); + qTzSet(); } }; }; @@ -3412,33 +3407,10 @@ 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")); + TimeZoneRollback useZone(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); @@ -3451,16 +3423,18 @@ void tst_QDateTime::systemTimeZoneChange() const QVERIFY(tzDate.timeZone().isValid()); // Change to Indian time - setTimeZone(QByteArray("IST-05:30")); + useZone.reset(QByteArray("IST-05:30")); QCOMPARE(localDate, QDateTime(QDate(2012, 6, 1), QTime(2, 15, 30), Qt::LocalTime)); +#ifdef Q_OS_WINRT + QEXPECT_FAIL("", "WinRT gets this wrong, QTBUG-71185", Continue); +#endif 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 { |