diff options
author | Liang Qi <liang.qi@qt.io> | 2019-04-10 08:16:20 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2019-04-10 08:16:20 +0200 |
commit | a20da2353cc308aab15e3efa05ab7d899e9c6ca7 (patch) | |
tree | 63881eb44f19384ebfb0e0443291b8f9ab82f149 /src/corelib/tools/qtimezoneprivate_tz.cpp | |
parent | 95f787bfdc890c259e8b347bdad9123d534efe0f (diff) | |
parent | eaf20420f8a4d72c804a9d3725c3e294b34c78c8 (diff) |
Merge remote-tracking branch 'origin/5.13' into dev
Conflicts:
mkspecs/win32-clang-msvc/qmake.conf
src/gui/image/qpnghandler.cpp
Change-Id: Ied79d02912ffb3a307a99483df7db08c7f9d0cd8
Diffstat (limited to 'src/corelib/tools/qtimezoneprivate_tz.cpp')
-rw-r--r-- | src/corelib/tools/qtimezoneprivate_tz.cpp | 55 |
1 files changed, 33 insertions, 22 deletions
diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp index 6105c93a23..fab0b2cbf1 100644 --- a/src/corelib/tools/qtimezoneprivate_tz.cpp +++ b/src/corelib/tools/qtimezoneprivate_tz.cpp @@ -39,6 +39,7 @@ #include "qtimezone.h" #include "qtimezoneprivate_p.h" +#include "qdatetime_p.h" // ### Qt 5.14: remove once YearRange is on QDateTime #include <QtCore/QFile> #include <QtCore/QHash> @@ -520,19 +521,14 @@ PosixZone PosixZone::parse(const char *&pos, const char *end) static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArray &posixRule, int startYear, int endYear, - int lastTranMSecs) + qint64 lastTranMSecs) { QVector<QTimeZonePrivate::Data> result; - // Limit year by qint64 max size for msecs - if (startYear > 292278994) - startYear = 292278994; - if (endYear > 292278994) - endYear = 292278994; - // POSIX Format is like "TZ=CST6CDT,M3.2.0/2:00:00,M11.1.0/2:00:00" // i.e. "std offset dst [offset],start[/time],end[/time]" - // See the section about TZ at http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html + // See the section about TZ at + // http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html QList<QByteArray> parts = posixRule.split(','); PosixZone stdZone, dstZone = PosixZone::invalid(); @@ -583,6 +579,13 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra else stdTime = QTime(2, 0, 0); + // Limit year to the range QDateTime can represent: + const int minYear = int(QDateTimePrivate::YearRange::First); + const int maxYear = int(QDateTimePrivate::YearRange::Last); + startYear = qBound(minYear, startYear, maxYear); + endYear = qBound(minYear, endYear, maxYear); + Q_ASSERT(startYear <= endYear); + for (int year = startYear; year <= endYear; ++year) { QTimeZonePrivate::Data dstData; QDateTime dst(calculatePosixDate(dstDateRule, year), dstTime, Qt::UTC); @@ -598,13 +601,16 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra stdData.standardTimeOffset = stdZone.offset; stdData.daylightTimeOffset = 0; stdData.abbreviation = stdZone.name; - // Part of the high year will overflow - if (year == 292278994 && (dstData.atMSecsSinceEpoch < 0 || stdData.atMSecsSinceEpoch < 0)) { + // Part of maxYear will overflow (likewise for minYear, below): + if (year == maxYear && (dstData.atMSecsSinceEpoch < 0 || stdData.atMSecsSinceEpoch < 0)) { if (dstData.atMSecsSinceEpoch > 0) { result << dstData; } else if (stdData.atMSecsSinceEpoch > 0) { result << stdData; } + } else if (year < 1970) { // We ignore DST before the epoch. + if (year > minYear || stdData.atMSecsSinceEpoch != QTimeZonePrivate::invalidMSecs()) + result << stdData; } else if (dst < std) { result << dstData << stdData; } else { @@ -794,6 +800,8 @@ void QTzTimeZonePrivate::init(const QByteArray &ianaId) tran.atMSecsSinceEpoch = tz_tran.tz_time * 1000; m_tranTimes.append(tran); } + if (m_tranTimes.isEmpty() && m_posixRule.isEmpty()) + return; // Invalid after all ! if (ianaId.isEmpty()) m_id = systemTimeZoneId(); @@ -954,22 +962,25 @@ QVector<QTimeZonePrivate::Data> QTzTimeZonePrivate::getPosixTransitions(qint64 m QTimeZonePrivate::Data QTzTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const { // If the required time is after the last transition (or there were none) - // and we have a POSIX rule then use it: - if ((m_tranTimes.isEmpty() || m_tranTimes.last().atMSecsSinceEpoch < forMSecsSinceEpoch) - && !m_posixRule.isEmpty() && forMSecsSinceEpoch >= 0) { + // and we have a POSIX rule, then use it: + if (!m_posixRule.isEmpty() + && (m_tranTimes.isEmpty() || m_tranTimes.last().atMSecsSinceEpoch < forMSecsSinceEpoch)) { QVector<QTimeZonePrivate::Data> posixTrans = getPosixTransitions(forMSecsSinceEpoch); auto it = std::partition_point(posixTrans.cbegin(), posixTrans.cend(), [forMSecsSinceEpoch] (const QTimeZonePrivate::Data &at) { return at.atMSecsSinceEpoch <= forMSecsSinceEpoch; }); - if (it > posixTrans.cbegin()) { - QTimeZonePrivate::Data data = *--it; + // Use most recent, if any in the past; or the first if we have no other rules: + if (it > posixTrans.cbegin() || (m_tranTimes.isEmpty() && it < posixTrans.cend())) { + QTimeZonePrivate::Data data = *(it > posixTrans.cbegin() ? it - 1 : it); data.atMSecsSinceEpoch = forMSecsSinceEpoch; return data; } } + if (m_tranTimes.isEmpty()) // Only possible if !isValid() + return invalidData(); - // Otherwise, if we can find a valid tran, then use its rule: + // Otherwise, use the rule for the most recent or first transition: auto last = std::partition_point(m_tranTimes.cbegin(), m_tranTimes.cend(), [forMSecsSinceEpoch] (const QTzTransitionTime &at) { return at.atMSecsSinceEpoch <= forMSecsSinceEpoch; @@ -989,9 +1000,9 @@ bool QTzTimeZonePrivate::hasTransitions() const QTimeZonePrivate::Data QTzTimeZonePrivate::nextTransition(qint64 afterMSecsSinceEpoch) const { // If the required time is after the last transition (or there were none) - // and we have a POSIX rule then use it: - if ((m_tranTimes.isEmpty() || m_tranTimes.last().atMSecsSinceEpoch < afterMSecsSinceEpoch) - && !m_posixRule.isEmpty() && afterMSecsSinceEpoch >= 0) { + // and we have a POSIX rule, then use it: + if (!m_posixRule.isEmpty() + && (m_tranTimes.isEmpty() || m_tranTimes.last().atMSecsSinceEpoch < afterMSecsSinceEpoch)) { QVector<QTimeZonePrivate::Data> posixTrans = getPosixTransitions(afterMSecsSinceEpoch); auto it = std::partition_point(posixTrans.cbegin(), posixTrans.cend(), [afterMSecsSinceEpoch] (const QTimeZonePrivate::Data &at) { @@ -1012,9 +1023,9 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::nextTransition(qint64 afterMSecsSince QTimeZonePrivate::Data QTzTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch) const { // If the required time is after the last transition (or there were none) - // and we have a POSIX rule then use it: - if ((m_tranTimes.isEmpty() || m_tranTimes.last().atMSecsSinceEpoch < beforeMSecsSinceEpoch) - && !m_posixRule.isEmpty() && beforeMSecsSinceEpoch > 0) { + // and we have a POSIX rule, then use it: + if (!m_posixRule.isEmpty() + && (m_tranTimes.isEmpty() || m_tranTimes.last().atMSecsSinceEpoch < beforeMSecsSinceEpoch)) { QVector<QTimeZonePrivate::Data> posixTrans = getPosixTransitions(beforeMSecsSinceEpoch); auto it = std::partition_point(posixTrans.cbegin(), posixTrans.cend(), [beforeMSecsSinceEpoch] (const QTimeZonePrivate::Data &at) { |