summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2021-03-01 12:08:17 +0100
committerEdward Welbourne <edward.welbourne@qt.io>2021-06-11 17:12:11 +0200
commit74eddd5bf0672db4edd190aefd813bcf7eb26df4 (patch)
treee91fb3601a7899c66e691d7a494d801b26c10a22 /src/corelib
parentfd5b92c2ba87cfce39e5f74115f3df5208fcf0e3 (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.cpp85
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;
}
}