diff options
Diffstat (limited to 'src/corelib/time/qtimezoneprivate_tz.cpp')
-rw-r--r-- | src/corelib/time/qtimezoneprivate_tz.cpp | 160 |
1 files changed, 76 insertions, 84 deletions
diff --git a/src/corelib/time/qtimezoneprivate_tz.cpp b/src/corelib/time/qtimezoneprivate_tz.cpp index f6156fe93e..45a6867524 100644 --- a/src/corelib/time/qtimezoneprivate_tz.cpp +++ b/src/corelib/time/qtimezoneprivate_tz.cpp @@ -33,10 +33,6 @@ QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; -#if QT_CONFIG(icu) -Q_CONSTINIT static QBasicMutex s_icu_mutex; -#endif - /* Private @@ -771,9 +767,6 @@ QTzTimeZonePrivate::~QTzTimeZonePrivate() QTzTimeZonePrivate *QTzTimeZonePrivate::clone() const { -#if QT_CONFIG(icu) - const auto lock = qt_scoped_lock(s_icu_mutex); -#endif return new QTzTimeZonePrivate(*this); } @@ -1007,15 +1000,7 @@ QTzTimeZonePrivate::QTzTimeZonePrivate(const QByteArray &ianaId) if (m_id.isEmpty()) { // This can only happen for the system zone, when we've read the // contents of /etc/localtime because it wasn't a symlink. -#if QT_CONFIG(icu) - // Use ICU's system zone, if only to avoid using the abbreviation as ID - // (ICU might mis-recognize it) in displayName(). - m_icu = new QIcuTimeZonePrivate(); - // Use its ID, as an alternate source of data: - m_id = m_icu->id(); - if (!m_id.isEmpty()) - return; -#endif + // TODO: use CLDR generic abbreviation for the zone. m_id = abbreviation(QDateTime::currentMSecsSinceEpoch()).toUtf8(); } } @@ -1034,70 +1019,19 @@ QString QTzTimeZonePrivate::displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType, const QLocale &locale) const { - // TZ DB lacks localized names (it only has IANA IDs), so delegate to ICU - // for those, when available. -#if QT_CONFIG(icu) - { - auto lock = qt_scoped_lock(s_icu_mutex); - // TODO Some valid TZ names are not valid ICU names, use translation table? - if (!m_icu) - m_icu = new QIcuTimeZonePrivate(m_id); - if (m_icu->isValid()) - return m_icu->displayName(timeType, nameType, locale); - } -#else - Q_UNUSED(timeType); - Q_UNUSED(nameType); - Q_UNUSED(locale); -#endif - // If ICU is unavailable, fall back to abbreviations. - // Abbreviations don't have GenericTime - if (timeType == QTimeZone::GenericTime) - timeType = QTimeZone::StandardTime; - - // Get current tran, if valid and is what we want, then use it - const qint64 currentMSecs = QDateTime::currentMSecsSinceEpoch(); - QTimeZonePrivate::Data tran = data(currentMSecs); - if (tran.atMSecsSinceEpoch != invalidMSecs() - && ((timeType == QTimeZone::DaylightTime && tran.daylightTimeOffset != 0) - || (timeType == QTimeZone::StandardTime && tran.daylightTimeOffset == 0))) { - return tran.abbreviation; - } - - // Otherwise get next tran and if valid and is what we want, then use it - tran = nextTransition(currentMSecs); - if (tran.atMSecsSinceEpoch != invalidMSecs() - && ((timeType == QTimeZone::DaylightTime && tran.daylightTimeOffset != 0) - || (timeType == QTimeZone::StandardTime && tran.daylightTimeOffset == 0))) { - return tran.abbreviation; - } - - // Otherwise get prev tran and if valid and is what we want, then use it - tran = previousTransition(currentMSecs); - if (tran.atMSecsSinceEpoch != invalidMSecs()) - tran = previousTransition(tran.atMSecsSinceEpoch); - if (tran.atMSecsSinceEpoch != invalidMSecs() - && ((timeType == QTimeZone::DaylightTime && tran.daylightTimeOffset != 0) - || (timeType == QTimeZone::StandardTime && tran.daylightTimeOffset == 0))) { - return tran.abbreviation; - } - - // Otherwise is strange sequence, so work backwards through trans looking for first match, if any - auto it = std::partition_point(tranCache().cbegin(), tranCache().cend(), - [currentMSecs](const QTzTransitionTime &at) { - return at.atMSecsSinceEpoch <= currentMSecs; - }); - - while (it != tranCache().cbegin()) { - --it; - tran = dataForTzTransition(*it); - int offset = tran.daylightTimeOffset; - if ((timeType == QTimeZone::DaylightTime) != (offset == 0)) - return tran.abbreviation; + // TZ only provides C-locale abbreviations and offset: + if (nameType != QTimeZone::LongName && isDataLocale(locale)) { + QTimeZonePrivate::Data tran = data(timeType); + if (tran.atMSecsSinceEpoch != invalidMSecs()) { + if (nameType == QTimeZone::ShortName) + return tran.abbreviation; + // Save base class repeating the data(timeType) query: + if (locale.language() == QLocale::C) + return isoOffsetFormat(tran.offsetFromUtc); + } } - - // Otherwise if no match use current data - return data(currentMSecs).abbreviation; + // Otherwise, fall back to base class (and qtimezonelocale.cpp): + return QTimeZonePrivate::displayName(timeType, nameType, locale); } QString QTzTimeZonePrivate::abbreviation(qint64 atMSecsSinceEpoch) const @@ -1174,7 +1108,7 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const // Otherwise, use the rule for the most recent or first transition: auto last = std::partition_point(tranCache().cbegin(), tranCache().cend(), - [forMSecsSinceEpoch] (const QTzTransitionTime &at) { + [forMSecsSinceEpoch] (QTzTransitionTime at) { return at.atMSecsSinceEpoch <= forMSecsSinceEpoch; }); if (last == tranCache().cbegin()) @@ -1184,6 +1118,64 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const return dataFromRule(cached_data.m_tranRules.at(last->ruleIndex), forMSecsSinceEpoch); } +// Overridden because the final iteration over transitions only needs to look +// forward and backwards one transition within the POSIX rule (when there is +// one, as is common) to settle the whole period it covers, so we can then skip +// all other transitions of the POSIX rule and iterate tranCache() backwards +// from its most recent transition. +QTimeZonePrivate::Data QTzTimeZonePrivate::data(QTimeZone::TimeType timeType) const +{ + // True if tran is valid and has the DST-ness to match timeType: + const auto validMatch = [timeType](const QTimeZonePrivate::Data &tran) { + return tran.atMSecsSinceEpoch != invalidMSecs() + && ((timeType == QTimeZone::DaylightTime) != (tran.daylightTimeOffset == 0)); + }; + + // Get current tran, use if suitable: + const qint64 currentMSecs = QDateTime::currentMSecsSinceEpoch(); + QTimeZonePrivate::Data tran = data(currentMSecs); + if (validMatch(tran)) + return tran; + + // Otherwise, next tran probably flips DST-ness: + tran = nextTransition(currentMSecs); + if (validMatch(tran)) + return tran; + + // Failing that, prev (or present, if current MSecs is eactly a transition + // moment) tran defines what data() got us and the one before that probably + // flips DST-ness: + tran = previousTransition(currentMSecs + 1); + if (tran.atMSecsSinceEpoch != invalidMSecs()) + tran = previousTransition(tran.atMSecsSinceEpoch); + if (validMatch(tran)) + return tran; + + // Otherwise, we can look backwards through transitions for a match; if we + // have a POSIX rule, it clearly doesn't do DST (or we'd have hit it by + // now), so we only need to look in the tranCache() up to now. + const auto untilNow = [currentMSecs](QTzTransitionTime at) { + return at.atMSecsSinceEpoch <= currentMSecs; + }; + auto it = std::partition_point(tranCache().cbegin(), tranCache().cend(), untilNow); + // That's the end or first future transition; we don't want to look at it, + // but at all those before it. + while (it != tranCache().cbegin()) { + --it; + tran = dataForTzTransition(*it); + if ((timeType == QTimeZone::DaylightTime) != (tran.daylightTimeOffset == 0)) + return tran; + } + + return {}; +} + +bool QTzTimeZonePrivate::isDataLocale(const QLocale &locale) const +{ + // TZ data uses English / C locale names: + return locale.language() == QLocale::C || locale.language() == QLocale::English; +} + bool QTzTimeZonePrivate::hasTransitions() const { return true; @@ -1206,7 +1198,7 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::nextTransition(qint64 afterMSecsSince // Otherwise, if we can find a valid tran, use its rule: auto last = std::partition_point(tranCache().cbegin(), tranCache().cend(), - [afterMSecsSinceEpoch] (const QTzTransitionTime &at) { + [afterMSecsSinceEpoch] (QTzTransitionTime at) { return at.atMSecsSinceEpoch <= afterMSecsSinceEpoch; }); return last != tranCache().cend() ? dataForTzTransition(*last) : Data{}; @@ -1231,7 +1223,7 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::previousTransition(qint64 beforeMSecs // Otherwise if we can find a valid tran then use its rule auto last = std::partition_point(tranCache().cbegin(), tranCache().cend(), - [beforeMSecsSinceEpoch] (const QTzTransitionTime &at) { + [beforeMSecsSinceEpoch] (QTzTransitionTime at) { return at.atMSecsSinceEpoch < beforeMSecsSinceEpoch; }); return last > tranCache().cbegin() ? dataForTzTransition(*--last) : Data{}; @@ -1324,8 +1316,8 @@ private: constexpr StatIdent() : m_dev(bad), m_ino(bad) {} StatIdent(const QT_STATBUF &data) : m_dev(data.st_dev), m_ino(data.st_ino) {} bool isValid() { return m_dev != bad || m_ino != bad; } - bool operator==(const StatIdent &other) - { return other.m_dev == m_dev && other.m_ino == m_ino; } + friend constexpr bool operator==(StatIdent lhs, StatIdent rhs) + { return lhs.m_dev == rhs.m_dev && lhs.m_ino == rhs.m_ino; } }; StatIdent m_last; |