diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-04-09 01:00:06 +0200 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-04-09 01:00:06 +0200 |
commit | 93acb76222f8cfedc46cedc428a42d164c3c0f02 (patch) | |
tree | e4400085802f907b7b7c8fb09171036875128164 /src/corelib | |
parent | ce7f14d2e0791acc92622fdc23886a06d6712e90 (diff) | |
parent | a02a2a1e73206b3955438b38bb9311067ef04794 (diff) |
Merge remote-tracking branch 'origin/5.12' into 5.13
Change-Id: I05d14a40e17554691bad369d0363e88413afd9b3
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/tools/qdatetime_p.h | 4 | ||||
-rw-r--r-- | src/corelib/tools/qtimezoneprivate_tz.cpp | 55 |
2 files changed, 37 insertions, 22 deletions
diff --git a/src/corelib/tools/qdatetime_p.h b/src/corelib/tools/qdatetime_p.h index 4d30d4192b..b3d00745d0 100644 --- a/src/corelib/tools/qdatetime_p.h +++ b/src/corelib/tools/qdatetime_p.h @@ -140,6 +140,10 @@ public: // Inlined for its one caller in qdatetime.cpp inline void setUtcOffsetByTZ(qint64 atMSecsSinceEpoch); #endif // timezone + + // ### Qt 5.14: expose publicly in QDateTime + // The first and last years of which QDateTime can represent some part: + enum class YearRange : qint32 { First = -292275056, Last = +292278994 }; }; QT_END_NAMESPACE diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp index f75a61977d..7d85bc077d 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) { |