diff options
-rw-r--r-- | src/corelib/tools/qdatetime.cpp | 106 | ||||
-rw-r--r-- | src/corelib/tools/qdatetime.h | 1 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp | 33 |
3 files changed, 139 insertions, 1 deletions
diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 008e72af1c..db0f7d3a74 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -174,6 +174,7 @@ static void rfcDateImpl(const QString &s, QDate *dd = 0, QTime *dt = 0, int *utf #endif static QDateTimePrivate::Spec utcToLocal(QDate &date, QTime &time); static void utcToOffset(QDate *date, QTime *time, qint32 offset); +static QDate adjustDate(QDate date); // Return offset in [+-]HH:MM format // Qt::ISODate puts : between the hours and minutes, but Qt:TextDate does not @@ -225,6 +226,68 @@ static int fromOffsetString(const QString &offsetString, bool *valid) return ((hour * 60) + minute) * 60; } +#if !defined(Q_OS_WINCE) +// Calls the platform variant of mktime for the given date and time, +// and updates the date, time, spec and abbreviation with the returned values +// If the date falls outside the 1970 to 2037 range supported by mktime / time_t +// then null date/time will be returned, you should call adjustDate() first if +// you need a guaranteed result. +static time_t qt_mktime(QDate *date, QTime *time, QDateTimePrivate::Spec *spec, + QString *abbreviation, bool *ok) +{ + if (ok) + *ok = false; + int yy, mm, dd; + date->getDate(&yy, &mm, &dd); + tm local; + local.tm_sec = time->second(); + local.tm_min = time->minute(); + local.tm_hour = time->hour(); + local.tm_mday = dd; + local.tm_mon = mm - 1; + local.tm_year = yy - 1900; + local.tm_wday = 0; + local.tm_yday = 0; + local.tm_isdst = -1; +#if defined(Q_OS_WIN) + _tzset(); +#else + tzset(); +#endif // Q_OS_WIN + const time_t secsSinceEpoch = mktime(&local); + if (secsSinceEpoch != (uint)-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, time->msec()); + if (local.tm_isdst == 1) { + if (spec) + *spec = QDateTimePrivate::LocalDST; + if (abbreviation) + *abbreviation = QString::fromLocal8Bit(tzname[1]); + } else if (local.tm_isdst == 0) { + if (spec) + *spec = QDateTimePrivate::LocalStandard; + if (abbreviation) + *abbreviation = QString::fromLocal8Bit(tzname[0]); + } else { + if (spec) + *spec = QDateTimePrivate::LocalUnknown; + if (abbreviation) + *abbreviation = QString::fromLocal8Bit(tzname[0]); + } + if (ok) + *ok = true; + } else { + *date = QDate(); + *time = QTime(); + if (spec) + *spec = QDateTimePrivate::LocalUnknown; + if (abbreviation) + *abbreviation = QString(); + } + return secsSinceEpoch; +} +#endif // !Q_OS_WINCE + /***************************************************************************** QDate member functions *****************************************************************************/ @@ -2457,6 +2520,49 @@ int QDateTime::offsetFromUtc() const } /*! + \since 5.2 + + Returns the Time Zone Abbreviation for the datetime. + + If the timeSpec() is Qt::UTC this will be "UTC". + + If the timeSpec() is Qt::OffsetFromUTC this will be in the format + "UTC[+-]00:00". + + If the timeSpec() is Qt::LocalTime then the host system is queried for the + correct abbreviation. + + Note that abbreviations may or may not be localized. + + Note too that the abbreviation is not guaranteed to be a unique value, + i.e. different time zones may have the same abbreviation. + + \sa timeSpec() +*/ + +QString QDateTime::timeZoneAbbreviation() const +{ + switch (d->spec) { + case QDateTimePrivate::UTC: + return QStringLiteral("UTC"); + case QDateTimePrivate::OffsetFromUTC: + return QLatin1String("UTC") + toOffsetString(Qt::ISODate, d->m_offsetFromUtc); + default: { // Any Qt::LocalTime +#if defined(Q_OS_WINCE) + // TODO Stub to enable compilation on WinCE + return QString(); +#else + QDate dt = adjustDate(d->date); + QTime tm = d->time; + QString abbrev; + qt_mktime(&dt, &tm, 0, &abbrev, 0); + return abbrev; +#endif // !Q_OS_WINCE + } + } +} + +/*! Sets the date part of this datetime to \a date. If no time is set, it is set to midnight. diff --git a/src/corelib/tools/qdatetime.h b/src/corelib/tools/qdatetime.h index 3c8b1a9920..25f5b74eb2 100644 --- a/src/corelib/tools/qdatetime.h +++ b/src/corelib/tools/qdatetime.h @@ -219,6 +219,7 @@ public: QTime time() const; Qt::TimeSpec timeSpec() const; int offsetFromUtc() const; + QString timeZoneAbbreviation() const; qint64 toMSecsSinceEpoch() const; // ### Qt 6: use quint64 instead of uint diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp index 5576d3d8a4..917e931988 100644 --- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp @@ -133,6 +133,8 @@ private slots: void setOffsetFromUtc(); void toOffsetFromUtc(); + void timeZoneAbbreviation(); + void getDate(); void fewDigitsInYear() const; @@ -592,7 +594,7 @@ void tst_QDateTime::fromMSecsSinceEpoch() QCOMPARE(dtUtc.time(), utc.time()); QCOMPARE(dtOffset, utc); - QCOMPARE(dtOffset.utcOffset(), 60*60); + QCOMPARE(dtOffset.offsetFromUtc(), 60*60); QCOMPARE(dtOffset.time(), utc.time().addMSecs(60*60*1000)); if (europeanTimeZone) { @@ -2221,6 +2223,35 @@ void tst_QDateTime::toOffsetFromUtc() QCOMPARE(dt2.time(), QTime(0, 0, 0)); } +void tst_QDateTime::timeZoneAbbreviation() +{ + QDateTime dt1(QDate(2013, 1, 1), QTime(1, 0, 0), Qt::OffsetFromUTC, 60 * 60); + QCOMPARE(dt1.timeZoneAbbreviation(), QString("UTC+01:00")); + QDateTime dt2(QDate(2013, 1, 1), QTime(1, 0, 0), Qt::OffsetFromUTC, -60 * 60); + QCOMPARE(dt2.timeZoneAbbreviation(), QString("UTC-01:00")); + + QDateTime dt3(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::UTC); + QCOMPARE(dt3.timeZoneAbbreviation(), QString("UTC")); + + // LocalTime should vary + if (europeanTimeZone) { + // Time definitely in Standard Time + QDateTime dt4(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::LocalTime); +#ifdef Q_OS_WIN + QEXPECT_FAIL("", "Windows only returns long name (QTBUG-32759)", Continue); +#endif // Q_OS_WIN + QCOMPARE(dt4.timeZoneAbbreviation(), QString("CET")); + // Time definitely in Daylight Time + QDateTime dt5(QDate(2013, 6, 1), QTime(0, 0, 0), Qt::LocalTime); +#ifdef Q_OS_WIN + QEXPECT_FAIL("", "Windows only returns long name (QTBUG-32759)", Continue); +#endif // Q_OS_WIN + QCOMPARE(dt5.timeZoneAbbreviation(), QString("CEST")); + } else { + QSKIP("You must test using Central European (CET/CEST) time zone, e.g. TZ=Europe/Oslo"); + } +} + void tst_QDateTime::getDate() { { |