diff --git a/src/corelib/time/qtimezonelocale.cpp b/src/corelib/time/qtimezonelocale.cpp index c986b8ac280..e793a59f933 100644 --- a/src/corelib/time/qtimezonelocale.cpp +++ b/src/corelib/time/qtimezonelocale.cpp @@ -72,6 +72,24 @@ QString ucalTimeZoneDisplayName(UCalendar *ucal, return result; } +bool ucalKnownTimeZoneId(const QString &ianaStr) +{ + const UChar *const name = reinterpret_cast(ianaStr.constData()); + // We are not interested in the value, but we have to pass something. + // No known IANA zone name is (up to 2023) longer than 30 characters. + constexpr size_t size = 64; + UChar buffer[size]; + + // TODO: convert to ucal_getIanaTimeZoneID(), new draft in ICU 74, once we + // can rely on its availability, assuming it works the same once not draft. + UErrorCode status = U_ZERO_ERROR; + UBool isSys = false; + // Returns the length of the IANA zone name (but we don't care): + ucal_getCanonicalTimeZoneID(name, ianaStr.size(), buffer, size, &isSys, &status); + // We're only interested if the result is a "system" (i.e. IANA) ID: + return isSys; +} + } // QtTimeZoneLocale // Used by TZ backends when ICU is available: @@ -88,6 +106,11 @@ QString QTimeZonePrivate::localeName(qint64 atMSecsSinceEpoch, int offsetFromUtc return isoOffsetFormat(offsetFromUtc); const QString id = QString::fromUtf8(m_id); + // Need to check id is known to ICU, since ucal_open() will return a + // misleading "valid" GMT ucal when it doesn't recognise id. + if (!QtTimeZoneLocale::ucalKnownTimeZoneId(id)) + return QString(); + const QByteArray loc = locale.name().toUtf8(); UErrorCode status = U_ZERO_ERROR; UCalendar *ucal = ucal_open(reinterpret_cast(id.data()), id.size(), diff --git a/src/corelib/time/qtimezonelocale_p.h b/src/corelib/time/qtimezonelocale_p.h index 076e29d268d..dc5de597253 100644 --- a/src/corelib/time/qtimezonelocale_p.h +++ b/src/corelib/time/qtimezonelocale_p.h @@ -33,6 +33,8 @@ namespace QtTimeZoneLocale { QString ucalTimeZoneDisplayName(UCalendar *ucal, QTimeZone::TimeType timeType, QTimeZone::NameType nameType, const QByteArray &localeCode); + +bool ucalKnownTimeZoneId(const QString &id); #else // Define data types for QTZL_data_p.h diff --git a/src/corelib/time/qtimezoneprivate_icu.cpp b/src/corelib/time/qtimezoneprivate_icu.cpp index c7039e157ca..ef1c83b9d05 100644 --- a/src/corelib/time/qtimezoneprivate_icu.cpp +++ b/src/corelib/time/qtimezoneprivate_icu.cpp @@ -387,21 +387,7 @@ QByteArray QIcuTimeZonePrivate::systemTimeZoneId() const bool QIcuTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray &ianaId) const { - const QString ianaStr = QString::fromUtf8(ianaId); - const UChar *const name = reinterpret_cast(ianaStr.constData()); - // We are not interested in the value, but we have to pass something. - // No known IANA zone name is (up to 2023) longer than 30 characters. - constexpr size_t size = 64; - UChar buffer[size]; - - // TODO: convert to ucal_getIanaTimeZoneID(), new draft in ICU 74, once we - // can rely on its availability, assuming it works the same once not draft. - UErrorCode status = U_ZERO_ERROR; - UBool isSys = false; - // Returns the length of the IANA zone name (but we don't care): - ucal_getCanonicalTimeZoneID(name, ianaStr.size(), buffer, size, &isSys, &status); - // We're only interested if the result is a "system" (i.e. IANA) ID: - return isSys; + return QtTimeZoneLocale::ucalKnownTimeZoneId(QString::fromUtf8(ianaId)); } QList QIcuTimeZonePrivate::availableTimeZoneIds() const