diff options
Diffstat (limited to 'src/corelib/tools/qdatetime.cpp')
-rw-r--r-- | src/corelib/tools/qdatetime.cpp | 1051 |
1 files changed, 644 insertions, 407 deletions
diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index bfc7e1ca0e..f8611b3e68 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -57,9 +57,6 @@ #include <time.h> #ifdef Q_OS_WIN # include <qt_windows.h> -# ifdef Q_OS_WINCE -# include "qfunctions_wince.h" -# endif # ifdef Q_OS_WINRT # include "qfunctions_winrt.h" # endif @@ -71,8 +68,6 @@ QT_BEGIN_NAMESPACE -Q_GLOBAL_STATIC_WITH_ARGS(QSharedDataPointer<QDateTimePrivate>, defaultDateTimePrivate, (new QDateTimePrivate())) - /***************************************************************************** Date/Time Constants *****************************************************************************/ @@ -1687,9 +1682,6 @@ QString QTime::toString(const QString& format) const bool QTime::setHMS(int h, int m, int s, int ms) { -#if defined(Q_OS_WINCE) - startTick = NullTime; -#endif if (!isValid(h,m,s,ms)) { mds = NullTime; // make this invalid return false; @@ -1769,10 +1761,6 @@ QTime QTime::addMSecs(int ms) const t.mds = (ds() + ms) % MSECS_PER_DAY; } } -#if defined(Q_OS_WINCE) - if (startTick > NullTime) - t.startTick = (startTick + ms) % MSECS_PER_DAY; -#endif return t; } @@ -1794,13 +1782,7 @@ int QTime::msecsTo(const QTime &t) const { if (!isValid() || !t.isValid()) return 0; -#if defined(Q_OS_WINCE) - // GetLocalTime() for Windows CE has no milliseconds resolution - if (t.startTick > NullTime && startTick > NullTime) - return t.startTick - startTick; - else -#endif - return t.ds() - ds(); + return t.ds() - ds(); } @@ -2141,13 +2123,14 @@ int QTime::elapsed() const QDateTime static helper functions *****************************************************************************/ +// get the types from QDateTime (through QDateTimePrivate) +typedef QDateTimePrivate::QDateTimeShortData ShortData; +typedef QDateTimePrivate::QDateTimeData QDateTimeData; + // Calls the platform variant of tzset static void qt_tzset() { -#if defined(Q_OS_WINCE) - // WinCE doesn't use tzset - return; -#elif defined(Q_OS_WIN) +#if defined(Q_OS_WIN) _tzset(); #else tzset(); @@ -2161,12 +2144,7 @@ static void qt_tzset() // Relies on tzset, mktime, or localtime having been called to populate timezone static int qt_timezone() { -#if defined(Q_OS_WINCE) - TIME_ZONE_INFORMATION tzi; - GetTimeZoneInformation(&tzi); - // Expressed in minutes, convert to seconds - return (tzi.Bias + tzi.StandardBias) * 60; -#elif defined(_MSC_VER) && _MSC_VER >= 1400 +#if defined(_MSC_VER) long offset; _get_timezone(&offset); return offset; @@ -2195,16 +2173,6 @@ static int qt_timezone() // Returns the tzname, assume tzset has been called already static QString qt_tzname(QDateTimePrivate::DaylightStatus daylightStatus) { -#if defined(Q_OS_WINCE) - TIME_ZONE_INFORMATION tzi; - DWORD res = GetTimeZoneInformation(&tzi); - if (res == TIME_ZONE_ID_UNKNOWN) - return QString(); - else if (daylightStatus == QDateTimePrivate::DaylightTime) - return QString::fromWCharArray(tzi.DaylightName); - else - return QString::fromWCharArray(tzi.StandardName); -#else int isDst = (daylightStatus == QDateTimePrivate::DaylightTime) ? 1 : 0; #if defined(_MSC_VER) && _MSC_VER >= 1400 size_t s = 0; @@ -2215,7 +2183,6 @@ static QString qt_tzname(QDateTimePrivate::DaylightStatus daylightStatus) #else return QString::fromLocal8Bit(tzname[isDst]); #endif // Q_OS_WIN -#endif // Q_OS_WINCE } // Calls the platform variant of mktime for the given date, time and daylightStatus, @@ -2230,48 +2197,6 @@ static qint64 qt_mktime(QDate *date, QTime *time, QDateTimePrivate::DaylightStat int yy, mm, dd; date->getDate(&yy, &mm, &dd); -#if defined(Q_OS_WINCE) - // WinCE doesn't provide standard C library time functions - SYSTEMTIME st; - memset(&st, 0, sizeof(SYSTEMTIME)); - st.wSecond = time->second(); - st.wMinute = time->minute(); - st.wHour = time->hour(); - st.wDay = dd; - st.wMonth = mm; - st.wYear = yy; - FILETIME lft; - bool valid = SystemTimeToFileTime(&st, &lft); - FILETIME ft; - if (valid) - valid = LocalFileTimeToFileTime(&lft, &ft); - const time_t secsSinceEpoch = ftToTime_t(ft); - const time_t localSecs = ftToTime_t(lft); - TIME_ZONE_INFORMATION tzi; - GetTimeZoneInformation(&tzi); - bool isDaylight = false; - // Check for overflow - qint64 localDiff = qAbs(localSecs - secsSinceEpoch); - int daylightOffset = qAbs(tzi.Bias + tzi.DaylightBias) * 60; - if (localDiff > daylightOffset) - valid = false; - else - isDaylight = (localDiff == daylightOffset); - if (daylightStatus) { - if (isDaylight) - *daylightStatus = QDateTimePrivate::DaylightTime; - else - *daylightStatus = QDateTimePrivate::StandardTime; - } - if (abbreviation) { - if (isDaylight) - *abbreviation = QString::fromWCharArray(tzi.DaylightName); - else - *abbreviation = QString::fromWCharArray(tzi.StandardName); - } - if (ok) - *ok = valid; -#else // All other platforms provide standard C library time functions tm local; memset(&local, 0, sizeof(local)); // tm_[wy]day plus any non-standard fields @@ -2333,7 +2258,6 @@ static qint64 qt_mktime(QDate *date, QTime *time, QDateTimePrivate::DaylightStat if (ok) *ok = false; } -#endif // Q_OS_WINCE return ((qint64)secsSinceEpoch * 1000) + msec; } @@ -2349,23 +2273,7 @@ static bool qt_localtime(qint64 msecsSinceEpoch, QDate *localDate, QTime *localT tm local; bool valid = false; -#if defined(Q_OS_WINCE) - FILETIME utcTime = time_tToFt(secsSinceEpoch); - FILETIME resultTime; - valid = FileTimeToLocalFileTime(&utcTime , &resultTime); - SYSTEMTIME sysTime; - if (valid) - valid = FileTimeToSystemTime(&resultTime , &sysTime); - - if (valid) { - local.tm_sec = sysTime.wSecond; - local.tm_min = sysTime.wMinute; - local.tm_hour = sysTime.wHour; - local.tm_mday = sysTime.wDay; - local.tm_mon = sysTime.wMonth - 1; - local.tm_year = sysTime.wYear - 1900; - } -#elif !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) +#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) // localtime() is required to work as if tzset() was called before it. // localtime_r() does not have this requirement, so make an explicit call. qt_tzset(); @@ -2578,240 +2486,423 @@ static qint64 localMSecsToEpochMSecs(qint64 localMsecs, } } -/***************************************************************************** - QDateTimePrivate member functions - *****************************************************************************/ +static inline bool specCanBeSmall(Qt::TimeSpec spec) +{ + return spec == Qt::LocalTime || spec == Qt::UTC; +} -QDateTimePrivate::QDateTimePrivate(const QDate &toDate, const QTime &toTime, Qt::TimeSpec toSpec, - int offsetSeconds) - : m_msecs(0), - m_spec(Qt::LocalTime), - m_offsetFromUtc(0), - m_status(0) +static inline bool msecsCanBeSmall(qint64 msecs) { - setTimeSpec(toSpec, offsetSeconds); - setDateTime(toDate, toTime); + if (!QDateTimeData::CanBeSmall) + return false; + + ShortData sd; + sd.msecs = qintptr(msecs); + return sd.msecs == msecs; } -#ifndef QT_BOOTSTRAPPED -QDateTimePrivate::QDateTimePrivate(const QDate &toDate, const QTime &toTime, - const QTimeZone &toTimeZone) - : m_spec(Qt::TimeZone), - m_offsetFromUtc(0), - m_timeZone(toTimeZone), - m_status(0) +static Q_DECL_CONSTEXPR inline +QDateTimePrivate::StatusFlags mergeSpec(QDateTimePrivate::StatusFlags status, Qt::TimeSpec spec) { - setDateTime(toDate, toTime); + return QDateTimePrivate::StatusFlags((status & ~QDateTimePrivate::TimeSpecMask) | + (int(spec) << QDateTimePrivate::TimeSpecShift)); +} + +static Q_DECL_CONSTEXPR inline Qt::TimeSpec extractSpec(QDateTimePrivate::StatusFlags status) +{ + return Qt::TimeSpec((status & QDateTimePrivate::TimeSpecMask) >> QDateTimePrivate::TimeSpecShift); +} + +// Set the Daylight Status if LocalTime set via msecs +static Q_DECL_RELAXED_CONSTEXPR inline QDateTimePrivate::StatusFlags +mergeDaylightStatus(QDateTimePrivate::StatusFlags sf, QDateTimePrivate::DaylightStatus status) +{ + sf &= ~QDateTimePrivate::DaylightMask; + if (status == QDateTimePrivate::DaylightTime) { + sf |= QDateTimePrivate::SetToDaylightTime; + } else if (status == QDateTimePrivate::StandardTime) { + sf |= QDateTimePrivate::SetToStandardTime; + } + return sf; +} + +// Get the DST Status if LocalTime set via msecs +static Q_DECL_RELAXED_CONSTEXPR inline +QDateTimePrivate::DaylightStatus extractDaylightStatus(QDateTimePrivate::StatusFlags status) +{ + if (status & QDateTimePrivate::SetToDaylightTime) + return QDateTimePrivate::DaylightTime; + if (status & QDateTimePrivate::SetToStandardTime) + return QDateTimePrivate::StandardTime; + return QDateTimePrivate::UnknownDaylightTime; } -#endif // QT_BOOTSTRAPPED -void QDateTimePrivate::setTimeSpec(Qt::TimeSpec spec, int offsetSeconds) +static inline qint64 getMSecs(const QDateTimeData &d) { - clearValidDateTime(); - clearSetToDaylightStatus(); + if (d.isShort()) { + // same as, but producing better code + //return d.data.msecs; + return qintptr(d.d) >> 8; + } + return d->m_msecs; +} + +static inline QDateTimePrivate::StatusFlags getStatus(const QDateTimeData &d) +{ + if (d.isShort()) { + // same as, but producing better code + //return StatusFlag(d.data.status); + return QDateTimePrivate::StatusFlag(qintptr(d.d) & 0xFF); + } + return d->m_status; +} + +static inline Qt::TimeSpec getSpec(const QDateTimeData &d) +{ + return extractSpec(getStatus(d)); +} + +// Refresh the LocalTime validity and offset +static void refreshDateTime(QDateTimeData &d) +{ + auto status = getStatus(d); + const auto spec = extractSpec(status); + const qint64 msecs = getMSecs(d); + qint64 epochMSecs = 0; + int offsetFromUtc = 0; + QDate testDate; + QTime testTime; + Q_ASSERT(spec == Qt::TimeZone || spec == Qt::LocalTime); #ifndef QT_BOOTSTRAPPED - m_timeZone = QTimeZone(); + // If not valid time zone then is invalid + if (spec == Qt::TimeZone) { + if (!d->m_timeZone.isValid()) + status &= ~QDateTimePrivate::ValidDateTime; + else + epochMSecs = QDateTimePrivate::zoneMSecsToEpochMSecs(msecs, d->m_timeZone, &testDate, &testTime); + } #endif // QT_BOOTSTRAPPED - switch (spec) { - case Qt::OffsetFromUTC: - if (offsetSeconds == 0) { - m_spec = Qt::UTC; - m_offsetFromUtc = 0; + // If not valid date and time then is invalid + if (!(status & QDateTimePrivate::ValidDate) || !(status & QDateTimePrivate::ValidTime)) { + status &= ~QDateTimePrivate::ValidDateTime; + if (status & QDateTimePrivate::ShortData) { + d.data.status = status; } else { - m_spec = Qt::OffsetFromUTC; - m_offsetFromUtc = offsetSeconds; + d->m_status = status; + d->m_offsetFromUtc = 0; } + return; + } + + // We have a valid date and time and a Qt::LocalTime or Qt::TimeZone that needs calculating + // LocalTime and TimeZone might fall into a "missing" DST transition hour + // Calling toEpochMSecs will adjust the returned date/time if it does + if (spec == Qt::LocalTime) { + auto dstStatus = extractDaylightStatus(status); + epochMSecs = localMSecsToEpochMSecs(msecs, &dstStatus, &testDate, &testTime); + } + if (timeToMSecs(testDate, testTime) == msecs) { + status |= QDateTimePrivate::ValidDateTime; + // Cache the offset to use in offsetFromUtc() + offsetFromUtc = (msecs - epochMSecs) / 1000; + } else { + status &= ~QDateTimePrivate::ValidDateTime; + } + + if (status & QDateTimePrivate::ShortData) { + d.data.status = status; + } else { + d->m_status = status; + d->m_offsetFromUtc = offsetFromUtc; + } +} + +// Check the UTC / offsetFromUTC validity +static void checkValidDateTime(QDateTimeData &d) +{ + auto status = getStatus(d); + auto spec = extractSpec(status); + switch (spec) { + case Qt::OffsetFromUTC: + case Qt::UTC: + // for these, a valid date and a valid time imply a valid QDateTime + if ((status & QDateTimePrivate::ValidDate) && (status & QDateTimePrivate::ValidTime)) + status |= QDateTimePrivate::ValidDateTime; + else + status &= ~QDateTimePrivate::ValidDateTime; + if (status & QDateTimePrivate::ShortData) + d.data.status = status; + else + d->m_status = status; break; case Qt::TimeZone: - // Use system time zone instead - m_spec = Qt::LocalTime; - m_offsetFromUtc = 0; + case Qt::LocalTime: + // for these, we need to check whether the timezone is valid and whether + // the time is valid in that timezone. Expensive, but no other option. + refreshDateTime(d); + break; + } +} + +static void setTimeSpec(QDateTimeData &d, Qt::TimeSpec spec, int offsetSeconds) +{ + auto status = getStatus(d); + status &= ~(QDateTimePrivate::ValidDateTime | QDateTimePrivate::DaylightMask | + QDateTimePrivate::TimeSpecMask); + + switch (spec) { + case Qt::OffsetFromUTC: + if (offsetSeconds == 0) + spec = Qt::UTC; break; + case Qt::TimeZone: + // Use system time zone instead + spec = Qt::LocalTime; + Q_FALLTHROUGH(); case Qt::UTC: case Qt::LocalTime: - m_spec = spec; - m_offsetFromUtc = 0; + offsetSeconds = 0; break; } + + status = mergeSpec(status, spec); + if (d.isShort() && offsetSeconds == 0) { + d.data.status = status; + } else { + d.detach(); + d->m_status = status & ~QDateTimePrivate::ShortData; + d->m_offsetFromUtc = offsetSeconds; +#ifndef QT_BOOTSTRAPPED + d->m_timeZone = QTimeZone(); +#endif // QT_BOOTSTRAPPED + } } -void QDateTimePrivate::setDateTime(const QDate &date, const QTime &time) +static void setDateTime(QDateTimeData &d, const QDate &date, const QTime &time) { // If the date is valid and the time is not we set time to 00:00:00 QTime useTime = time; if (!useTime.isValid() && date.isValid()) useTime = QTime::fromMSecsSinceStartOfDay(0); - StatusFlags newStatus; + QDateTimePrivate::StatusFlags newStatus = 0; // Set date value and status qint64 days = 0; if (date.isValid()) { days = date.toJulianDay() - JULIAN_DAY_FOR_EPOCH; - newStatus = ValidDate; - } else if (date.isNull()) { - newStatus = NullDate; + newStatus = QDateTimePrivate::ValidDate; } // Set time value and status int ds = 0; if (useTime.isValid()) { ds = useTime.msecsSinceStartOfDay(); - newStatus |= ValidTime; - } else if (time.isNull()) { - newStatus |= NullTime; + newStatus |= QDateTimePrivate::ValidTime; } // Set msecs serial value - m_msecs = (days * MSECS_PER_DAY) + ds; - m_status = newStatus; + qint64 msecs = (days * MSECS_PER_DAY) + ds; + if (d.isShort()) { + // let's see if we can keep this short + if (msecsCanBeSmall(msecs)) { + // yes, we can + d.data.msecs = qintptr(msecs); + d.data.status &= ~(QDateTimePrivate::ValidityMask | QDateTimePrivate::DaylightMask); + d.data.status |= newStatus; + } else { + // nope... + d.detach(); + } + } + if (!d.isShort()) { + d.detach(); + d->m_msecs = msecs; + d->m_status &= ~(QDateTimePrivate::ValidityMask | QDateTimePrivate::DaylightMask); + d->m_status |= newStatus; + } // Set if date and time are valid - checkValidDateTime(); + checkValidDateTime(d); } -QPair<QDate, QTime> QDateTimePrivate::getDateTime() const +static QPair<QDate, QTime> getDateTime(const QDateTimeData &d) { QPair<QDate, QTime> result; - msecsToTime(m_msecs, &result.first, &result.second); + qint64 msecs = getMSecs(d); + auto status = getStatus(d); + msecsToTime(msecs, &result.first, &result.second); - if (isNullDate()) + if (!status.testFlag(QDateTimePrivate::ValidDate)) result.first = QDate(); - if (isNullTime()) + if (!status.testFlag(QDateTimePrivate::ValidTime)) result.second = QTime(); return result; } -// Set the Daylight Status if LocalTime set via msecs -void QDateTimePrivate::setDaylightStatus(QDateTimePrivate::DaylightStatus status) -{ - if (status == DaylightTime) { - m_status = m_status & ~SetToStandardTime; - m_status = m_status | SetToDaylightTime; - } else if (status == StandardTime) { - m_status = m_status & ~SetToDaylightTime; - m_status = m_status | SetToStandardTime; +/***************************************************************************** + QDateTime::Data member functions + *****************************************************************************/ + +inline QDateTime::Data::Data() +{ + // default-constructed data has a special exception: + // it can be small even if CanBeSmall == false + // (optimization so we don't allocate memory in the default constructor) + quintptr value = quintptr(mergeSpec(QDateTimePrivate::ShortData, Qt::LocalTime)); + d = reinterpret_cast<QDateTimePrivate *>(value); +} + +inline QDateTime::Data::Data(Qt::TimeSpec spec) +{ + if (CanBeSmall && Q_LIKELY(specCanBeSmall(spec))) { + d = reinterpret_cast<QDateTimePrivate *>(quintptr(mergeSpec(QDateTimePrivate::ShortData, spec))); } else { - clearSetToDaylightStatus(); + // the structure is too small, we need to detach + d = new QDateTimePrivate; + d->ref.ref(); + d->m_status = mergeSpec(0, spec); } } -// Get the DST Status if LocalTime set via msecs -QDateTimePrivate::DaylightStatus QDateTimePrivate::daylightStatus() const +inline QDateTime::Data::Data(const Data &other) + : d(other.d) { - if ((m_status & SetToDaylightTime) == SetToDaylightTime) - return DaylightTime; - if ((m_status & SetToStandardTime) == SetToStandardTime) - return StandardTime; - return UnknownDaylightTime; + if (!isShort()) { + // check if we could shrink + if (specCanBeSmall(extractSpec(d->m_status)) && msecsCanBeSmall(d->m_msecs)) { + ShortData sd; + sd.msecs = qintptr(d->m_msecs); + sd.status = d->m_status | QDateTimePrivate::ShortData; + data = sd; + } else { + // no, have to keep it big + d->ref.ref(); + } + } } -qint64 QDateTimePrivate::toMSecsSinceEpoch() const +inline QDateTime::Data::Data(Data &&other) + : d(other.d) { - switch (m_spec) { - case Qt::OffsetFromUTC: - case Qt::UTC: - return (m_msecs - (m_offsetFromUtc * 1000)); + // reset the other to a short state + Data dummy; + Q_ASSERT(dummy.isShort()); + other.d = dummy.d; +} - case Qt::LocalTime: { - // recalculate the local timezone - DaylightStatus status = daylightStatus(); - return localMSecsToEpochMSecs(m_msecs, &status); - } +inline QDateTime::Data &QDateTime::Data::operator=(const Data &other) +{ + if (d == other.d) + return *this; - case Qt::TimeZone: -#ifdef QT_BOOTSTRAPPED - return 0; -#else - return zoneMSecsToEpochMSecs(m_msecs, m_timeZone); -#endif + auto x = d; + d = other.d; + if (!other.isShort()) { + // check if we could shrink + if (specCanBeSmall(extractSpec(other.d->m_status)) && msecsCanBeSmall(other.d->m_msecs)) { + ShortData sd; + sd.msecs = qintptr(other.d->m_msecs); + sd.status = other.d->m_status | QDateTimePrivate::ShortData; + data = sd; + } else { + // no, have to keep it big + other.d->ref.ref(); + } } - Q_UNREACHABLE(); - return 0; + + if (!(quintptr(x) & QDateTimePrivate::ShortData) && !x->ref.deref()) + delete x; + return *this; } -// Check the UTC / offsetFromUTC validity -void QDateTimePrivate::checkValidDateTime() +inline QDateTime::Data::~Data() { - switch (m_spec) { - case Qt::OffsetFromUTC: - case Qt::UTC: - // for these, a valid date and a valid time imply a valid QDateTime - if (isValidDate() && isValidTime()) - setValidDateTime(); - else - clearValidDateTime(); - break; - case Qt::TimeZone: - case Qt::LocalTime: - // for these, we need to check whether the timezone is valid and whether - // the time is valid in that timezone. Expensive, but no other option. - refreshDateTime(); - break; - } + if (!isShort() && !d->ref.deref()) + delete d; } -// Refresh the LocalTime validity and offset -void QDateTimePrivate::refreshDateTime() +inline bool QDateTime::Data::isShort() const { - switch (m_spec) { - case Qt::OffsetFromUTC: - case Qt::UTC: - // Always set by setDateTime so just return - return; - case Qt::TimeZone: - case Qt::LocalTime: - break; - } - - // If not valid date and time then is invalid - if (!isValidDate() || !isValidTime()) { - clearValidDateTime(); - m_offsetFromUtc = 0; - return; - } + bool b = quintptr(d) & QDateTimePrivate::ShortData; -#ifndef QT_BOOTSTRAPPED - // If not valid time zone then is invalid - if (m_spec == Qt::TimeZone && !m_timeZone.isValid()) { - clearValidDateTime(); - m_offsetFromUtc = 0; - return; - } -#endif // QT_BOOTSTRAPPED + // even if CanBeSmall = false, we have short data for a default-constructed + // QDateTime object. But it's unlikely. + if (CanBeSmall) + return Q_LIKELY(b); + return Q_UNLIKELY(b); +} - // We have a valid date and time and a Qt::LocalTime or Qt::TimeZone that needs calculating - // LocalTime and TimeZone might fall into a "missing" DST transition hour - // Calling toEpochMSecs will adjust the returned date/time if it does - QDate testDate; - QTime testTime; - qint64 epochMSecs = 0; - if (m_spec == Qt::LocalTime) { - DaylightStatus status = daylightStatus(); - epochMSecs = localMSecsToEpochMSecs(m_msecs, &status, &testDate, &testTime); -#ifndef QT_BOOTSTRAPPED - } else { - epochMSecs = zoneMSecsToEpochMSecs(m_msecs, m_timeZone, &testDate, &testTime); -#endif // QT_BOOTSTRAPPED - } - if (timeToMSecs(testDate, testTime) == m_msecs) { - setValidDateTime(); - // Cache the offset to use in toMSecsSinceEpoch() - m_offsetFromUtc = (m_msecs - epochMSecs) / 1000; +inline void QDateTime::Data::detach() +{ + QDateTimePrivate *x; + bool wasShort = isShort(); + if (wasShort) { + // force enlarging + x = new QDateTimePrivate; + x->m_status = QDateTimePrivate::StatusFlag(data.status & ~QDateTimePrivate::ShortData); + x->m_msecs = data.msecs; } else { - clearValidDateTime(); - m_offsetFromUtc = 0; + if (d->ref.load() == 1) + return; + + x = new QDateTimePrivate(*d); } + + x->ref.store(1); + if (!wasShort && !d->ref.deref()) + delete d; + d = x; +} + +inline const QDateTimePrivate *QDateTime::Data::operator->() const +{ + Q_ASSERT(!isShort()); + return d; +} + +inline QDateTimePrivate *QDateTime::Data::operator->() +{ + // should we attempt to detach here? + Q_ASSERT(!isShort()); + Q_ASSERT(d->ref.load() == 1); + return d; +} + +/***************************************************************************** + QDateTimePrivate member functions + *****************************************************************************/ + +Q_NEVER_INLINE +QDateTime::Data QDateTimePrivate::create(const QDate &toDate, const QTime &toTime, Qt::TimeSpec toSpec, + int offsetSeconds) +{ + QDateTime::Data result(toSpec); + setTimeSpec(result, toSpec, offsetSeconds); + setDateTime(result, toDate, toTime); + return result; } #ifndef QT_BOOTSTRAPPED +inline QDateTime::Data QDateTimePrivate::create(const QDate &toDate, const QTime &toTime, + const QTimeZone &toTimeZone) +{ + QDateTime::Data result(Qt::TimeZone); + Q_ASSERT(!result.isShort()); + + result.d->m_status = mergeSpec(result.d->m_status, Qt::TimeZone); + result.d->m_timeZone = toTimeZone; + setDateTime(result, toDate, toTime); + return result; +} + // Convert a TimeZone time expressed in zone msecs encoding into a UTC epoch msecs -qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QTimeZone &zone, - QDate *localDate, QTime *localTime) +inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QTimeZone &zone, + QDate *localDate, QTime *localTime) { // Get the effective data from QTimeZone QTimeZonePrivate::Data data = zone.d->dataForLocalTime(zoneMSecs); @@ -2961,8 +3052,7 @@ qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QTimeZone \sa isValid() */ -QDateTime::QDateTime() - : d(*defaultDateTimePrivate()) +QDateTime::QDateTime() Q_DECL_NOEXCEPT_EXPR(Data::CanBeSmall) { } @@ -2973,7 +3063,7 @@ QDateTime::QDateTime() */ QDateTime::QDateTime(const QDate &date) - : d(new QDateTimePrivate(date, QTime(0, 0, 0), Qt::LocalTime, 0)) + : d(QDateTimePrivate::create(date, QTime(0, 0, 0), Qt::LocalTime, 0)) { } @@ -2993,7 +3083,7 @@ QDateTime::QDateTime(const QDate &date) */ QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec) - : d(new QDateTimePrivate(date, time, spec, 0)) + : d(QDateTimePrivate::create(date, time, spec, 0)) { } @@ -3016,7 +3106,7 @@ QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec) */ QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec, int offsetSeconds) - : d(new QDateTimePrivate(date, time, spec, offsetSeconds)) + : d(QDateTimePrivate::create(date, time, spec, offsetSeconds)) { } @@ -3033,7 +3123,7 @@ QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec, in */ QDateTime::QDateTime(const QDate &date, const QTime &time, const QTimeZone &timeZone) - : d(new QDateTimePrivate(date, time, timeZone)) + : d(QDateTimePrivate::create(date, time, timeZone)) { } #endif // QT_BOOTSTRAPPED @@ -3041,13 +3131,22 @@ QDateTime::QDateTime(const QDate &date, const QTime &time, const QTimeZone &time /*! Constructs a copy of the \a other datetime. */ - -QDateTime::QDateTime(const QDateTime &other) +QDateTime::QDateTime(const QDateTime &other) Q_DECL_NOTHROW : d(other.d) { } /*! + \since 5.8 + Moves the content of the temporary \a other datetime to this object and + leaves \a other in an unspecified (but proper) state. +*/ +QDateTime::QDateTime(QDateTime &&other) Q_DECL_NOTHROW + : d(std::move(other.d)) +{ +} + +/*! Destroys the datetime. */ QDateTime::~QDateTime() @@ -3059,7 +3158,7 @@ QDateTime::~QDateTime() copy. */ -QDateTime &QDateTime::operator=(const QDateTime &other) +QDateTime &QDateTime::operator=(const QDateTime &other) Q_DECL_NOTHROW { d = other.d; return *this; @@ -3081,7 +3180,9 @@ QDateTime &QDateTime::operator=(const QDateTime &other) bool QDateTime::isNull() const { - return d->isNullDate() && d->isNullTime(); + auto status = getStatus(d); + return !status.testFlag(QDateTimePrivate::ValidDate) && + !status.testFlag(QDateTimePrivate::ValidTime); } /*! @@ -3098,7 +3199,8 @@ bool QDateTime::isNull() const bool QDateTime::isValid() const { - return (d->isValidDateTime()); + auto status = getStatus(d); + return status & QDateTimePrivate::ValidDateTime; } /*! @@ -3109,10 +3211,11 @@ bool QDateTime::isValid() const QDate QDateTime::date() const { - if (d->isNullDate()) + auto status = getStatus(d); + if (!status.testFlag(QDateTimePrivate::ValidDate)) return QDate(); QDate dt; - msecsToTime(d->m_msecs, &dt, 0); + msecsToTime(getMSecs(d), &dt, 0); return dt; } @@ -3124,10 +3227,11 @@ QDate QDateTime::date() const QTime QDateTime::time() const { - if (d->isNullTime()) + auto status = getStatus(d); + if (!status.testFlag(QDateTimePrivate::ValidTime)) return QTime(); QTime tm; - msecsToTime(d->m_msecs, 0, &tm); + msecsToTime(getMSecs(d), 0, &tm); return tm; } @@ -3139,7 +3243,7 @@ QTime QDateTime::time() const Qt::TimeSpec QDateTime::timeSpec() const { - return d->m_spec; + return getSpec(d); } #ifndef QT_BOOTSTRAPPED @@ -3157,7 +3261,7 @@ Qt::TimeSpec QDateTime::timeSpec() const QTimeZone QDateTime::timeZone() const { - switch (d->m_spec) { + switch (getSpec(d)) { case Qt::UTC: return QTimeZone::utc(); case Qt::OffsetFromUTC: @@ -3192,7 +3296,20 @@ QTimeZone QDateTime::timeZone() const int QDateTime::offsetFromUtc() const { - return d->m_offsetFromUtc; + if (!d.isShort()) + return d->m_offsetFromUtc; + if (!isValid()) + return 0; + + auto spec = getSpec(d); + if (spec == Qt::LocalTime) { + // we didn't cache the value, so we need to calculate it now... + qint64 msecs = getMSecs(d); + return (msecs - toMSecsSinceEpoch()) / 1000; + } + + Q_ASSERT(spec == Qt::UTC); + return 0; } /*! @@ -3218,7 +3335,7 @@ int QDateTime::offsetFromUtc() const QString QDateTime::timeZoneAbbreviation() const { - switch (d->m_spec) { + switch (getSpec(d)) { case Qt::UTC: return QTimeZonePrivate::utcQString(); case Qt::OffsetFromUTC: @@ -3227,12 +3344,12 @@ QString QDateTime::timeZoneAbbreviation() const #ifdef QT_BOOTSTRAPPED break; #else - return d->m_timeZone.d->abbreviation(d->toMSecsSinceEpoch()); + return d->m_timeZone.d->abbreviation(toMSecsSinceEpoch()); #endif // QT_BOOTSTRAPPED case Qt::LocalTime: { QString abbrev; - QDateTimePrivate::DaylightStatus status = d->daylightStatus(); - localMSecsToEpochMSecs(d->m_msecs, &status, 0, 0, &abbrev); + auto status = extractDaylightStatus(getStatus(d)); + localMSecsToEpochMSecs(getMSecs(d), &status, 0, 0, &abbrev); return abbrev; } } @@ -3252,7 +3369,7 @@ QString QDateTime::timeZoneAbbreviation() const bool QDateTime::isDaylightTime() const { - switch (d->m_spec) { + switch (getSpec(d)) { case Qt::UTC: case Qt::OffsetFromUTC: return false; @@ -3263,9 +3380,9 @@ bool QDateTime::isDaylightTime() const return d->m_timeZone.d->isDaylightTime(toMSecsSinceEpoch()); #endif // QT_BOOTSTRAPPED case Qt::LocalTime: { - QDateTimePrivate::DaylightStatus status = d->daylightStatus(); + auto status = extractDaylightStatus(getStatus(d)); if (status == QDateTimePrivate::UnknownDaylightTime) - localMSecsToEpochMSecs(d->m_msecs, &status); + localMSecsToEpochMSecs(getMSecs(d), &status); return (status == QDateTimePrivate::DaylightTime); } } @@ -3281,7 +3398,7 @@ bool QDateTime::isDaylightTime() const void QDateTime::setDate(const QDate &date) { - d->setDateTime(date, time()); + setDateTime(d, date, time()); } /*! @@ -3299,7 +3416,7 @@ void QDateTime::setDate(const QDate &date) void QDateTime::setTime(const QTime &time) { - d->setDateTime(date(), time); + setDateTime(d, date(), time); } /*! @@ -3320,9 +3437,8 @@ void QDateTime::setTime(const QTime &time) void QDateTime::setTimeSpec(Qt::TimeSpec spec) { - QDateTimePrivate *d = this->d.data(); // detaches (and shadows d) - d->setTimeSpec(spec, 0); - d->checkValidDateTime(); + QT_PREPEND_NAMESPACE(setTimeSpec(d, spec, 0)); + checkValidDateTime(d); } /*! @@ -3342,9 +3458,8 @@ void QDateTime::setTimeSpec(Qt::TimeSpec spec) void QDateTime::setOffsetFromUtc(int offsetSeconds) { - QDateTimePrivate *d = this->d.data(); // detaches (and shadows d) - d->setTimeSpec(Qt::OffsetFromUTC, offsetSeconds); - d->checkValidDateTime(); + QT_PREPEND_NAMESPACE(setTimeSpec(d, Qt::OffsetFromUTC, offsetSeconds)); + checkValidDateTime(d); } #ifndef QT_BOOTSTRAPPED @@ -3361,11 +3476,11 @@ void QDateTime::setOffsetFromUtc(int offsetSeconds) void QDateTime::setTimeZone(const QTimeZone &toZone) { - QDateTimePrivate *d = this->d.data(); // detaches (and shadows d) - d->m_spec = Qt::TimeZone; + d.detach(); // always detach + d->m_status = mergeSpec(d->m_status, Qt::TimeZone); d->m_offsetFromUtc = 0; d->m_timeZone = toZone; - d->refreshDateTime(); + refreshDateTime(d); } #endif // QT_BOOTSTRAPPED @@ -3382,44 +3497,85 @@ void QDateTime::setTimeZone(const QTimeZone &toZone) this object is not valid. However, for all valid dates, this function returns a unique value. - \sa toTime_t(), setMSecsSinceEpoch() + \sa toSecsSinceEpoch(), setMSecsSinceEpoch() */ qint64 QDateTime::toMSecsSinceEpoch() const { - return d->toMSecsSinceEpoch(); + switch (getSpec(d)) { + case Qt::UTC: + return getMSecs(d); + + case Qt::OffsetFromUTC: + return d->m_msecs - (d->m_offsetFromUtc * 1000); + + case Qt::LocalTime: { + // recalculate the local timezone + auto status = extractDaylightStatus(getStatus(d)); + return localMSecsToEpochMSecs(getMSecs(d), &status); + } + + case Qt::TimeZone: +#ifdef QT_BOOTSTRAPPED + return 0; +#else + return QDateTimePrivate::zoneMSecsToEpochMSecs(d->m_msecs, d->m_timeZone); +#endif + } + Q_UNREACHABLE(); + return 0; +} + +/*! + \since 5.8 + + Returns the datetime as the number of seconds that have passed since + 1970-01-01T00:00:00.000, Coordinated Universal Time (Qt::UTC). + + On systems that do not support time zones, this function will + behave as if local time were Qt::UTC. + + The behavior for this function is undefined if the datetime stored in + this object is not valid. However, for all valid dates, this function + returns a unique value. + + \sa toMSecsSinceEpoch(), setSecsSinceEpoch() +*/ +qint64 QDateTime::toSecsSinceEpoch() const +{ + return toMSecsSinceEpoch() / 1000; } +#if QT_DEPRECATED_SINCE(5, 8) /*! + \deprecated + Returns the datetime as the number of seconds that have passed since 1970-01-01T00:00:00, Coordinated Universal Time (Qt::UTC). On systems that do not support time zones, this function will behave as if local time were Qt::UTC. - \note This function returns a 32-bit unsigned integer, so it does not - support dates before 1970, but it does support dates after - 2038-01-19T03:14:06, which may not be valid time_t values. Be careful - when passing those time_t values to system functions, which could - interpret them as negative dates. + \note This function returns a 32-bit unsigned integer and is deprecated. If the date is outside the range 1970-01-01T00:00:00 to 2106-02-07T06:28:14, this function returns -1 cast to an unsigned integer (i.e., 0xFFFFFFFF). - To get an extended range, use toMSecsSinceEpoch(). + To get an extended range, use toMSecsSinceEpoch() or toSecsSinceEpoch(). - \sa toMSecsSinceEpoch(), setTime_t() + \sa toSecsSinceEpoch(), toMSecsSinceEpoch(), setTime_t() */ uint QDateTime::toTime_t() const { if (!isValid()) return uint(-1); - qint64 retval = d->toMSecsSinceEpoch() / 1000; + qint64 retval = toMSecsSinceEpoch() / 1000; if (quint64(retval) >= Q_UINT64_C(0xFFFFFFFF)) return uint(-1); return uint(retval); } +#endif /*! \since 4.7 @@ -3433,65 +3589,98 @@ uint QDateTime::toTime_t() const (\c{std::numeric_limits<qint64>::min()}) to \a msecs will result in undefined behavior. - \sa toMSecsSinceEpoch(), setTime_t() + \sa toMSecsSinceEpoch(), setSecsSinceEpoch() */ void QDateTime::setMSecsSinceEpoch(qint64 msecs) { - QDateTimePrivate *d = this->d.data(); // detaches (and shadows d) + const auto spec = getSpec(d); + auto status = getStatus(d); - d->m_status = 0; - switch (d->m_spec) { + status &= ~QDateTimePrivate::ValidityMask; + switch (spec) { case Qt::UTC: - d->m_msecs = msecs; - d->m_status = d->m_status + status = status | QDateTimePrivate::ValidDate | QDateTimePrivate::ValidTime | QDateTimePrivate::ValidDateTime; break; case Qt::OffsetFromUTC: - d->m_msecs = msecs + (d->m_offsetFromUtc * 1000); - d->m_status = d->m_status + msecs = msecs + (d->m_offsetFromUtc * 1000); + status = status | QDateTimePrivate::ValidDate | QDateTimePrivate::ValidTime | QDateTimePrivate::ValidDateTime; break; case Qt::TimeZone: + Q_ASSERT(!d.isShort()); #ifndef QT_BOOTSTRAPPED // Docs state any LocalTime before 1970-01-01 will *not* have any DST applied // but all affected times afterwards will have DST applied. + d.detach(); if (msecs >= 0) d->m_offsetFromUtc = d->m_timeZone.d->offsetFromUtc(msecs); else d->m_offsetFromUtc = d->m_timeZone.d->standardTimeOffset(msecs); - d->m_msecs = msecs + (d->m_offsetFromUtc * 1000); - d->m_status = d->m_status + msecs = msecs + (d->m_offsetFromUtc * 1000); + status = status | QDateTimePrivate::ValidDate | QDateTimePrivate::ValidTime | QDateTimePrivate::ValidDateTime; - d->refreshDateTime(); #endif // QT_BOOTSTRAPPED break; case Qt::LocalTime: { QDate dt; QTime tm; - QDateTimePrivate::DaylightStatus status; - epochMSecsToLocalTime(msecs, &dt, &tm, &status); - d->setDateTime(dt, tm); - d->setDaylightStatus(status); - d->refreshDateTime(); + QDateTimePrivate::DaylightStatus dstStatus; + epochMSecsToLocalTime(msecs, &dt, &tm, &dstStatus); + setDateTime(d, dt, tm); + msecs = getMSecs(d); + status = mergeDaylightStatus(getStatus(d), dstStatus); break; } } + + if (msecsCanBeSmall(msecs) && d.isShort()) { + // we can keep short + d.data.msecs = qintptr(msecs); + d.data.status = status; + } else { + d.detach(); + d->m_status = status; + d->m_msecs = msecs; + } + + if (spec == Qt::LocalTime || spec == Qt::TimeZone) + refreshDateTime(d); } /*! + \since 5.8 + + Sets the date and time given the number of seconds \a secs that have + passed since 1970-01-01T00:00:00.000, Coordinated Universal Time + (Qt::UTC). On systems that do not support time zones this function + will behave as if local time were Qt::UTC. + + \sa toSecsSinceEpoch(), setMSecsSinceEpoch() +*/ +void QDateTime::setSecsSinceEpoch(qint64 secs) +{ + setMSecsSinceEpoch(secs * 1000); +} + +#if QT_DEPRECATED_SINCE(5, 8) +/*! \fn void QDateTime::setTime_t(uint seconds) + \deprecated Sets the date and time given the number of \a seconds that have passed since 1970-01-01T00:00:00, Coordinated Universal Time (Qt::UTC). On systems that do not support time zones this function will behave as if local time were Qt::UTC. + \note This function is deprecated. For new code, use setSecsSinceEpoch(). + \sa toTime_t() */ @@ -3499,6 +3688,7 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC) { setMSecsSinceEpoch((qint64)secsSince1Jan1970UTC * 1000); } +#endif #ifndef QT_NO_DATESTRING /*! @@ -3569,13 +3759,13 @@ QString QDateTime::toString(Qt::DateFormat format) const return QLocale().toString(*this, QLocale::LongFormat); case Qt::RFC2822Date: { buf = QLocale::c().toString(*this, QStringLiteral("dd MMM yyyy hh:mm:ss ")); - buf += toOffsetString(Qt::TextDate, d->m_offsetFromUtc); + buf += toOffsetString(Qt::TextDate, offsetFromUtc()); return buf; } default: #ifndef QT_NO_TEXTDATE case Qt::TextDate: { - const QPair<QDate, QTime> p = d->getDateTime(); + const QPair<QDate, QTime> p = getDateTime(d); const QDate &dt = p.first; const QTime &tm = p.second; //We cant use date.toString(Qt::TextDate) as we need to insert the time before the year @@ -3586,14 +3776,14 @@ QString QDateTime::toString(Qt::DateFormat format) const .arg(dt.year()); if (timeSpec() != Qt::LocalTime) { buf += QLatin1String(" GMT"); - if (d->m_spec == Qt::OffsetFromUTC) - buf += toOffsetString(Qt::TextDate, d->m_offsetFromUtc); + if (getSpec(d) == Qt::OffsetFromUTC) + buf += toOffsetString(Qt::TextDate, offsetFromUtc()); } return buf; } #endif case Qt::ISODate: { - const QPair<QDate, QTime> p = d->getDateTime(); + const QPair<QDate, QTime> p = getDateTime(d); const QDate &dt = p.first; const QTime &tm = p.second; buf = dt.toString(Qt::ISODate); @@ -3601,12 +3791,12 @@ QString QDateTime::toString(Qt::DateFormat format) const return QString(); // failed to convert buf += QLatin1Char('T'); buf += tm.toString(Qt::ISODate); - switch (d->m_spec) { + switch (getSpec(d)) { case Qt::UTC: buf += QLatin1Char('Z'); break; case Qt::OffsetFromUTC: - buf += toOffsetString(Qt::ISODate, d->m_offsetFromUtc); + buf += toOffsetString(Qt::ISODate, offsetFromUtc()); break; default: break; @@ -3695,12 +3885,7 @@ QString QDateTime::toString(const QString& format) const } #endif //QT_NO_DATESTRING -static void massageAdjustedDateTime(Qt::TimeSpec spec, -#ifndef QT_BOOTSTRAPPED - const QTimeZone &zone, -#endif // QT_BOOTSTRAPPED - QDate *date, - QTime *time) +static inline void massageAdjustedDateTime(const QDateTimeData &d, QDate *date, QTime *time) { /* If we have just adjusted to a day with a DST transition, our given time @@ -3710,24 +3895,20 @@ static void massageAdjustedDateTime(Qt::TimeSpec spec, to its DST-ness); but for a time in spring's missing hour it'll adjust the time while picking a DST-ness. (Handling of autumn is trickier, as either DST-ness is valid, without adjusting the time. We might want to propagate - d->daylightStatus() in that case, but it's hard to do so without breaking + the daylight status in that case, but it's hard to do so without breaking (far more common) other cases; and it makes little difference, as the two answers do then differ only in DST-ness.) */ + auto spec = getSpec(d); if (spec == Qt::LocalTime) { QDateTimePrivate::DaylightStatus status = QDateTimePrivate::UnknownDaylightTime; localMSecsToEpochMSecs(timeToMSecs(*date, *time), &status, date, time); #ifndef QT_BOOTSTRAPPED } else if (spec == Qt::TimeZone) { - QDateTimePrivate::zoneMSecsToEpochMSecs(timeToMSecs(*date, *time), zone, date, time); + QDateTimePrivate::zoneMSecsToEpochMSecs(timeToMSecs(*date, *time), d->m_timeZone, date, time); #endif // QT_BOOTSTRAPPED } } -#ifdef QT_BOOTSTRAPPED // Avoid duplicate #if-ery in uses. -#define MASSAGEADJUSTEDDATETIME(s, z, d, t) massageAdjustedDateTime(s, d, t) -#else -#define MASSAGEADJUSTEDDATETIME(s, z, d, t) massageAdjustedDateTime(s, z, d, t) -#endif // QT_BOOTSTRAPPED /*! Returns a QDateTime object containing a datetime \a ndays days @@ -3746,12 +3927,12 @@ static void massageAdjustedDateTime(Qt::TimeSpec spec, QDateTime QDateTime::addDays(qint64 ndays) const { QDateTime dt(*this); - QPair<QDate, QTime> p = d->getDateTime(); + QPair<QDate, QTime> p = getDateTime(d); QDate &date = p.first; QTime &time = p.second; date = date.addDays(ndays); - MASSAGEADJUSTEDDATETIME(d->m_spec, d->m_timeZone, &date, &time); - dt.d->setDateTime(date, time); + massageAdjustedDateTime(dt.d, &date, &time); + setDateTime(dt.d, date, time); return dt; } @@ -3772,12 +3953,12 @@ QDateTime QDateTime::addDays(qint64 ndays) const QDateTime QDateTime::addMonths(int nmonths) const { QDateTime dt(*this); - QPair<QDate, QTime> p = d->getDateTime(); + QPair<QDate, QTime> p = getDateTime(d); QDate &date = p.first; QTime &time = p.second; date = date.addMonths(nmonths); - MASSAGEADJUSTEDDATETIME(d->m_spec, d->m_timeZone, &date, &time); - dt.d->setDateTime(date, time); + massageAdjustedDateTime(dt.d, &date, &time); + setDateTime(dt.d, date, time); return dt; } @@ -3798,15 +3979,14 @@ QDateTime QDateTime::addMonths(int nmonths) const QDateTime QDateTime::addYears(int nyears) const { QDateTime dt(*this); - QPair<QDate, QTime> p = d->getDateTime(); + QPair<QDate, QTime> p = getDateTime(d); QDate &date = p.first; QTime &time = p.second; date = date.addYears(nyears); - MASSAGEADJUSTEDDATETIME(d->m_spec, d->m_timeZone, &date, &time); - dt.d->setDateTime(date, time); + massageAdjustedDateTime(dt.d, &date, &time); + setDateTime(dt.d, date, time); return dt; } -#undef MASSAGEADJUSTEDDATETIME /*! Returns a QDateTime object containing a datetime \a s seconds @@ -3838,12 +4018,26 @@ QDateTime QDateTime::addMSecs(qint64 msecs) const return QDateTime(); QDateTime dt(*this); - if (d->m_spec == Qt::LocalTime || d->m_spec == Qt::TimeZone) + auto spec = getSpec(d); + if (spec == Qt::LocalTime || spec == Qt::TimeZone) { // Convert to real UTC first in case crosses DST transition - dt.setMSecsSinceEpoch(d->toMSecsSinceEpoch() + msecs); - else + dt.setMSecsSinceEpoch(toMSecsSinceEpoch() + msecs); + } else { // No need to convert, just add on - dt.d->m_msecs = dt.d->m_msecs + msecs; + if (d.isShort()) { + // need to check if we need to enlarge first + msecs += dt.d.data.msecs; + if (msecsCanBeSmall(msecs)) { + dt.d.data.msecs = qintptr(msecs); + } else { + dt.d.detach(); + dt.d->m_msecs = msecs; + } + } else { + dt.d.detach(); + dt.d->m_msecs += msecs; + } + } return dt; } @@ -3909,7 +4103,7 @@ qint64 QDateTime::msecsTo(const QDateTime &other) const if (!isValid() || !other.isValid()) return 0; - return other.d->toMSecsSinceEpoch() - d->toMSecsSinceEpoch(); + return other.toMSecsSinceEpoch() - toMSecsSinceEpoch(); } /*! @@ -3932,7 +4126,7 @@ qint64 QDateTime::msecsTo(const QDateTime &other) const QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const { - if (d->m_spec == spec && (spec == Qt::UTC || spec == Qt::LocalTime)) + if (getSpec(d) == spec && (spec == Qt::UTC || spec == Qt::LocalTime)) return *this; if (!isValid()) { @@ -3941,7 +4135,7 @@ QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const return ret; } - return fromMSecsSinceEpoch(d->toMSecsSinceEpoch(), spec, 0); + return fromMSecsSinceEpoch(toMSecsSinceEpoch(), spec, 0); } /*! @@ -3959,7 +4153,8 @@ QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const { - if (d->m_spec == Qt::OffsetFromUTC && d->m_offsetFromUtc == offsetSeconds) + if (getSpec(d) == Qt::OffsetFromUTC + && d->m_offsetFromUtc == offsetSeconds) return *this; if (!isValid()) { @@ -3968,7 +4163,7 @@ QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const return ret; } - return fromMSecsSinceEpoch(d->toMSecsSinceEpoch(), Qt::OffsetFromUTC, offsetSeconds); + return fromMSecsSinceEpoch(toMSecsSinceEpoch(), Qt::OffsetFromUTC, offsetSeconds); } #ifndef QT_BOOTSTRAPPED @@ -3982,7 +4177,7 @@ QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const QDateTime QDateTime::toTimeZone(const QTimeZone &timeZone) const { - if (d->m_spec == Qt::TimeZone && d->m_timeZone == timeZone) + if (getSpec(d) == Qt::TimeZone && d->m_timeZone == timeZone) return *this; if (!isValid()) { @@ -3991,7 +4186,7 @@ QDateTime QDateTime::toTimeZone(const QTimeZone &timeZone) const return ret; } - return fromMSecsSinceEpoch(d->toMSecsSinceEpoch(), timeZone); + return fromMSecsSinceEpoch(toMSecsSinceEpoch(), timeZone); } #endif // QT_BOOTSTRAPPED @@ -4004,10 +4199,9 @@ QDateTime QDateTime::toTimeZone(const QTimeZone &timeZone) const bool QDateTime::operator==(const QDateTime &other) const { - if (d->m_spec == Qt::LocalTime - && other.d->m_spec == Qt::LocalTime - && d->m_status == other.d->m_status) { - return (d->m_msecs == other.d->m_msecs); + if (getSpec(d) == Qt::LocalTime + && getStatus(d) == getStatus(other.d)) { + return getMSecs(d) == getMSecs(other.d); } // Convert to UTC and compare return (toMSecsSinceEpoch() == other.toMSecsSinceEpoch()); @@ -4032,10 +4226,9 @@ bool QDateTime::operator==(const QDateTime &other) const bool QDateTime::operator<(const QDateTime &other) const { - if (d->m_spec == Qt::LocalTime - && other.d->m_spec == Qt::LocalTime - && d->m_status == other.d->m_status) { - return (d->m_msecs < other.d->m_msecs); + if (getSpec(d) == Qt::LocalTime + && getStatus(d) == getStatus(other.d)) { + return getMSecs(d) < getMSecs(other.d); } // Convert to UTC and compare return (toMSecsSinceEpoch() < other.toMSecsSinceEpoch()); @@ -4090,6 +4283,16 @@ bool QDateTime::operator<(const QDateTime &other) const \sa currentDateTime(), currentDateTimeUtc(), toTime_t(), toTimeSpec() */ +/*! + \fn qint64 QDateTime::currentSecsSinceEpoch() + \since 5.8 + + Returns the number of seconds since 1970-01-01T00:00:00 Universal + Coordinated Time. + + \sa currentMSecsSinceEpoch() +*/ + #if defined(Q_OS_WIN) static inline uint msecsFromDecomposed(int hour, int minute, int sec, int msec = 0) { @@ -4113,9 +4316,6 @@ QTime QTime::currentTime() memset(&st, 0, sizeof(SYSTEMTIME)); GetLocalTime(&st); ct.setHMS(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); -#if defined(Q_OS_WINCE) - ct.startTick = GetTickCount() % MSECS_PER_DAY; -#endif return ct; } @@ -4154,6 +4354,17 @@ qint64 QDateTime::currentMSecsSinceEpoch() Q_DECL_NOTHROW - julianDayFromDate(1970, 1, 1)) * Q_INT64_C(86400000); } +qint64 QDateTime::currentSecsSinceEpoch() Q_DECL_NOTHROW +{ + SYSTEMTIME st; + memset(&st, 0, sizeof(SYSTEMTIME)); + GetSystemTime(&st); + + return st.wHour * SECS_PER_HOUR + st.wMinute * SECS_PER_MIN + st.wSecond + + qint64(julianDayFromDate(st.wYear, st.wMonth, st.wDay) + - julianDayFromDate(1970, 1, 1)) * Q_INT64_C(86400); +} + #elif defined(Q_OS_UNIX) QDate QDate::currentDate() { @@ -4184,51 +4395,29 @@ qint64 QDateTime::currentMSecsSinceEpoch() Q_DECL_NOTHROW return qint64(tv.tv_sec) * Q_INT64_C(1000) + tv.tv_usec / 1000; } +qint64 QDateTime::currentSecsSinceEpoch() Q_DECL_NOTHROW +{ + struct timeval tv; + gettimeofday(&tv, 0); + return qint64(tv.tv_sec); +} #else #error "What system is this?" #endif -/*! \fn QDateTime QDateTime::fromCFDate(CFDateRef date) - \since 5.5 - - Constructs a new QDateTime containing a copy of the CFDate \a date. - - \sa toCFDate() -*/ - -/*! \fn CFDateRef QDateTime::toCFDate() const - \since 5.5 - - Creates a CFDate from a QDateTime. The caller owns the CFDate object - and is responsible for releasing it. - - \sa fromCFDate() -*/ - -/*! \fn QDateTime QDateTime::fromNSDate(const NSDate *date) - \since 5.5 - - Constructs a new QDateTime containing a copy of the NSDate \a date. - - \sa toNSDate() -*/ - -/*! \fn NSDate QDateTime::toNSDate() const - \since 5.5 - - Creates an NSDate from a QDateTime. The NSDate object is autoreleased. - - \sa fromNSDate() -*/ - +#if QT_DEPRECATED_SINCE(5, 8) /*! \since 4.2 + \deprecated Returns a datetime whose date and time are the number of \a seconds that have passed since 1970-01-01T00:00:00, Coordinated Universal Time (Qt::UTC) and converted to Qt::LocalTime. On systems that do not support time zones, the time will be set as if local time were Qt::UTC. + \note This function is deprecated. Please use fromSecsSinceEpoch() in new + code. + \sa toTime_t(), setTime_t() */ QDateTime QDateTime::fromTime_t(uint seconds) @@ -4238,6 +4427,7 @@ QDateTime QDateTime::fromTime_t(uint seconds) /*! \since 5.2 + \deprecated Returns a datetime whose date and time are the number of \a seconds that have passed since 1970-01-01T00:00:00, Coordinated Universal @@ -4247,6 +4437,9 @@ QDateTime QDateTime::fromTime_t(uint seconds) ignored. If the \a spec is Qt::OffsetFromUTC and the \a offsetSeconds is 0 then the spec will be set to Qt::UTC, i.e. an offset of 0 seconds. + \note This function is deprecated. Please use fromSecsSinceEpoch() in new + code. + \sa toTime_t(), setTime_t() */ QDateTime QDateTime::fromTime_t(uint seconds, Qt::TimeSpec spec, int offsetSeconds) @@ -4257,11 +4450,15 @@ QDateTime QDateTime::fromTime_t(uint seconds, Qt::TimeSpec spec, int offsetSecon #ifndef QT_BOOTSTRAPPED /*! \since 5.2 + \deprecated Returns a datetime whose date and time are the number of \a seconds that have passed since 1970-01-01T00:00:00, Coordinated Universal Time (Qt::UTC) and with the given \a timeZone. + \note This function is deprecated. Please use fromSecsSinceEpoch() in new + code. + \sa toTime_t(), setTime_t() */ QDateTime QDateTime::fromTime_t(uint seconds, const QTimeZone &timeZone) @@ -4269,6 +4466,7 @@ QDateTime QDateTime::fromTime_t(uint seconds, const QTimeZone &timeZone) return fromMSecsSinceEpoch((qint64)seconds * 1000, timeZone); } #endif +#endif // QT_DEPRECATED_SINCE(5, 8) /*! \since 4.7 @@ -4282,7 +4480,7 @@ QDateTime QDateTime::fromTime_t(uint seconds, const QTimeZone &timeZone) range of QDateTime, both negative and positive. The behavior of this function is undefined for those values. - \sa toTime_t(), setTime_t() + \sa toMSecsSinceEpoch(), setMSecsSinceEpoch() */ QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs) { @@ -4307,16 +4505,41 @@ QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs) If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime, i.e. the current system time zone. - \sa fromTime_t() + \sa toMSecsSinceEpoch(), setMSecsSinceEpoch() */ QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, Qt::TimeSpec spec, int offsetSeconds) { QDateTime dt; - dt.d->setTimeSpec(spec, offsetSeconds); + QT_PREPEND_NAMESPACE(setTimeSpec(dt.d, spec, offsetSeconds)); dt.setMSecsSinceEpoch(msecs); return dt; } +/*! + \since 5.8 + + Returns a datetime whose date and time are the number of seconds \a secs + that have passed since 1970-01-01T00:00:00.000, Coordinated Universal + Time (Qt::UTC) and converted to the given \a spec. + + Note that there are possible values for \a secs that lie outside the valid + range of QDateTime, both negative and positive. The behavior of this + function is undefined for those values. + + If the \a spec is not Qt::OffsetFromUTC then the \a offsetSeconds will be + ignored. If the \a spec is Qt::OffsetFromUTC and the \a offsetSeconds is 0 + then the spec will be set to Qt::UTC, i.e. an offset of 0 seconds. + + If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime, + i.e. the current system time zone. + + \sa toSecsSinceEpoch(), setSecsSinceEpoch() +*/ +QDateTime QDateTime::fromSecsSinceEpoch(qint64 secs, Qt::TimeSpec spec, int offsetSeconds) +{ + return fromMSecsSinceEpoch(secs * 1000, spec, offsetSeconds); +} + #ifndef QT_BOOTSTRAPPED /*! \since 5.2 @@ -4325,7 +4548,7 @@ QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, Qt::TimeSpec spec, int of that have passed since 1970-01-01T00:00:00.000, Coordinated Universal Time (Qt::UTC) and with the given \a timeZone. - \sa fromTime_t() + \sa fromSecsSinceEpoch() */ QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone) { @@ -4334,6 +4557,20 @@ QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone dt.setMSecsSinceEpoch(msecs); return dt; } + +/*! + \since 5.8 + + Returns a datetime whose date and time are the number of seconds \a secs + that have passed since 1970-01-01T00:00:00.000, Coordinated Universal + Time (Qt::UTC) and with the given \a timeZone. + + \sa fromMSecsSinceEpoch() +*/ +QDateTime QDateTime::fromSecsSinceEpoch(qint64 secs, const QTimeZone &timeZone) +{ + return fromMSecsSinceEpoch(secs * 1000, timeZone); +} #endif #if QT_DEPRECATED_SINCE(5, 2) @@ -4831,7 +5068,7 @@ QDataStream &operator<<(QDataStream &out, const QDateTime &dateTime) if (out.version() >= QDataStream::Qt_5_2) { // In 5.2 we switched to using Qt::TimeSpec and added offset support - dateAndTime = dateTime.d->getDateTime(); + dateAndTime = getDateTime(dateTime.d); out << dateAndTime << qint8(dateTime.timeSpec()); if (dateTime.timeSpec() == Qt::OffsetFromUTC) out << qint32(dateTime.offsetFromUtc()); @@ -4846,13 +5083,13 @@ QDataStream &operator<<(QDataStream &out, const QDateTime &dateTime) // This approach is wrong and should not be used again; it breaks // the guarantee that a deserialised local datetime is the same time // of day, regardless of which timezone it was serialised in. - dateAndTime = (dateTime.isValid() ? dateTime.toUTC() : dateTime).d->getDateTime(); + dateAndTime = getDateTime((dateTime.isValid() ? dateTime.toUTC() : dateTime).d); out << dateAndTime << qint8(dateTime.timeSpec()); } else if (out.version() >= QDataStream::Qt_4_0) { // From 4.0 to 5.1 (except 5.0) we used QDateTimePrivate::Spec - dateAndTime = dateTime.d->getDateTime(); + dateAndTime = getDateTime(dateTime.d); out << dateAndTime; switch (dateTime.timeSpec()) { case Qt::UTC: @@ -4872,7 +5109,7 @@ QDataStream &operator<<(QDataStream &out, const QDateTime &dateTime) } else { // version < QDataStream::Qt_4_0 // Before 4.0 there was no TimeSpec, only Qt::LocalTime was supported - dateAndTime = dateTime.d->getDateTime(); + dateAndTime = getDateTime(dateTime.d); out << dateAndTime; } |