diff options
-rw-r--r-- | src/corelib/tools/qtimezoneprivate_p.h | 1 | ||||
-rw-r--r-- | src/corelib/tools/qtimezoneprivate_tz.cpp | 46 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp | 4 |
3 files changed, 27 insertions, 24 deletions
diff --git a/src/corelib/tools/qtimezoneprivate_p.h b/src/corelib/tools/qtimezoneprivate_p.h index c9a5726216..24a9a00f11 100644 --- a/src/corelib/tools/qtimezoneprivate_p.h +++ b/src/corelib/tools/qtimezoneprivate_p.h @@ -331,6 +331,7 @@ public: private: void init(const QByteArray &ianaId); + QVector<QTimeZonePrivate::Data> getPosixTransitions(qint64 msNear) const; Data dataForTzTransition(QTzTransitionTime tran) const; QVector<QTzTransitionTime> m_tranTimes; diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp index fa4ec031fa..f75a61977d 100644 --- a/src/corelib/tools/qtimezoneprivate_tz.cpp +++ b/src/corelib/tools/qtimezoneprivate_tz.cpp @@ -943,19 +943,21 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::dataForTzTransition(QTzTransitionTime return data; } -QTimeZonePrivate::Data QTzTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const +QVector<QTimeZonePrivate::Data> QTzTimeZonePrivate::getPosixTransitions(qint64 msNear) const { - // If we have no rules (so probably an invalid tz), return invalid data: - if (!m_tranTimes.size()) - return invalidData(); + const int year = QDateTime::fromMSecsSinceEpoch(msNear, Qt::UTC).date().year(); + // The Data::atMSecsSinceEpoch of the single entry if zone is constant: + qint64 atTime = m_tranTimes.isEmpty() ? msNear : m_tranTimes.last().atMSecsSinceEpoch; + return calculatePosixTransitions(m_posixRule, year - 1, year + 1, atTime); +} - // If the required time is after the last transition and we have a POSIX rule then use it - if (m_tranTimes.last().atMSecsSinceEpoch < forMSecsSinceEpoch +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) { - const int year = QDateTime::fromMSecsSinceEpoch(forMSecsSinceEpoch, Qt::UTC).date().year(); - QVector<QTimeZonePrivate::Data> posixTrans = - calculatePosixTransitions(m_posixRule, year - 1, year + 1, - m_tranTimes.last().atMSecsSinceEpoch); + QVector<QTimeZonePrivate::Data> posixTrans = getPosixTransitions(forMSecsSinceEpoch); auto it = std::partition_point(posixTrans.cbegin(), posixTrans.cend(), [forMSecsSinceEpoch] (const QTimeZonePrivate::Data &at) { return at.atMSecsSinceEpoch <= forMSecsSinceEpoch; @@ -986,13 +988,11 @@ bool QTzTimeZonePrivate::hasTransitions() const QTimeZonePrivate::Data QTzTimeZonePrivate::nextTransition(qint64 afterMSecsSinceEpoch) const { - // If the required time is after the last transition and we have a POSIX rule then use it - if (m_tranTimes.size() > 0 && m_tranTimes.last().atMSecsSinceEpoch < afterMSecsSinceEpoch + // 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) { - const int year = QDateTime::fromMSecsSinceEpoch(afterMSecsSinceEpoch, Qt::UTC).date().year(); - QVector<QTimeZonePrivate::Data> posixTrans = - calculatePosixTransitions(m_posixRule, year - 1, year + 1, - m_tranTimes.last().atMSecsSinceEpoch); + QVector<QTimeZonePrivate::Data> posixTrans = getPosixTransitions(afterMSecsSinceEpoch); auto it = std::partition_point(posixTrans.cbegin(), posixTrans.cend(), [afterMSecsSinceEpoch] (const QTimeZonePrivate::Data &at) { return at.atMSecsSinceEpoch <= afterMSecsSinceEpoch; @@ -1011,21 +1011,19 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::nextTransition(qint64 afterMSecsSince QTimeZonePrivate::Data QTzTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch) const { - // If the required time is after the last transition and we have a POSIX rule then use it - if (m_tranTimes.size() > 0 && m_tranTimes.last().atMSecsSinceEpoch < beforeMSecsSinceEpoch + // 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) { - const int year = QDateTime::fromMSecsSinceEpoch(beforeMSecsSinceEpoch, Qt::UTC).date().year(); - QVector<QTimeZonePrivate::Data> posixTrans = - calculatePosixTransitions(m_posixRule, year - 1, year + 1, - m_tranTimes.last().atMSecsSinceEpoch); + QVector<QTimeZonePrivate::Data> posixTrans = getPosixTransitions(beforeMSecsSinceEpoch); auto it = std::partition_point(posixTrans.cbegin(), posixTrans.cend(), [beforeMSecsSinceEpoch] (const QTimeZonePrivate::Data &at) { return at.atMSecsSinceEpoch < beforeMSecsSinceEpoch; }); if (it > posixTrans.cbegin()) return *--it; - // else: it fell between the last transition and the first of the POSIX rule. - return dataForTzTransition(m_tranTimes.last()); + // It fell between the last transition (if any) and the first of the POSIX rule: + return m_tranTimes.isEmpty() ? invalidData() : dataForTzTransition(m_tranTimes.last()); } // Otherwise if we can find a valid tran then use its rule diff --git a/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp b/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp index a25fd39693..eff9835776 100644 --- a/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp +++ b/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp @@ -539,6 +539,8 @@ void tst_QTimeZone::checkOffset_data() int year, month, day, hour, min, sec; int std, dst; } table[] = { + // Zone with no transitions (QTBUG-74614, when TZ backend uses minimalist data) + { "Etc/UTC", "epoch", 1970, 1, 1, 0, 0, 0, 0, 0 }, // Kiev: regression test for QTBUG-64122 (on MS): { "Europe/Kiev", "summer", 2017, 10, 27, 12, 0, 0, 2 * 3600, 3600 }, { "Europe/Kiev", "winter", 2017, 10, 29, 12, 0, 0, 2 * 3600, 0 } @@ -551,6 +553,8 @@ void tst_QTimeZone::checkOffset_data() << QDateTime(QDate(entry.year, entry.month, entry.day), QTime(entry.hour, entry.min, entry.sec), zone) << entry.dst + entry.std << entry.std << entry.dst; + } else { + qWarning("Skipping %s@%s test as zone is invalid", entry.zone, entry.nick); } } } |