diff options
Diffstat (limited to 'src/corelib/time/qtimezoneprivate_icu.cpp')
-rw-r--r-- | src/corelib/time/qtimezoneprivate_icu.cpp | 60 |
1 files changed, 38 insertions, 22 deletions
diff --git a/src/corelib/time/qtimezoneprivate_icu.cpp b/src/corelib/time/qtimezoneprivate_icu.cpp index c071e7d549..1a3baa70d0 100644 --- a/src/corelib/time/qtimezoneprivate_icu.cpp +++ b/src/corelib/time/qtimezoneprivate_icu.cpp @@ -153,7 +153,7 @@ static QTimeZonePrivate::Data ucalTimeZoneTransition(UCalendar *m_ucal, UTimeZoneTransitionType type, qint64 atMSecsSinceEpoch) { - QTimeZonePrivate::Data tran = QTimeZonePrivate::invalidData(); + QTimeZonePrivate::Data tran; // Clone the ucal so we don't change the shared object UErrorCode status = U_ZERO_ERROR; @@ -254,8 +254,8 @@ QIcuTimeZonePrivate::QIcuTimeZonePrivate() QIcuTimeZonePrivate::QIcuTimeZonePrivate(const QByteArray &ianaId) : m_ucal(nullptr) { - // Need to check validity here as ICu will create a GMT tz if name is invalid - if (availableTimeZoneIds().contains(ianaId)) + // ICU misleadingly maps invalid IDs to GMT. + if (isTimeZoneIdAvailable(ianaId)) init(ianaId); } @@ -301,28 +301,25 @@ QString QIcuTimeZonePrivate::displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType, const QLocale &locale) const { - // Return standard offset format name as ICU C api doesn't support it yet + // Base class has handled OffsetName if we came via the other overload. if (nameType == QTimeZone::OffsetName) { - const Data nowData = data(QDateTime::currentMSecsSinceEpoch()); - // We can't use transitions reliably to find out right dst offset - // Instead use dst offset api to try get it if needed + int offset = standardTimeOffset(QDateTime::currentMSecsSinceEpoch()); + // We can't use transitions reliably to find out right DST offset. + // Instead use DST offset API to try to get it, when needed: if (timeType == QTimeZone::DaylightTime) - return isoOffsetFormat(nowData.standardTimeOffset + ucalDaylightOffset(m_id)); - else - return isoOffsetFormat(nowData.standardTimeOffset); + offset += ucalDaylightOffset(m_id); + // This is only valid for times since the most recent standard offset + // change; for earlier times, caller must use the other overload. + + // Use our own formating for offset names (ICU C API doesn't support it + // and we may as well be self-consistent anyway). + return isoOffsetFormat(offset); } + // Technically this may be suspect, if locale isn't QLocale(), since that's + // what we used when constructing m_ucal; does ICU cope with inconsistency ? return ucalTimeZoneDisplayName(m_ucal, timeType, nameType, locale.name()); } -QString QIcuTimeZonePrivate::abbreviation(qint64 atMSecsSinceEpoch) const -{ - // TODO No ICU API, use short name instead - if (isDaylightTime(atMSecsSinceEpoch)) - return displayName(QTimeZone::DaylightTime, QTimeZone::ShortName, QLocale()); - else - return displayName(QTimeZone::StandardTime, QTimeZone::ShortName, QLocale()); -} - int QIcuTimeZonePrivate::offsetFromUtc(qint64 atMSecsSinceEpoch) const { int stdOffset = 0; @@ -387,7 +384,7 @@ bool QIcuTimeZonePrivate::isDaylightTime(qint64 atMSecsSinceEpoch) const QTimeZonePrivate::Data QIcuTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const { // Available in ICU C++ api, and draft C api in v50 - QTimeZonePrivate::Data data = invalidData(); + QTimeZonePrivate::Data data; #if U_ICU_VERSION_MAJOR_NUM >= 50 data = ucalTimeZoneTransition(m_ucal, UCAL_TZ_TRANSITION_PREVIOUS_INCLUSIVE, forMSecsSinceEpoch); @@ -420,7 +417,7 @@ QTimeZonePrivate::Data QIcuTimeZonePrivate::nextTransition(qint64 afterMSecsSinc return ucalTimeZoneTransition(m_ucal, UCAL_TZ_TRANSITION_NEXT, afterMSecsSinceEpoch); #else Q_UNUSED(afterMSecsSinceEpoch); - return invalidData(); + return {}; #endif } @@ -431,7 +428,7 @@ QTimeZonePrivate::Data QIcuTimeZonePrivate::previousTransition(qint64 beforeMSec return ucalTimeZoneTransition(m_ucal, UCAL_TZ_TRANSITION_PREVIOUS, beforeMSecsSinceEpoch); #else Q_UNUSED(beforeMSecsSinceEpoch); - return invalidData(); + return {}; #endif } @@ -442,6 +439,25 @@ QByteArray QIcuTimeZonePrivate::systemTimeZoneId() const return ucalDefaultTimeZoneId(); } +bool QIcuTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray &ianaId) const +{ + const QString ianaStr = QString::fromUtf8(ianaId); + const UChar *const name = reinterpret_cast<const UChar *>(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; +} + QList<QByteArray> QIcuTimeZonePrivate::availableTimeZoneIds() const { UErrorCode status = U_ZERO_ERROR; |