Process IANA ID lists joined by spaces correctly

The CLDR data from which they're obtained may contain a space-joined
sequence of timezone IDs, rather than a single ID. (This applies
principally to the mapping from MS-specific names to IANA IDs, but in
principle may also apply to the other data obtained from same-shaped
XML.) Note this on the methods of internal types and actually take it
into account when using this data to match IDs.

See CldrAccess.readWindowsTimeZones() in util/locale_database/cldr.py
for the form of the CLDR data from which these are extracted; the type
attributes of mapZone elements in the XML are the source of the
space-joined lists of IANA IDs.

Change-Id: I3f940e4c352d8312ff735f972c9f8f3961572884
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Edward Welbourne 2021-01-13 13:58:57 +01:00
parent 72dd23cf53
commit e5034cb453
2 changed files with 43 additions and 13 deletions

View File

@ -648,8 +648,12 @@ QByteArray QTimeZonePrivate::ianaIdToWindowsId(const QByteArray &id)
QByteArray QTimeZonePrivate::windowsIdToDefaultIanaId(const QByteArray &windowsId)
{
for (const QWindowsData &data : windowsDataTable) {
if (data.windowsId() == windowsId)
return data.ianaId().toByteArray();
if (data.windowsId() == windowsId) {
QByteArrayView id = data.ianaId();
if (qsizetype cut = id.indexOf(' '); cut >= 0)
id = id.first(cut);
return id.toByteArray();
}
}
return QByteArray();
}
@ -702,6 +706,17 @@ template<> QTimeZonePrivate *QSharedDataPointer<QTimeZonePrivate>::clone()
return d->clone();
}
static bool isEntryInIanaList(QByteArrayView id, QByteArrayView ianaIds)
{
qsizetype cut;
while ((cut = ianaIds.indexOf(' ')) >= 0) {
if (id == ianaIds.first(cut))
return true;
ianaIds = ianaIds.sliced(cut);
}
return id == ianaIds;
}
/*
UTC Offset implementation, used when QT_NO_SYSTEMLOCALE set and ICU is not being used,
or for QDateTimes with a Qt:Spec of Qt::OffsetFromUtc.
@ -719,7 +734,7 @@ QUtcTimeZonePrivate::QUtcTimeZonePrivate(const QByteArray &id)
{
// Look for the name in the UTC list, if found set the values
for (const QUtcData &data : utcDataTable) {
if (data.id() == id) {
if (isEntryInIanaList(id, data.id())) {
QString name = QString::fromUtf8(id);
init(id, data.offsetFromUtc, name, name, QLocale::AnyTerritory, name);
break;
@ -869,7 +884,7 @@ bool QUtcTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray &ianaId) const
{
// Only the zone IDs supplied by CLDR and recognized by constructor.
for (const QUtcData &data : utcDataTable) {
if (data.id() == ianaId)
if (isEntryInIanaList(ianaId, data.id()))
return true;
}
// But see offsetFromUtcString(), which lets us accept some "unavailable" IDs.
@ -881,8 +896,15 @@ QList<QByteArray> QUtcTimeZonePrivate::availableTimeZoneIds() const
// Only the zone IDs supplied by CLDR and recognized by constructor.
QList<QByteArray> result;
result.reserve(std::size(utcDataTable));
for (const QUtcData &data : utcDataTable)
result << data.id().toByteArray();
for (const QUtcData &data : utcDataTable) {
QByteArrayView id = data.id();
qsizetype cut;
while ((cut = id.indexOf(' ')) >= 0) {
result << id.first(cut).toByteArray();
id = id.sliced(cut);
}
result << id.toByteArray();
}
// Not guaranteed to be sorted, so sort:
std::sort(result.begin(), result.end());
// ### assuming no duplicates
@ -903,8 +925,15 @@ QList<QByteArray> QUtcTimeZonePrivate::availableTimeZoneIds(qint32 offsetSeconds
// and UTC-00:00 all have the same offset.)
QList<QByteArray> result;
for (const QUtcData &data : utcDataTable) {
if (data.offsetFromUtc == offsetSeconds)
result << data.id().toByteArray();
if (data.offsetFromUtc == offsetSeconds) {
QByteArrayView id = data.id();
qsizetype cut;
while ((cut = id.indexOf(' ')) >= 0) {
result << id.first(cut).toByteArray();
id = id.sliced(cut);
}
result << id.toByteArray();
}
}
// Not guaranteed to be sorted, so sort:
std::sort(result.begin(), result.end());

View File

@ -44,7 +44,7 @@ struct QZoneData
quint16 windowsIdKey; // Windows ID Key
quint16 territory; // Territory of IANA ID's, AnyTerritory means No Territory
quint16 ianaIdIndex; // All IANA ID's for the Windows ID and Country, space separated
inline QLatin1StringView id() const;
inline QLatin1StringView id() const; // Space-joined list of IANA IDs
inline auto ids() const { return id().tokenize(u' '); }
};
@ -52,17 +52,17 @@ struct QWindowsData
{
quint16 windowsIdKey; // Windows ID Key
quint16 windowsIdIndex; // Windows ID Literal
quint16 ianaIdIndex; // Default IANA ID for the Windows ID
quint16 ianaIdIndex; // IANA IDs for the Windows ID
qint32 offsetFromUtc; // Standard Time Offset from UTC, used for quick look-ups
inline QByteArrayView windowsId() const;
inline QByteArrayView ianaId() const;
inline QByteArrayView ianaId() const; // Space-joined list of IANA IDs
};
struct QUtcData
{
quint16 ianaIdIndex; // IANA ID
quint16 ianaIdIndex; // IANA IDs
qint32 offsetFromUtc; // Offset form UTC is seconds
inline QByteArrayView id() const;
inline QByteArrayView id() const; // Space-joined list of IANA IDs
};
/*
@ -1234,6 +1234,7 @@ static constexpr char ianaIdData[] = {
// GENERATED PART ENDS HERE
inline QByteArrayView QWindowsData::windowsId() const { return windowsIdData + windowsIdIndex; }
// Each of the following returns a space-joined sequence of IANA IDs:
inline QByteArrayView QWindowsData::ianaId() const { return ianaIdData + ianaIdIndex; }
inline QByteArrayView QUtcData::id() const { return ianaIdData + ianaIdIndex; }
inline QLatin1StringView QZoneData::id() const