diff options
-rw-r--r-- | src/corelib/time/qdatetime.cpp | 35 | ||||
-rw-r--r-- | tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp | 20 |
2 files changed, 50 insertions, 5 deletions
diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp index f51411f45b..c6a41855b0 100644 --- a/src/corelib/time/qdatetime.cpp +++ b/src/corelib/time/qdatetime.cpp @@ -2763,6 +2763,37 @@ static inline Qt::TimeSpec getSpec(const QDateTimeData &d) return extractSpec(getStatus(d)); } +/* True if we *can cheaply determine* that a and b use the same offset. + If they use different offsets or it would be expensive to find out, false. + Calls to toMSecsSinceEpoch() are expensive, for these purposes. + See QDateTime's comparison operators. +*/ +static inline bool usesSameOffset(const QDateTimeData &a, const QDateTimeData &b) +{ + const auto status = getStatus(a); + if (status != getStatus(b)) + return false; + // Status includes DST-ness, so we now know they match in it. + + switch (extractSpec(status)) { + case Qt::LocalTime: + case Qt::UTC: + return true; + + case Qt::TimeZone: + /* TimeZone always determines its offset during construction of the + private data. Even if we're in different zones, what matters is the + offset actually in effect at the specific time. (DST can cause things + with the same time-zone to use different offsets, but we already + checked their DSTs match.) */ + case Qt::OffsetFromUTC: // always knows its offset, which is all that matters. + Q_ASSERT(!a.isShort() && !b.isShort()); + return a->m_offsetFromUtc == b->m_offsetFromUtc; + } + Q_UNREACHABLE(); + return false; +} + #if QT_CONFIG(timezone) void QDateTimePrivate::setUtcOffsetByTZ(qint64 atMSecsSinceEpoch) { @@ -4333,7 +4364,7 @@ bool QDateTime::operator==(const QDateTime &other) const if (!other.isValid()) return false; - if (getSpec(d) == Qt::LocalTime && getStatus(d) == getStatus(other.d)) + if (usesSameOffset(d, other.d)) return getMSecs(d) == getMSecs(other.d); // Convert to UTC and compare @@ -4365,7 +4396,7 @@ bool QDateTime::operator<(const QDateTime &other) const if (!other.isValid()) return false; - if (getSpec(d) == Qt::LocalTime && getStatus(d) == getStatus(other.d)) + if (usesSameOffset(d, other.d)) return getMSecs(d) < getMSecs(other.d); // Convert to UTC and compare diff --git a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp index b942316c95..a568ef69db 100644 --- a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp @@ -1971,12 +1971,26 @@ void tst_QDateTime::operator_eqeq_data() // might agree with UTC about the epoch, all the same. QTest::newRow("invalid == invalid") << QDateTime() << QDateTime() << true << false; - QTest::newRow("invalid == valid #1") << QDateTime() << dateTime1 << false << false; + QTest::newRow("invalid != valid #1") << QDateTime() << dateTime1 << false << false; if (zoneIsCET) { - QTest::newRow("data14") << QDateTime(QDate(2004, 1, 2), QTime(2, 2, 3), Qt::LocalTime) - << QDateTime(QDate(2004, 1, 2), QTime(1, 2, 3), Qt::UTC) << true << true; + QTest::newRow("data14") + << QDateTime(QDate(2004, 1, 2), QTime(2, 2, 3), Qt::LocalTime) + << QDateTime(QDate(2004, 1, 2), QTime(1, 2, 3), Qt::UTC) << true << true; + QTest::newRow("local-fall-back") // Sun, 31 Oct 2004, 02:30, both ways round: + << QDateTime::fromMSecsSinceEpoch(Q_INT64_C(1099186200000)) + << QDateTime::fromMSecsSinceEpoch(Q_INT64_C(1099182600000)) + << false << false; } +#if QT_CONFIG(timezone) + const QTimeZone CET("Europe/Oslo"); + if (CET.isValid()) { + QTest::newRow("CET-fall-back") // Sun, 31 Oct 2004, 02:30, both ways round: + << QDateTime::fromMSecsSinceEpoch(Q_INT64_C(1099186200000), CET) + << QDateTime::fromMSecsSinceEpoch(Q_INT64_C(1099182600000), CET) + << false << false; + } +#endif } void tst_QDateTime::operator_eqeq() |