diff --git a/src/corelib/time/qtimezone.cpp b/src/corelib/time/qtimezone.cpp index 9f42d3e36c9..86103a8e5b8 100644 --- a/src/corelib/time/qtimezone.cpp +++ b/src/corelib/time/qtimezone.cpp @@ -1512,6 +1512,7 @@ static QList set_union(const QList &l1, const QList QTimeZone::availableTimeZoneIds() { + // Backends MUST implement availableTimeZoneIds(). return set_union(QUtcTimeZonePrivate().availableTimeZoneIds(), global_tz->backend->availableTimeZoneIds()); } diff --git a/src/corelib/time/qtimezoneprivate.cpp b/src/corelib/time/qtimezoneprivate.cpp index bf7496f26c6..32a4055f85a 100644 --- a/src/corelib/time/qtimezoneprivate.cpp +++ b/src/corelib/time/qtimezoneprivate.cpp @@ -601,7 +601,7 @@ QByteArray QTimeZonePrivate::systemTimeZoneId() const return QByteArray(); } -bool QTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray& ianaId) const +bool QTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray &ianaId) const { // Fall-back implementation, can be made faster in subclasses. // Backends that don't cache the available list SHOULD override this. @@ -609,11 +609,6 @@ bool QTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray& ianaId) const return std::binary_search(tzIds.begin(), tzIds.end(), ianaId); } -QList QTimeZonePrivate::availableTimeZoneIds() const -{ - return QList(); -} - static QList selectAvailable(QList &&desired, const QList &all) { diff --git a/src/corelib/time/qtimezoneprivate_chrono.cpp b/src/corelib/time/qtimezoneprivate_chrono.cpp index e317ab522ef..2e0b0ffb9e5 100644 --- a/src/corelib/time/qtimezoneprivate_chrono.cpp +++ b/src/corelib/time/qtimezoneprivate_chrono.cpp @@ -4,6 +4,7 @@ #include "qtimezoneprivate_p.h" #include +#include QT_BEGIN_NAMESPACE @@ -34,6 +35,41 @@ static const std::chrono::time_zone *idToZone(std::string_view id) EXCEPTION_CHECKED(return get_tzdb().locate_zone(id), return nullptr); } +static const std::vector getAllZoneIds(std::optional offset = std::nullopt) +{ + const tzdb &db = get_tzdb(); // May throw std::runtime_error. + std::vector raw, links, all; + auto now = system_clock::now(); + for (const time_zone &zone : db.zones) { + if (offset) { + const sys_info info = zone.get_info(now); + if (info.offset.count() != *offset) + continue; + } + raw.push_back(zone.name()); + } + for (const time_zone_link &link : db.links) { + if (offset) { + const std::string_view target = link.target(); + const time_zone *zone = db.locate_zone(target); + const sys_info info = zone->get_info(now); + if (info.offset.count() != *offset) + continue; + } + links.push_back(link.name()); + } + // Each is sorted, so we can unite them; and the result shall be sorted. + all.reserve(raw.size() + links.size()); + std::set_union(raw.begin(), raw.end(), links.begin(), links.end(), std::back_inserter(all)); + return all; +} + +static const std::optional> +allZoneIds(std::optional offset = std::nullopt) +{ + EXCEPTION_CHECKED(return getAllZoneIds(offset), return std::nullopt); +} + static QChronoTimeZonePrivate::Data fromSysInfo(std::chrono::sys_info info, qint64 atMSecsSinceEpoch) { @@ -76,6 +112,35 @@ QByteArray QChronoTimeZonePrivate::systemTimeZoneId() const return {}; } +bool QChronoTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray &ianaId) const +{ + return idToZone(std::string_view(ianaId.data(), ianaId.size())) != nullptr; +} + +QList QChronoTimeZonePrivate::availableTimeZoneIds() const +{ + QList result; + if (auto ids = allZoneIds()) { + result.reserve(ids->size()); + for (std::string_view id : *ids) + result << QByteArray{id.data(), qsizetype(id.size())}; + // Order preserved; they were already sorted and unique. + } + return result; +} + +QList QChronoTimeZonePrivate::availableTimeZoneIds(int utcOffset) const +{ + QList result; + if (auto ids = allZoneIds(utcOffset)) { + result.reserve(ids->size()); + for (std::string_view id : *ids) + result << QByteArray{id.data(), qsizetype(id.size())}; + // Order preserved; they were already sorted and unique. + } + return result; +} + QString QChronoTimeZonePrivate::abbreviation(qint64 atMSecsSinceEpoch) const { if (auto info = infoAtEpochMillis(m_timeZone, atMSecsSinceEpoch)) diff --git a/src/corelib/time/qtimezoneprivate_p.h b/src/corelib/time/qtimezoneprivate_p.h index 0482b91fca8..1e0c7f28e2e 100644 --- a/src/corelib/time/qtimezoneprivate_p.h +++ b/src/corelib/time/qtimezoneprivate_p.h @@ -120,7 +120,7 @@ public: virtual QByteArray systemTimeZoneId() const; virtual bool isTimeZoneIdAvailable(const QByteArray &ianaId) const; - virtual QList availableTimeZoneIds() const; + virtual QList availableTimeZoneIds() const = 0; virtual QList availableTimeZoneIds(QLocale::Territory territory) const; virtual QList availableTimeZoneIds(int utcOffset) const; @@ -256,6 +256,10 @@ public: int standardTimeOffset(qint64 atMSecsSinceEpoch) const override; int daylightTimeOffset(qint64 atMSecsSinceEpoch) const override; + bool isTimeZoneIdAvailable(const QByteArray &ianaId) const override; + QList availableTimeZoneIds() const override; + QList availableTimeZoneIds(int utcOffset) const override; + bool hasDaylightTime() const override; bool isDaylightTime(qint64 atMSecsSinceEpoch) const override;