Add support for available ID queries to QTZ chrono backend

We seem to have missed this when adding the backend. Enforce
overriding availableTimeZoneIds(), by = 0'ing it, so that we don't
make that mistake for any future backends. Document this obligation in
QTZ's availableTimeZoneIds(). Fix coding style of isTZIAvailable()'s
signature as a drive-by.

Change-Id: Ibb736fb400644bd25681707b9255415760543ff9
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Edward Welbourne 2024-10-30 12:50:40 +01:00
parent c9d1f18d0b
commit bde08d7343
4 changed files with 72 additions and 7 deletions

View File

@ -1512,6 +1512,7 @@ static QList<QByteArray> set_union(const QList<QByteArray> &l1, const QList<QByt
QList<QByteArray> QTimeZone::availableTimeZoneIds()
{
// Backends MUST implement availableTimeZoneIds().
return set_union(QUtcTimeZonePrivate().availableTimeZoneIds(),
global_tz->backend->availableTimeZoneIds());
}

View File

@ -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<QByteArray> QTimeZonePrivate::availableTimeZoneIds() const
{
return QList<QByteArray>();
}
static QList<QByteArray> selectAvailable(QList<QByteArrayView> &&desired,
const QList<QByteArray> &all)
{

View File

@ -4,6 +4,7 @@
#include "qtimezoneprivate_p.h"
#include <chrono>
#include <optional>
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<std::string_view> getAllZoneIds(std::optional<int> offset = std::nullopt)
{
const tzdb &db = get_tzdb(); // May throw std::runtime_error.
std::vector<std::string_view> 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<std::vector<std::string_view>>
allZoneIds(std::optional<int> 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<QByteArray> QChronoTimeZonePrivate::availableTimeZoneIds() const
{
QList<QByteArray> 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<QByteArray> QChronoTimeZonePrivate::availableTimeZoneIds(int utcOffset) const
{
QList<QByteArray> 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))

View File

@ -120,7 +120,7 @@ public:
virtual QByteArray systemTimeZoneId() const;
virtual bool isTimeZoneIdAvailable(const QByteArray &ianaId) const;
virtual QList<QByteArray> availableTimeZoneIds() const;
virtual QList<QByteArray> availableTimeZoneIds() const = 0;
virtual QList<QByteArray> availableTimeZoneIds(QLocale::Territory territory) const;
virtual QList<QByteArray> 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<QByteArray> availableTimeZoneIds() const override;
QList<QByteArray> availableTimeZoneIds(int utcOffset) const override;
bool hasDaylightTime() const override;
bool isDaylightTime(qint64 atMSecsSinceEpoch) const override;