summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;
}
}