From b6544dc36caffa18e60db6adfcd8ea6ff6654960 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Mon, 22 Feb 2021 18:44:41 +0100 Subject: [PATCH] QTzTimeZonePrivate: provide correct data for before the first transition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We previously used the data for after the first transition; but the Olson database knows about local mean time for each zone, and it does get used by the system libraries, so systemZone will conflict with LocalTime once we use the time_t functions outside their 32-bit range (coming shortly). Record the pre-zone data during parsing and use it in the (fortunately only one) place that needs it. Discovered the issue in the course of debugging other issues while purging QDateTime of its wilful ignorance of pre-1970 DST. Change-Id: Icf957460fa3ccbaf5165e79f38ac68b450ecf98f Reviewed-by: MÃ¥rten Nordheim Reviewed-by: Thiago Macieira --- src/corelib/time/qtimezoneprivate_p.h | 2 ++ src/corelib/time/qtimezoneprivate_tz.cpp | 36 +++++++++++++++--------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/corelib/time/qtimezoneprivate_p.h b/src/corelib/time/qtimezoneprivate_p.h index 4fcf4cf32c..164a1b790f 100644 --- a/src/corelib/time/qtimezoneprivate_p.h +++ b/src/corelib/time/qtimezoneprivate_p.h @@ -300,6 +300,7 @@ struct QTzTimeZoneCacheEntry QList m_tranRules; QList m_abbreviations; QByteArray m_posixRule; + QTzTransitionRule m_preZoneRule; }; class Q_AUTOTEST_EXPORT QTzTimeZonePrivate final : public QTimeZonePrivate @@ -349,6 +350,7 @@ private: QList getPosixTransitions(qint64 msNear) const; Data dataForTzTransition(QTzTransitionTime tran) const; + Data dataFromRule(QTzTransitionRule rule, qint64 msecsSinceEpoch) const; #if QT_CONFIG(icu) mutable QSharedDataPointer m_icu; #endif diff --git a/src/corelib/time/qtimezoneprivate_tz.cpp b/src/corelib/time/qtimezoneprivate_tz.cpp index e758f1c12f..dd3dae78e9 100644 --- a/src/corelib/time/qtimezoneprivate_tz.cpp +++ b/src/corelib/time/qtimezoneprivate_tz.cpp @@ -768,12 +768,20 @@ QTzTimeZoneCacheEntry QTzTimeZoneCache::findEntry(const QByteArray &ianaId) ret.m_abbreviations.append(it.value()); abbrindList.append(it.key()); } + // Map tz_abbrind from map's keys (as initially read) to abbrindList's + // indices (used hereafter): for (int i = 0; i < typeList.size(); ++i) typeList[i].tz_abbrind = abbrindList.indexOf(typeList.at(i).tz_abbrind); + // TODO: is typeList[0] always the "before zones" data ? It seems to be ... + if (typeList.size()) + ret.m_preZoneRule = { typeList.at(0).tz_gmtoff, 0, typeList.at(0).tz_abbrind }; + else + ret.m_preZoneRule = { 0, 0, 0 }; + // Offsets are stored as total offset, want to know separate UTC and DST offsets // so find the first non-dst transition to use as base UTC Offset - int utcOffset = 0; + int utcOffset = ret.m_preZoneRule.stdOffset; for (const QTzTransition &tran : qAsConst(tranList)) { if (!typeList.at(tran.tz_typeind).tz_isdst) { utcOffset = typeList.at(tran.tz_typeind).tz_gmtoff; @@ -1026,14 +1034,14 @@ bool QTzTimeZonePrivate::isDaylightTime(qint64 atMSecsSinceEpoch) const QTimeZonePrivate::Data QTzTimeZonePrivate::dataForTzTransition(QTzTransitionTime tran) const { - QTimeZonePrivate::Data data; - data.atMSecsSinceEpoch = tran.atMSecsSinceEpoch; - QTzTransitionRule rule = cached_data.m_tranRules.at(tran.ruleIndex); - data.standardTimeOffset = rule.stdOffset; - data.daylightTimeOffset = rule.dstOffset; - data.offsetFromUtc = rule.stdOffset + rule.dstOffset; - data.abbreviation = QString::fromUtf8(cached_data.m_abbreviations.at(rule.abbreviationIndex)); - return data; + return dataFromRule(cached_data.m_tranRules.at(tran.ruleIndex), tran.atMSecsSinceEpoch); +} + +QTimeZonePrivate::Data QTzTimeZonePrivate::dataFromRule(QTzTransitionRule rule, + qint64 msecsSinceEpoch) const +{ + return { QString::fromUtf8(cached_data.m_abbreviations.at(rule.abbreviationIndex)), + msecsSinceEpoch, rule.stdOffset + rule.dstOffset, rule.stdOffset, rule.dstOffset }; } QList QTzTimeZonePrivate::getPosixTransitions(qint64 msNear) const @@ -1070,11 +1078,11 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const [forMSecsSinceEpoch] (const QTzTransitionTime &at) { return at.atMSecsSinceEpoch <= forMSecsSinceEpoch; }); - if (last > tranCache().cbegin()) - --last; - Data data = dataForTzTransition(*last); - data.atMSecsSinceEpoch = forMSecsSinceEpoch; - return data; + if (last == tranCache().cbegin()) + return dataFromRule(cached_data.m_preZoneRule, forMSecsSinceEpoch); + + --last; + return dataFromRule(cached_data.m_tranRules.at(last->ruleIndex), forMSecsSinceEpoch); } bool QTzTimeZonePrivate::hasTransitions() const