diff --git a/src/corelib/time/qtimezone.cpp b/src/corelib/time/qtimezone.cpp index b1ef9b172b..57500eee2c 100644 --- a/src/corelib/time/qtimezone.cpp +++ b/src/corelib/time/qtimezone.cpp @@ -974,6 +974,15 @@ QList QTimeZone::windowsIdToIanaIds(const QByteArray &windowsId, QLo return QTimeZonePrivate::windowsIdToIanaIds(windowsId, territory); } +/*! + \fn QTimeZone QTimeZone::fromStdTimeZonePtr(const std::chrono::time_zone *timeZone) + \since 6.4 + + Returns a QTimeZone object representing the same time zone as \a timeZone. + The IANA ID of \a timeZone must be one of the available system IDs, + otherwise an invalid time zone will be returned. +*/ + #ifndef QT_NO_DATASTREAM // Invalid, as an IANA ID: too long, starts with - and has other invalid characters in it static inline QString invalidId() { return QStringLiteral("-No Time Zone Specified!"); } diff --git a/src/corelib/time/qtimezone.h b/src/corelib/time/qtimezone.h index 6039749689..32a71f5a43 100644 --- a/src/corelib/time/qtimezone.h +++ b/src/corelib/time/qtimezone.h @@ -45,6 +45,8 @@ #include #include +#include + QT_REQUIRE_CONFIG(timezone); #if (defined(Q_OS_DARWIN) || defined(Q_QDOC)) && !defined(QT_NO_SYSTEMLOCALE) @@ -164,6 +166,17 @@ public: NSTimeZone *toNSTimeZone() const Q_DECL_NS_RETURNS_AUTORELEASED; #endif +#if __cpp_lib_chrono >= 201907L || defined(Q_QDOC) + QT_POST_CXX17_API_IN_EXPORTED_CLASS + static QTimeZone fromStdTimeZonePtr(const std::chrono::time_zone *timeZone) + { + if (!timeZone) + return QTimeZone(); + const std::string_view timeZoneName = timeZone->name(); + return QTimeZone(QByteArrayView(timeZoneName).toByteArray()); + } +#endif + private: QTimeZone(QTimeZonePrivate &dd); #ifndef QT_NO_DATASTREAM diff --git a/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp b/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp index 0a18958fb6..378c0d619d 100644 --- a/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp +++ b/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp @@ -77,6 +77,8 @@ private Q_SLOTS: void winTest(); void localeSpecificDisplayName_data(); void localeSpecificDisplayName(); + void stdCompatibility_data(); + void stdCompatibility(); private: void printTimeZone(const QTimeZone &tz); @@ -341,6 +343,11 @@ void tst_QTimeZone::systemZone() }; for (const auto &date : dates) QCOMPARE(date.startOfDay(Qt::LocalTime), date.startOfDay(zone)); + +#if __cpp_lib_chrono >= 201907L + const std::chrono::time_zone *currentTimeZone = std::chrono::current_zone(); + QCOMPARE(QByteArrayView(currentTimeZone->name()), QByteArrayView(zone.id())); +#endif } void tst_QTimeZone::dataStreamTest() @@ -1609,5 +1616,46 @@ void tst_QTimeZone::testEpochTranPrivate(const QTimeZonePrivate &tzp) } #endif // QT_BUILD_INTERNAL +#if __cpp_lib_chrono >= 201907L +Q_DECLARE_METATYPE(const std::chrono::time_zone *); +#endif + +void tst_QTimeZone::stdCompatibility_data() +{ +#if __cpp_lib_chrono >= 201907L + QTest::addColumn("timeZone"); + const std::chrono::tzdb &tzdb = std::chrono::get_tzdb(); + qDebug() << "Using tzdb version:" << QByteArrayView(tzdb.version); + + for (const std::chrono::time_zone &zone : tzdb.zones) + QTest::addRow(zone.name().data()) << &zone; +#else + QSKIP("This test requires C++20's ."); +#endif +} + +void tst_QTimeZone::stdCompatibility() +{ +#if __cpp_lib_chrono >= 201907L + QFETCH(const std::chrono::time_zone *, timeZone); + QByteArrayView zoneName = QByteArrayView(timeZone->name()); + QTimeZone tz = QTimeZone::fromStdTimeZonePtr(timeZone); + if (tz.isValid()) { + QCOMPARE(tz.id(), zoneName); + } else { + // QTBUG-102187: a few timezones reported by tzdb might not be + // recognized by QTimeZone. This happens for instance on Windows, where + // tzdb is using ICU, whose database does not match QTimeZone's. + const bool isKnownUnknown = + !zoneName.contains('/') + || zoneName == "Antarctica/Troll" + || zoneName.startsWith("SystemV/"); + QVERIFY(isKnownUnknown); + } +#else + QSKIP("This test requires C++20's ."); +#endif +} + QTEST_APPLESS_MAIN(tst_QTimeZone) #include "tst_qtimezone.moc"