summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2019-03-21 15:07:48 +0100
committerTony Sarajärvi <tony.sarajarvi@qt.io>2019-03-22 07:32:52 +0000
commit03fadc26e7617aece89949bc7d0acf50f6f050a9 (patch)
tree2da6ae332630caa0883ca8d2dbc57495131e2460 /src/corelib
parent1119cd4ece6555be82212b273d05d581bffb79d1 (diff)
Fix broken data for time-zones with no transitions
While an invalid time-zone shall have no transitions, so may various constant zones, like UTC. The TZ data may include only the POSIX rule for such a zone, in which case we should use it, even if there are no transitions. Broke out a piece of repeated code as a common method, in the process, since I was complicating it further. Added test for the case that revealed this; and made sure we see a warning if any of the checkOffset() tests gets skipped because its zone is unsupported. Fixes: QTBUG-74614 Change-Id: Ic8e039a2a9b3f4e0f567585682a94f4b494b558d Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/tools/qtimezoneprivate_p.h1
-rw-r--r--src/corelib/tools/qtimezoneprivate_tz.cpp46
2 files changed, 23 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