summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/time/qdatetime.cpp35
-rw-r--r--tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp20
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()