diff options
author | Edward Welbourne <edward.welbourne@qt.io> | 2021-03-01 12:08:17 +0100 |
---|---|---|
committer | Edward Welbourne <edward.welbourne@qt.io> | 2021-06-11 17:12:11 +0200 |
commit | 74eddd5bf0672db4edd190aefd813bcf7eb26df4 (patch) | |
tree | e91fb3601a7899c66e691d7a494d801b26c10a22 /src/corelib | |
parent | fd5b92c2ba87cfce39e5f74115f3df5208fcf0e3 (diff) |
Rework setMSecsSinceEpoch() to avoid local->UTC conversions
The function takes a UTC time, which it converts to local time when
needed, but its (two) calls to refresh a local time instance were
doing the (more expensive) reverse conversion, which we don't need
(because we knew UTC to start with) and, in this case, it can't land
on an invalid time, so we don't need to cope with that.
Change-Id: I49b42bfa9f6a5fde12810f5a0da9ff4466ca86a4
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/time/qdatetime.cpp | 85 |
1 files changed, 41 insertions, 44 deletions
diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp index 94ea0112d4..b84f450097 100644 --- a/src/corelib/time/qdatetime.cpp +++ b/src/corelib/time/qdatetime.cpp @@ -4005,63 +4005,60 @@ void QDateTime::setMSecsSinceEpoch(qint64 msecs) { auto status = getStatus(d); const auto spec = extractSpec(status); + Q_ASSERT(spec == Qt::UTC || spec == Qt::LocalTime || !d.isShort()); + qint64 local = msecs; + int offsetFromUtc = 0; status &= ~QDateTimePrivate::ValidityMask; - switch (spec) { - case Qt::UTC: - status |= QDateTimePrivate::ValidWhenMask; - break; - case Qt::OffsetFromUTC: - if (!add_overflow(msecs, d->m_offsetFromUtc * MSECS_PER_SEC, &msecs)) + if (spec == Qt::UTC || spec == Qt::OffsetFromUTC) { + if (spec == Qt::OffsetFromUTC) + offsetFromUtc = d->m_offsetFromUtc; + if (!offsetFromUtc || !add_overflow(msecs, offsetFromUtc * MSECS_PER_SEC, &local)) status |= QDateTimePrivate::ValidWhenMask; - break; - case Qt::TimeZone: - Q_ASSERT(!d.isShort()); + } else { + auto dst = extractDaylightStatus(status); + if (spec == Qt::LocalTime) { + QDate dt; + QTime tm; + if (QDateTimePrivate::epochMSecsToLocalTime(msecs, &dt, &tm, &dst)) + setDateTime(d, dt, tm); + status = getStatus(d); + if ((status & QDateTimePrivate::ValidDate) && (status & QDateTimePrivate::ValidTime)) { + local = getMSecs(d); + offsetFromUtc = (local - msecs) / MSECS_PER_SEC; + status |= QDateTimePrivate::ValidWhenMask; + } #if QT_CONFIG(timezone) - d.detach(); - if (!d->m_timeZone.isValid()) - break; - status = mergeDaylightStatus(status, - d->m_timeZone.d->isDaylightTime(msecs) - ? QDateTimePrivate::DaylightTime - : QDateTimePrivate::StandardTime); - d->m_offsetFromUtc = d->m_timeZone.d->offsetFromUtc(msecs); - // NB: cast to qint64 here is important to make sure a matching - // add_overflow is found, GCC 7.5.0 fails without this cast - if (!add_overflow(msecs, qint64(d->m_offsetFromUtc * MSECS_PER_SEC), &msecs)) - status |= QDateTimePrivate::ValidWhenMask; + } else if (spec == Qt::TimeZone && (d.detach(), d->m_timeZone.isValid())) { + const auto data = d->m_timeZone.d->data(msecs); + if (data.offsetFromUtc != QTimeZonePrivate::invalidSeconds()) { + dst = data.daylightTimeOffset + ? QDateTimePrivate::DaylightTime + : QDateTimePrivate::StandardTime; + offsetFromUtc = data.offsetFromUtc; + if (!offsetFromUtc + // NB: cast to qint64 here is important to make sure a matching + // add_overflow is found, GCC 7.5.0 fails without this cast + || !add_overflow(msecs, qint64(offsetFromUtc * MSECS_PER_SEC), &local)) { + status |= QDateTimePrivate::ValidWhenMask; + } + } #endif // timezone - break; - case Qt::LocalTime: { - QDate dt; - QTime tm; - QDateTimePrivate::DaylightStatus dstStatus; - if (QDateTimePrivate::epochMSecsToLocalTime(msecs, &dt, &tm, &dstStatus)) { - setDateTime(d, dt, tm); - status = getStatus(d); - } - if ((status & QDateTimePrivate::ValidDate) && (status & QDateTimePrivate::ValidTime)) { - refreshZonedDateTime(d, spec); // FIXME: we do this again, below - msecs = getMSecs(d); - status = mergeDaylightStatus(getStatus(d), dstStatus); - } - break; } + status = mergeDaylightStatus(status, dst); } + Q_ASSERT(!(status & QDateTimePrivate::ValidDateTime) + || (offsetFromUtc >= -SECS_PER_DAY && offsetFromUtc <= SECS_PER_DAY)); - if (msecsCanBeSmall(msecs) && d.isShort()) { + if (msecsCanBeSmall(local) && d.isShort()) { // we can keep short - d.data.msecs = qintptr(msecs); + d.data.msecs = qintptr(local); d.data.status = status.toInt(); } else { d.detach(); d->m_status = status & ~QDateTimePrivate::ShortData; - d->m_msecs = msecs; - } - - if (spec == Qt::LocalTime || spec == Qt::TimeZone) { - refreshZonedDateTime(d, spec); - Q_ASSERT((d.isShort() ? d.data.msecs : d->m_msecs) == msecs); + d->m_msecs = local; + d->m_offsetFromUtc = offsetFromUtc; } } |