Use same-msecs optimization more in QDateTime comparison

QDateTime's comparisons just compare milliseconds when both values are
local times and their statuses (hence DST-ness) match. It can do the
same for time-zones. While doing the same for UTC and fixed offsets
wins nothing, it also costs nothing, given that we're already checking
the spec.

Task-number: QTBUG-75585
Change-Id: Ib6d824569aba8def2f1319ef3a11cca6869a5b5e
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Edward Welbourne 2020-09-21 11:06:18 +02:00 committed by Thiago Macieira
parent 691762e0e3
commit 3bd6901429
2 changed files with 50 additions and 5 deletions

View File

@ -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

View File

@ -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()