diff options
-rw-r--r-- | src/corelib/io/qdatastream.cpp | 5 | ||||
-rw-r--r-- | src/corelib/io/qdatastream.h | 2 | ||||
-rw-r--r-- | src/corelib/tools/qdatetime.cpp | 457 | ||||
-rw-r--r-- | src/corelib/tools/qdatetime.h | 16 | ||||
-rw-r--r-- | src/corelib/tools/qdatetime_p.h | 20 | ||||
-rw-r--r-- | tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp | 3 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp | 349 |
7 files changed, 637 insertions, 215 deletions
diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp index 52b80badb8..008460df5d 100644 --- a/src/corelib/io/qdatastream.cpp +++ b/src/corelib/io/qdatastream.cpp @@ -539,8 +539,8 @@ void QDataStream::setByteOrder(ByteOrder bo) \value Qt_4_8 Same as Qt_4_6. \value Qt_4_9 Same as Qt_4_6. \value Qt_5_0 Version 13 (Qt 5.0) - \value Qt_5_1 Version 14 (Qt 5.1, Qt 5.2) - \value Qt_5_2 Same as Qt_5_1. + \value Qt_5_1 Version 14 (Qt 5.1) + \value Qt_5_2 Version 15 (Qt 5.2) \sa setVersion(), version() */ @@ -572,6 +572,7 @@ void QDataStream::setByteOrder(ByteOrder bo) \table \header \li Qt Version \li QDataStream Version + \row \li Qt 5.2 \li 15 \row \li Qt 5.1 \li 14 \row \li Qt 5.0 \li 13 \row \li Qt 4.6 \li 12 diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h index eb064b3fe2..f107e801b6 100644 --- a/src/corelib/io/qdatastream.h +++ b/src/corelib/io/qdatastream.h @@ -87,7 +87,7 @@ public: Qt_4_9 = Qt_4_8, Qt_5_0 = 13, Qt_5_1 = 14, - Qt_5_2 = Qt_5_1 + Qt_5_2 = 15 #if QT_VERSION >= 0x050300 #error Add the datastream version for this Qt version #endif diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index b47511c39c..da1f48a34c 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -172,6 +172,58 @@ int qt_monthNumberFromShortName(const QString &shortName) static QString fmtDateTime(const QString& f, const QTime* dt = 0, const QDate* dd = 0); static void rfcDateImpl(const QString &s, QDate *dd = 0, QTime *dt = 0, int *utfcOffset = 0); #endif +static QDateTimePrivate::Spec utcToLocal(QDate &date, QTime &time); +static void utcToOffset(QDate *date, QTime *time, qint32 offset); + +// Return offset in [+-]HH:MM format +// Qt::ISODate puts : between the hours and minutes, but Qt:TextDate does not +static QString toOffsetString(Qt::DateFormat format, int offset) +{ + QString result; + if (format == Qt::TextDate) + result = QStringLiteral("%1%2%3"); + else // Qt::ISODate + result = QStringLiteral("%1%2:%3"); + + return result.arg(offset >= 0 ? QLatin1Char('+') : QLatin1Char('-')) + .arg(qAbs(offset) / SECS_PER_HOUR, 2, 10, QLatin1Char('0')) + .arg((offset / 60) % 60, 2, 10, QLatin1Char('0')); +} + +// Parse offset in [+-]HH[:]MM format +static int fromOffsetString(const QString &offsetString, bool *valid) +{ + *valid = false; + + const int size = offsetString.size(); + if (size < 2 || size > 6) + return 0; + + // First char must be + or - + const QChar sign = offsetString.at(0); + if (sign != QLatin1Char('+') && sign != QLatin1Char('-')) + return 0; + + // Split the hour and minute parts + QStringList parts = offsetString.split(QLatin1Char(':')); + if (parts.count() == 1) { + // [+-]HHMM format + parts.append(parts.at(0).mid(3)); + parts[0] = parts.at(0).left(3); + } + + bool ok = false; + const int hour = parts.at(0).toInt(&ok); + if (!ok) + return 0; + + const int minute = parts.at(1).toInt(&ok); + if (!ok || minute < 0 || minute > 59) + return 0; + + *valid = true; + return ((hour * 60) + minute) * 60; +} /***************************************************************************** QDate member functions @@ -2165,6 +2217,20 @@ int QTime::elapsed() const time zone before 1970, even if the system's time zone database supports that information. + \section2 Offset From UTC + + A Qt::TimeSpec of Qt::OffsetFromUTC is also supported. This allows you + to define a QDateTime relative to UTC at a fixed offset of a given number + of seconds from UTC. For example, an offset of +3600 seconds is one hour + ahead of UTC and is usually written in ISO standard notation as + "UTC+01:00". Daylight Savings Time never applies with this TimeSpec. + + There is no explicit size restriction to the offset seconds, but there is + an implicit limit imposed when using the toString() and fromString() + methods which use a format of [+|-]hh:mm, effectively limiting the range + to +/- 99 hours and 59 minutes and whole minutes only. Note that currently + no time zone lies outside the range of +/- 14 hours. + \sa QDate, QTime, QDateTimeEdit */ @@ -2186,10 +2252,8 @@ QDateTime::QDateTime() */ QDateTime::QDateTime(const QDate &date) - : d(new QDateTimePrivate) + : d(new QDateTimePrivate(date, QTime(0, 0, 0), Qt::LocalTime, 0)) { - d->date = date; - d->time = QTime(0, 0, 0); } /*! @@ -2197,14 +2261,72 @@ QDateTime::QDateTime(const QDate &date) the time specification defined by \a spec. If \a date is valid and \a time is not, the time will be set to midnight. + + If \a spec is Qt::OffsetFromUTC then it will be set to Qt::UTC, i.e. an + offset of 0 seconds. To create a Qt::OffsetFromUTC datetime use the + correct constructor. */ QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec) - : d(new QDateTimePrivate) + : d(new QDateTimePrivate(date, time, spec, 0)) +{ +} + +/*! + \since 5.2 + + Constructs a datetime with the given \a date and \a time, using + the time specification defined by \a spec and \a offsetSeconds seconds. + + If \a date is valid and \a time is not, the time will be set to midnight. + + If the \a spec is not Qt::OffsetFromUTC then \a offsetSeconds will be ignored. + + If the \a spec is Qt::OffsetFromUTC and \a offsetSeconds is 0 then the + timeSpec() will be set to Qt::UTC, i.e. an offset of 0 seconds. +*/ + +QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec, int offsetSeconds) + : d(new QDateTimePrivate(date, time, spec, offsetSeconds)) { - d->date = date; - d->time = date.isValid() && !time.isValid() ? QTime(0, 0, 0) : time; - d->spec = (spec == Qt::UTC) ? QDateTimePrivate::UTC : QDateTimePrivate::LocalUnknown; +} + +/*! + \internal + \since 5.2 + + Private. + + Create a datetime with the given \a date, \a time, \a spec and \a offsetSeconds +*/ + +QDateTimePrivate::QDateTimePrivate(const QDate &toDate, const QTime &toTime, Qt::TimeSpec toSpec, + int offsetSeconds) +{ + date = toDate; + + if (!toTime.isValid() && toDate.isValid()) + time = QTime(0, 0, 0); + else + time = toTime; + + m_offsetFromUtc = 0; + + switch (toSpec) { + case Qt::UTC : + spec = QDateTimePrivate::UTC; + break; + case Qt::OffsetFromUTC : + if (offsetSeconds == 0) { + spec = QDateTimePrivate::UTC; + } else { + spec = QDateTimePrivate::OffsetFromUTC; + m_offsetFromUtc = offsetSeconds; + } + break; + case Qt::LocalTime : + spec = QDateTimePrivate::LocalUnknown; + } } /*! @@ -2307,6 +2429,34 @@ Qt::TimeSpec QDateTime::timeSpec() const } /*! + \since 5.2 + + Returns the current Offset From UTC in seconds. + + If the timeSpec() is Qt::OffsetFromUTC this will be the value originally set. + + If the timeSpec() is Qt::LocalTime this will be the difference between the + Local Time and UTC including any Daylight Saving Offset. + + If the timeSpec() is Qt::UTC this will be 0. + + \sa setOffsetFromUtc() +*/ + +int QDateTime::offsetFromUtc() const +{ + switch (d->spec) { + case QDateTimePrivate::OffsetFromUTC: + return d->m_offsetFromUtc; + case QDateTimePrivate::UTC: + return 0; + default: // Any Qt::LocalTime + const QDateTime fakeDate(d->date, d->time, Qt::UTC); + return (fakeDate.toMSecsSinceEpoch() - toMSecsSinceEpoch()) / 1000; + } +} + +/*! Sets the date part of this datetime to \a date. If no time is set, it is set to midnight. @@ -2343,6 +2493,9 @@ void QDateTime::setTime(const QTime &time) Sets the time specification used in this datetime to \a spec. The datetime will refer to a different point in time. + If \a spec is Qt::OffsetFromUTC then the timeSpec() will be set + to Qt::UTC, i.e. an effective offset of 0. + Example: \snippet code/src_corelib_tools_qdatetime.cpp 19 @@ -2353,17 +2506,43 @@ void QDateTime::setTimeSpec(Qt::TimeSpec spec) { detach(); - switch(spec) - { - case Qt::UTC: - d->spec = QDateTimePrivate::UTC; - break; - case Qt::OffsetFromUTC: - d->spec = QDateTimePrivate::OffsetFromUTC; - break; - default: - d->spec = QDateTimePrivate::LocalUnknown; - break; + d->m_offsetFromUtc = 0; + switch (spec) { + case Qt::UTC: + case Qt::OffsetFromUTC: + d->spec = QDateTimePrivate::UTC; + break; + default: + d->spec = QDateTimePrivate::LocalUnknown; + break; + } +} + +/*! + \since 5.2 + + Sets the timeSpec() to Qt::OffsetFromUTC and the offset to \a offsetSeconds. + The datetime will refer to a different point in time. + + The maximum and minimum offset is 14 positive or negative hours. If + \a offsetSeconds is larger or smaller than that, then the result is + undefined. + + If \a offsetSeconds is 0 then the timeSpec() will be set to Qt::UTC. + + \sa isValid(), offsetFromUtc() +*/ + +void QDateTime::setOffsetFromUtc(int offsetSeconds) +{ + detach(); + + if (offsetSeconds == 0) { + d->spec = QDateTimePrivate::UTC; + d->m_offsetFromUtc = 0; + } else { + d->spec = QDateTimePrivate::OffsetFromUTC; + d->m_offsetFromUtc = offsetSeconds; } } @@ -2446,8 +2625,6 @@ void QDateTime::setMSecsSinceEpoch(qint64 msecs) { detach(); - QDateTimePrivate::Spec oldSpec = d->spec; - qint64 ddays = msecs / MSECS_PER_DAY; msecs %= MSECS_PER_DAY; if (msecs < 0) { @@ -2458,10 +2635,11 @@ void QDateTime::setMSecsSinceEpoch(qint64 msecs) d->date = QDate(1970, 1, 1).addDays(ddays); d->time = QTime(0, 0, 0).addMSecs(msecs); - d->spec = QDateTimePrivate::UTC; - if (oldSpec != QDateTimePrivate::UTC) - d->spec = d->getLocal(d->date, d->time); + if (d->spec == QDateTimePrivate::OffsetFromUTC) + utcToOffset(&d->date, &d->time, d->m_offsetFromUtc); + else if (d->spec != QDateTimePrivate::UTC) + utcToLocal(d->date, d->time); } /*! @@ -2479,14 +2657,13 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC) { detach(); - QDateTimePrivate::Spec oldSpec = d->spec; - d->date = QDate(1970, 1, 1).addDays(secsSince1Jan1970UTC / SECS_PER_DAY); d->time = QTime(0, 0, 0).addSecs(secsSince1Jan1970UTC % SECS_PER_DAY); - d->spec = QDateTimePrivate::UTC; - if (oldSpec != QDateTimePrivate::UTC) - d->spec = d->getLocal(d->date, d->time); + if (d->spec == QDateTimePrivate::OffsetFromUTC) + utcToOffset(&d->date, &d->time, d->m_offsetFromUtc); + else if (d->spec != QDateTimePrivate::UTC) + utcToLocal(d->date, d->time); } #ifndef QT_NO_DATESTRING @@ -2554,11 +2731,7 @@ QString QDateTime::toString(Qt::DateFormat f) const buf += QLatin1Char('Z'); break; case QDateTimePrivate::OffsetFromUTC: { - int sign = d->utcOffset >= 0 ? 1: -1; - buf += QString::fromLatin1("%1%2:%3"). - arg(sign == 1 ? QLatin1Char('+') : QLatin1Char('-')). - arg(d->utcOffset * sign / SECS_PER_HOUR, 2, 10, QLatin1Char('0')). - arg((d->utcOffset / 60) % 60, 2, 10, QLatin1Char('0')); + buf += toOffsetString(Qt::ISODate, d->m_offsetFromUtc); break; } default: @@ -2567,7 +2740,7 @@ QString QDateTime::toString(Qt::DateFormat f) const } else if (f == Qt::RFC2822Date) { buf = toString(QStringLiteral("dd MMM yyyy hh:mm:ss ")); - int utcOffset = d->utcOffset; + int utcOffset = d->m_offsetFromUtc; if (timeSpec() == Qt::LocalTime) { QDateTime utc = toUTC(); utc.setTimeSpec(timeSpec()); @@ -2762,10 +2935,13 @@ QDateTime QDateTimePrivate::addMSecs(const QDateTime &dt, qint64 msecs) QDate utcDate; QTime utcTime; dt.d->getUTC(utcDate, utcTime); - addMSecs(utcDate, utcTime, msecs); + QDateTime utc(utcDate, utcTime, Qt::UTC); - return QDateTime(utcDate, utcTime, Qt::UTC).toTimeSpec(dt.timeSpec()); + if (dt.timeSpec() == Qt::OffsetFromUTC) + return utc.toOffsetFromUtc(dt.d->m_offsetFromUtc); + else + return utc.toTimeSpec(dt.timeSpec()); } /*! @@ -2916,12 +3092,14 @@ qint64 QDateTime::msecsTo(const QDateTime &other) const + static_cast<qint64>(selfTime.msecsTo(otherTime)); } - /*! - \fn QDateTime QDateTime::toTimeSpec(Qt::TimeSpec specification) const + \fn QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const Returns a copy of this datetime converted to the given time - \a specification. + \a spec. + + If \a spec is Qt::OffsetFromUTC then it is set to Qt::UTC. To set to a + spec of Qt::OffsetFromUTC use toOffsetFromUtc(). Example: \snippet code/src_corelib_tools_qdatetime.cpp 16 @@ -2931,19 +3109,41 @@ qint64 QDateTime::msecsTo(const QDateTime &other) const QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const { - if ((d->spec == QDateTimePrivate::UTC) == (spec == Qt::UTC)) - return *this; + if (spec == Qt::UTC || spec == Qt::OffsetFromUTC) { + QDate date; + QTime time; + d->getUTC(date, time); + return QDateTime(date, time, Qt::UTC, 0); + } QDateTime ret; - if (spec == Qt::UTC) { - d->getUTC(ret.d->date, ret.d->time); - ret.d->spec = QDateTimePrivate::UTC; - } else { - ret.d->spec = d->getLocal(ret.d->date, ret.d->time); - } + ret.d->spec = d->getLocal(ret.d->date, ret.d->time); return ret; } + +/*! + \since 5.2 + + \fn QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const + + Returns a copy of this datetime converted to a spec of Qt::OffsetFromUTC + with the given \a offsetSeconds. + + If the \a offsetSeconds equals 0 then a UTC datetime will be returned + + \sa setOffsetFromUtc(), offsetFromUtc(), toTimeSpec() +*/ + +QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const +{ + QDate date; + QTime time; + d->getUTC(date, time); + d->addMSecs(date, time, offsetSeconds * 1000); + return QDateTime(date, time, Qt::OffsetFromUTC, offsetSeconds); +} + /*! Returns true if this datetime is equal to the \a other datetime; otherwise returns false. @@ -2953,7 +3153,7 @@ QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const bool QDateTime::operator==(const QDateTime &other) const { - if (d->spec == other.d->spec && d->utcOffset == other.d->utcOffset) + if (d->spec == other.d->spec && d->m_offsetFromUtc == other.d->m_offsetFromUtc) return d->time == other.d->time && d->date == other.d->date; else { QDate date1, date2; @@ -3263,62 +3463,41 @@ QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs) return d; } +#if QT_DEPRECATED_SINCE(5, 2) /*! - \since 4.4 - \internal - - Sets the offset from UTC to \a seconds, and also sets timeSpec() to - Qt::OffsetFromUTC. + \since 4.4 + \internal + \obsolete - The maximum and minimum offset is 14 positive or negative hours. If - \a seconds is larger or smaller than that, the result is undefined. + This method was added in 4.4 but never documented as public. It was replaced + in 5.2 with public method setOffsetFromUtc() for consistency with QTimeZone. - 0 as offset is identical to UTC. Therefore, if \a seconds is 0, the - timeSpec() will be set to Qt::UTC. Hence the UTC offset always - relates to UTC, and can never relate to local time. + This method should never be made public. - \sa isValid(), utcOffset() + \sa setOffsetFromUtc() */ void QDateTime::setUtcOffset(int seconds) { - detach(); - - /* The motivation to also setting d->spec is to ensure that the QDateTime - * instance stays in well-defined states all the time; instead of that, - * we instruct the user to ensure it. */ - if(seconds == 0) - d->spec = QDateTimePrivate::UTC; - else - d->spec = QDateTimePrivate::OffsetFromUTC; - - /* Even if seconds is 0 we assign it to utcOffset. */ - d->utcOffset = seconds; + setOffsetFromUtc(seconds); } /*! - \since 4.4 - \internal - - Returns the UTC offset in seconds. If the timeSpec() isn't - Qt::OffsetFromUTC, 0 is returned. However, since 0 is a valid UTC - offset, the return value of this function cannot be used to determine - whether a utcOffset() is used or is valid; in that case, timeSpec() must be - checked. + \since 4.4 + \internal + \obsolete - Likewise, if this QDateTime() is invalid or if timeSpec() isn't - Qt::OffsetFromUTC, 0 is returned. + This method was added in 4.4 but never documented as public. It was replaced + in 5.1 with public method offsetFromUTC() for consistency with QTimeZone. - The UTC offset only applies if the timeSpec() is Qt::OffsetFromUTC. + This method should never be made public. - \sa isValid(), setUtcOffset() - */ + \sa offsetFromUTC() +*/ int QDateTime::utcOffset() const { - if(isValid() && d->spec == QDateTimePrivate::OffsetFromUTC) - return d->utcOffset; - else - return 0; + return offsetFromUtc(); } +#endif // QT_DEPRECATED_SINCE #ifndef QT_NO_DATESTRING @@ -3370,26 +3549,15 @@ QDateTime QDateTime::fromString(const QString& s, Qt::DateFormat f) } // Recognize timezone specifications - QRegExp rx(QLatin1String("[+-]")); - if (tmp.contains(rx)) { - int idx = tmp.indexOf(rx); - QString tmp2 = tmp.mid(idx); - tmp = tmp.left(idx); - bool ok = true; - int ntzhour = 1; - int ntzminute = 3; - if ( tmp2.indexOf(QLatin1Char(':')) == 3 ) - ntzminute = 4; - const int tzhour(tmp2.mid(ntzhour, 2).toInt(&ok)); - const int tzminute(tmp2.mid(ntzminute, 2).toInt(&ok)); - QTime tzt(tzhour, tzminute); - int utcOffset = (tzt.hour() * 60 + tzt.minute()) * 60; - if ( utcOffset != 0 ) { - ts = Qt::OffsetFromUTC; - QDateTime dt(date, QTime::fromString(tmp, Qt::ISODate), ts); - dt.setUtcOffset( utcOffset * (tmp2.startsWith(QLatin1Char('-')) ? -1 : 1) ); - return dt; - } + int offset = 0; + const int signIndex = tmp.indexOf(QRegExp(QStringLiteral("[+-]"))); + if (signIndex >= 0) { + bool ok; + offset = fromOffsetString(tmp.mid(signIndex), &ok); + if (!ok) + return QDateTime(); + tmp = tmp.left(signIndex); + ts = Qt::OffsetFromUTC; } bool isMidnight24 = false; @@ -3400,7 +3568,7 @@ QDateTime QDateTime::fromString(const QString& s, Qt::DateFormat f) date = date.addDays(1); } - return QDateTime(date, time, ts); + return QDateTime(date, time, ts, offset); } case Qt::RFC2822Date: { QDate date; @@ -3412,7 +3580,7 @@ QDateTime QDateTime::fromString(const QString& s, Qt::DateFormat f) return QDateTime(); QDateTime dateTime(date, time, Qt::UTC); - dateTime.setUtcOffset(utcOffset); + dateTime.setOffsetFromUtc(utcOffset); return dateTime; } case Qt::SystemLocaleDate: @@ -3521,26 +3689,15 @@ QDateTime QDateTime::fromString(const QString& s, Qt::DateFormat f) QString tz = parts.at(5); if (!tz.startsWith(QLatin1String("GMT"), Qt::CaseInsensitive)) return QDateTime(); - QDateTime dt(date, time, Qt::UTC); - if (tz.length() > 3) { - int tzoffset = 0; - QChar sign = tz.at(3); - if ((sign != QLatin1Char('+')) - && (sign != QLatin1Char('-'))) { - return QDateTime(); - } - int tzhour = tz.mid(4, 2).toInt(&ok); - if (!ok) - return QDateTime(); - int tzminute = tz.mid(6).toInt(&ok); + tz.remove(0, 3); + if (!tz.isEmpty()) { + int offset = fromOffsetString(tz, &ok); if (!ok) return QDateTime(); - tzoffset = (tzhour*60 + tzminute) * 60; - if (sign == QLatin1Char('-')) - tzoffset = -tzoffset; - dt.setUtcOffset(tzoffset); + return QDateTime(date, time, Qt::OffsetFromUTC, offset); + } else { + return QDateTime(date, time, Qt::UTC); } - return dt.toLocalTime(); } #endif //QT_NO_TEXTDATE } @@ -3790,7 +3947,7 @@ QDataStream &operator>>(QDataStream &in, QTime &time) */ QDataStream &operator<<(QDataStream &out, const QDateTime &dateTime) { - if (out.version() == 13) { + if (out.version() == QDataStream::Qt_5_0) { if (dateTime.isValid()) { // This approach is wrong and should not be used again; it breaks // the guarantee that a deserialised local datetime is the same time @@ -3803,8 +3960,12 @@ QDataStream &operator<<(QDataStream &out, const QDateTime &dateTime) out << (qint8)dateTime.timeSpec(); } else { out << dateTime.d->date << dateTime.d->time; - if (out.version() >= 7) + if (out.version() >= QDataStream::Qt_4_0) out << (qint8)dateTime.d->spec; + if (out.version() >= QDataStream::Qt_5_2 + && dateTime.d->spec == QDateTimePrivate::OffsetFromUTC) { + out << qint32(dateTime.offsetFromUtc()); + } } return out; } @@ -3823,19 +3984,23 @@ QDataStream &operator>>(QDataStream &in, QDateTime &dateTime) in >> dateTime.d->date >> dateTime.d->time; - if (in.version() == 13) { + if (in.version() == QDataStream::Qt_5_0) { qint8 ts = 0; in >> ts; if (dateTime.isValid()) { - // We always store the datetime as UTC in 13 onwards. + // We incorrectly stored the datetime as UTC in Qt_5_0. dateTime.d->spec = QDateTimePrivate::UTC; dateTime = dateTime.toTimeSpec(static_cast<Qt::TimeSpec>(ts)); } } else { qint8 ts = (qint8)QDateTimePrivate::LocalUnknown; - if (in.version() >= 7) + if (in.version() >= QDataStream::Qt_4_0) in >> ts; + qint32 offset = 0; + if (in.version() >= QDataStream::Qt_5_2 && ts == qint8(QDateTimePrivate::OffsetFromUTC)) + in >> offset; dateTime.d->spec = (QDateTimePrivate::Spec)ts; + dateTime.d->m_offsetFromUtc = offset; } return in; } @@ -4129,6 +4294,7 @@ static QDate adjustDate(QDate date) return date; } +// Convert passed in UTC datetime into LocalTime and return spec static QDateTimePrivate::Spec utcToLocal(QDate &date, QTime &time) { QDate fakeDate = adjustDate(date); @@ -4182,6 +4348,7 @@ static QDateTimePrivate::Spec utcToLocal(QDate &date, QTime &time) } } +// Convert passed in LocalTime datetime into UTC static void localToUtc(QDate &date, QTime &time, int isdst) { if (!date.isValid()) @@ -4254,26 +4421,42 @@ static void localToUtc(QDate &date, QTime &time, int isdst) } } +// Convert passed in OffsetFromUTC datetime and offset into UTC +static void offsetToUtc(QDate *outDate, QTime *outTime, qint32 offset) +{ + QDateTimePrivate::addMSecs(*outDate, *outTime, -(qint64(offset) * 1000)); +} + +// Convert passed in UTC datetime and offset into OffsetFromUTC +static void utcToOffset(QDate *outDate, QTime *outTime, qint32 offset) +{ + QDateTimePrivate::addMSecs(*outDate, *outTime, (qint64(offset) * 1000)); +} + +// Get current date/time in LocalTime and put result in outDate and outTime QDateTimePrivate::Spec QDateTimePrivate::getLocal(QDate &outDate, QTime &outTime) const { outDate = date; outTime = time; if (spec == QDateTimePrivate::UTC) return utcToLocal(outDate, outTime); + if (spec == QDateTimePrivate::OffsetFromUTC) { + offsetToUtc(&outDate, &outTime, m_offsetFromUtc); + return utcToLocal(outDate, outTime); + } return spec; } +// Get current date/time in UTC and put result in outDate and outTime void QDateTimePrivate::getUTC(QDate &outDate, QTime &outTime) const { outDate = date; outTime = time; - const bool isOffset = spec == QDateTimePrivate::OffsetFromUTC; - if (spec != QDateTimePrivate::UTC && !isOffset) + if (spec == QDateTimePrivate::OffsetFromUTC) + offsetToUtc(&outDate, &outTime, m_offsetFromUtc); + else if (spec != QDateTimePrivate::UTC) localToUtc(outDate, outTime, (int)spec); - - if (isOffset) - addMSecs(outDate, outTime, -(qint64(utcOffset) * 1000)); } #if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_NO_DATESTRING) diff --git a/src/corelib/tools/qdatetime.h b/src/corelib/tools/qdatetime.h index e5c1e104a2..83c92858ee 100644 --- a/src/corelib/tools/qdatetime.h +++ b/src/corelib/tools/qdatetime.h @@ -203,6 +203,8 @@ public: QDateTime(); explicit QDateTime(const QDate &); QDateTime(const QDate &, const QTime &, Qt::TimeSpec spec = Qt::LocalTime); + // ### Qt 6: Merge with above with default offsetSeconds = 0 + QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec, int offsetSeconds); QDateTime(const QDateTime &other); ~QDateTime(); @@ -216,15 +218,20 @@ public: QDate date() const; QTime time() const; Qt::TimeSpec timeSpec() const; + int offsetFromUtc() const; + qint64 toMSecsSinceEpoch() const; // ### Qt 6: use quint64 instead of uint uint toTime_t() const; + void setDate(const QDate &date); void setTime(const QTime &time); void setTimeSpec(Qt::TimeSpec spec); + void setOffsetFromUtc(int offsetSeconds); void setMSecsSinceEpoch(qint64 msecs); // ### Qt 6: use quint64 instead of uint void setTime_t(uint secsSince1Jan1970UTC); + #ifndef QT_NO_DATESTRING QString toString(Qt::DateFormat f = Qt::TextDate) const; QString toString(const QString &format) const; @@ -234,9 +241,12 @@ public: QDateTime addYears(int years) const; QDateTime addSecs(qint64 secs) const; QDateTime addMSecs(qint64 msecs) const; + QDateTime toTimeSpec(Qt::TimeSpec spec) const; inline QDateTime toLocalTime() const { return toTimeSpec(Qt::LocalTime); } inline QDateTime toUTC() const { return toTimeSpec(Qt::UTC); } + QDateTime toOffsetFromUtc(int offsetSeconds) const; + qint64 daysTo(const QDateTime &) const; qint64 secsTo(const QDateTime &) const; qint64 msecsTo(const QDateTime &) const; @@ -248,8 +258,10 @@ public: inline bool operator>(const QDateTime &other) const { return other < *this; } inline bool operator>=(const QDateTime &other) const { return !(*this < other); } - void setUtcOffset(int seconds); - int utcOffset() const; +#if QT_DEPRECATED_SINCE(5, 2) + QT_DEPRECATED void setUtcOffset(int seconds); + QT_DEPRECATED int utcOffset() const; +#endif // QT_DEPRECATED_SINCE static QDateTime currentDateTime(); static QDateTime currentDateTimeUtc(); diff --git a/src/corelib/tools/qdatetime_p.h b/src/corelib/tools/qdatetime_p.h index c70571d509..f3abcf02d8 100644 --- a/src/corelib/tools/qdatetime_p.h +++ b/src/corelib/tools/qdatetime_p.h @@ -81,25 +81,27 @@ class QDateTimePrivate : public QSharedData public: enum Spec { LocalUnknown = -1, LocalStandard = 0, LocalDST = 1, UTC = 2, OffsetFromUTC = 3}; - QDateTimePrivate() : spec(LocalUnknown), utcOffset(0) {} + QDateTimePrivate() : spec(LocalUnknown), m_offsetFromUtc(0) {} + QDateTimePrivate(const QDate &toDate, const QTime &toTime, Qt::TimeSpec toSpec, + int offsetSeconds); QDateTimePrivate(const QDateTimePrivate &other) - : QSharedData(other), date(other.date), time(other.time), spec(other.spec), utcOffset(other.utcOffset) + : QSharedData(other), date(other.date), time(other.time), spec(other.spec), + m_offsetFromUtc(other.m_offsetFromUtc) {} QDate date; QTime time; Spec spec; - /*! - \internal - \since 4.4 - - The offset in seconds. Applies only when timeSpec() is OffsetFromUTC. - */ - int utcOffset; + int m_offsetFromUtc; + // Get current date/time in LocalTime and put result in outDate and outTime Spec getLocal(QDate &outDate, QTime &outTime) const; + // Get current date/time in UTC and put result in outDate and outTime void getUTC(QDate &outDate, QTime &outTime) const; + + // Add msecs to given datetime and return result static QDateTime addMSecs(const QDateTime &dt, qint64 msecs); + // Add msecs to given datetime and put result in utcDate and utcTime static void addMSecs(QDate &utcDate, QTime &utcTime, qint64 msecs); static inline qint64 minJd() { return QDate::minJd(); } diff --git a/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp b/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp index 3607467ff9..a6d76ea7b6 100644 --- a/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp +++ b/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp @@ -269,7 +269,8 @@ static int NColorRoles[] = { QPalette::ToolTipText + 1, // Qt_4_6 QPalette::ToolTipText + 1, // Qt_5_0 QPalette::ToolTipText + 1, // Qt_5_1 - 0 // add the correct value for Qt_5_2 here later + QPalette::ToolTipText + 1, // Qt_5_2 + 0 // add the correct value for Qt_5_3 here later }; // Testing get/set functions diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp index 50092c9989..a49bc7faab 100644 --- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp @@ -129,8 +129,9 @@ private slots: void fromStringToStringLocale_data(); void fromStringToStringLocale(); - void utcOffset(); - void setUtcOffset(); + void offsetFromUtc(); + void setOffsetFromUtc(); + void toOffsetFromUtc(); void getDate(); @@ -187,8 +188,11 @@ QDateTime tst_QDateTime::dt( const QString& str ) void tst_QDateTime::ctor() { QDateTime dt1(QDate(2004, 1, 2), QTime(1, 2, 3)); + QCOMPARE(dt1.timeSpec(), Qt::LocalTime); QDateTime dt2(QDate(2004, 1, 2), QTime(1, 2, 3), Qt::LocalTime); + QCOMPARE(dt2.timeSpec(), Qt::LocalTime); QDateTime dt3(QDate(2004, 1, 2), QTime(1, 2, 3), Qt::UTC); + QCOMPARE(dt3.timeSpec(), Qt::UTC); QVERIFY(dt1 == dt2); if (europeanTimeZone) { @@ -196,6 +200,34 @@ void tst_QDateTime::ctor() QVERIFY(dt1 < dt3); QVERIFY(dt1.addSecs(3600).toUTC() == dt3); } + + // Test OffsetFromUTC constructors + QDate offsetDate(2013, 1, 1); + QTime offsetTime(1, 2, 3); + + QDateTime offset1(offsetDate, offsetTime, Qt::OffsetFromUTC); + QCOMPARE(offset1.timeSpec(), Qt::UTC); + QCOMPARE(offset1.offsetFromUtc(), 0); + QCOMPARE(offset1.date(), offsetDate); + QCOMPARE(offset1.time(), offsetTime); + + QDateTime offset2(offsetDate, offsetTime, Qt::OffsetFromUTC, 0); + QCOMPARE(offset2.timeSpec(), Qt::UTC); + QCOMPARE(offset2.offsetFromUtc(), 0); + QCOMPARE(offset2.date(), offsetDate); + QCOMPARE(offset2.time(), offsetTime); + + QDateTime offset3(offsetDate, offsetTime, Qt::OffsetFromUTC, 60 * 60); + QCOMPARE(offset3.timeSpec(), Qt::OffsetFromUTC); + QCOMPARE(offset3.offsetFromUtc(), 60 * 60); + QCOMPARE(offset3.date(), offsetDate); + QCOMPARE(offset3.time(), offsetTime); + + QDateTime offset4(offsetDate, QTime(), Qt::OffsetFromUTC, 60 * 60); + QCOMPARE(offset4.timeSpec(), Qt::OffsetFromUTC); + QCOMPARE(offset4.offsetFromUtc(), 60 * 60); + QCOMPARE(offset4.date(), offsetDate); + QCOMPARE(offset4.time(), QTime(0, 0, 0)); } void tst_QDateTime::operator_eq() @@ -390,7 +422,10 @@ void tst_QDateTime::setTimeSpec() QCOMPARE(dateTime.date(), expectedDate); QCOMPARE(dateTime.time(), expectedTime); - QCOMPARE(dateTime.timeSpec(), newTimeSpec); + if (newTimeSpec == Qt::OffsetFromUTC) + QCOMPARE(dateTime.timeSpec(), Qt::UTC); + else + QCOMPARE(dateTime.timeSpec(), newTimeSpec); } void tst_QDateTime::setTime_t() @@ -398,10 +433,12 @@ void tst_QDateTime::setTime_t() QDateTime dt1; dt1.setTime_t(0); QCOMPARE(dt1.toUTC(), QDateTime(QDate(1970, 1, 1), QTime(), Qt::UTC)); + QCOMPARE(dt1.timeSpec(), Qt::LocalTime); dt1.setTimeSpec(Qt::UTC); dt1.setTime_t(0); QCOMPARE(dt1, QDateTime(QDate(1970, 1, 1), QTime(), Qt::UTC)); + QCOMPARE(dt1.timeSpec(), Qt::UTC); dt1.setTime_t(123456); QCOMPARE(dt1, QDateTime(QDate(1970, 1, 2), QTime(10, 17, 36), Qt::UTC)); @@ -434,6 +471,12 @@ void tst_QDateTime::setTime_t() dt2.setTime_t(0x7FFFFFFF); QCOMPARE(dt2, QDateTime(QDate(2038, 1, 19), QTime(4, 14, 7), Qt::LocalTime)); } + + dt1 = QDateTime(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::OffsetFromUTC, 60 * 60); + dt1.setTime_t(123456); + QCOMPARE(dt1, QDateTime(QDate(1970, 1, 2), QTime(10, 17, 36), Qt::UTC)); + QCOMPARE(dt1.timeSpec(), Qt::OffsetFromUTC); + QCOMPARE(dt1.offsetFromUtc(), 60 * 60); } void tst_QDateTime::setMSecsSinceEpoch_data() @@ -503,6 +546,8 @@ void tst_QDateTime::setMSecsSinceEpoch() dt.setMSecsSinceEpoch(msecs); QCOMPARE(dt, utc); + QCOMPARE(dt.timeSpec(), Qt::UTC); + if (europeanTimeZone) { QCOMPARE(dt.toLocalTime(), european); @@ -512,6 +557,7 @@ void tst_QDateTime::setMSecsSinceEpoch() localDt.setMSecsSinceEpoch(msecs); QCOMPARE(localDt, utc); + QCOMPARE(localDt.timeSpec(), Qt::LocalTime); } QCOMPARE(dt.toMSecsSinceEpoch(), msecs); @@ -563,7 +609,7 @@ void tst_QDateTime::toString_isoDate_data() << QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34), Qt::UTC) << QString("1978-11-09T13:28:34.000Z"); QDateTime dt(QDate(1978, 11, 9), QTime(13, 28, 34)); - dt.setUtcOffset(19800); + dt.setOffsetFromUtc(19800); QTest::newRow("positive OffsetFromUTC") << dt << QString("1978-11-09T13:28:34.000+05:30"); @@ -673,6 +719,26 @@ void tst_QDateTime::addDays() QCOMPARE(dt.time(), QTime(12, 34, 56)); } + // Test preserves TimeSpec + QDateTime dt1(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::UTC); + QDateTime dt2 = dt1.addDays(2); + QCOMPARE(dt2.date(), QDate(2013, 1, 3)); + QCOMPARE(dt2.time(), QTime(0, 0, 0)); + QCOMPARE(dt2.timeSpec(), Qt::UTC); + + dt1 = QDateTime(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::LocalTime); + dt2 = dt1.addDays(2); + QCOMPARE(dt2.date(), QDate(2013, 1, 3)); + QCOMPARE(dt2.time(), QTime(0, 0, 0)); + QCOMPARE(dt2.timeSpec(), Qt::LocalTime); + + dt1 = QDateTime(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::OffsetFromUTC, 60*60); + dt2 = dt1.addDays(2); + QCOMPARE(dt2.date(), QDate(2013, 1, 3)); + QCOMPARE(dt2.time(), QTime(0, 0, 0)); + QCOMPARE(dt2.timeSpec(), Qt::OffsetFromUTC); + QCOMPARE(dt2.offsetFromUtc(), 60 * 60); + // ### test invalid QDateTime() } @@ -680,7 +746,7 @@ void tst_QDateTime::addDays() void tst_QDateTime::addMonths_data() { QTest::addColumn<int>("months"); - QTest::addColumn<QDate>("dt"); + QTest::addColumn<QDate>("resultDate"); QTest::newRow("-15") << -15 << QDate(2002, 10, 31); QTest::newRow("-14") << -14 << QDate(2002, 11, 30); @@ -718,20 +784,37 @@ void tst_QDateTime::addMonths_data() void tst_QDateTime::addMonths() { - QFETCH(QDate, dt); QFETCH(int, months); - - QDateTime start(QDate(2004, 1, 31), QTime(12, 34, 56)); - QCOMPARE(start.addMonths(months).date(), dt); - QCOMPARE(start.addMonths(months).time(), QTime(12, 34, 56)); + QFETCH(QDate, resultDate); + + QDate testDate(2004, 1, 31); + QTime testTime(12, 34, 56); + QDateTime start(testDate, testTime); + QDateTime end = start.addMonths(months); + QCOMPARE(end.date(), resultDate); + QCOMPARE(end.time(), testTime); + QCOMPARE(end.timeSpec(), Qt::LocalTime); + + start = QDateTime(testDate, testTime, Qt::UTC); + end = start.addMonths(months); + QCOMPARE(end.date(), resultDate); + QCOMPARE(end.time(), testTime); + QCOMPARE(end.timeSpec(), Qt::UTC); + + start = QDateTime(testDate, testTime, Qt::OffsetFromUTC, 60 * 60); + end = start.addMonths(months); + QCOMPARE(end.date(), resultDate); + QCOMPARE(end.time(), testTime); + QCOMPARE(end.timeSpec(), Qt::OffsetFromUTC); + QCOMPARE(end.offsetFromUtc(), 60 * 60); } void tst_QDateTime::addYears_data() { QTest::addColumn<int>("years1"); QTest::addColumn<int>("years2"); - QTest::addColumn<QDate>("start"); - QTest::addColumn<QDate>("dt"); + QTest::addColumn<QDate>("startDate"); + QTest::addColumn<QDate>("resultDate"); QTest::newRow("0") << 0 << 0 << QDate(1752, 9, 14) << QDate(1752, 9, 14); QTest::newRow("4000 - 4000") << 4000 << -4000 << QDate(1752, 9, 14) << QDate(1752, 9, 14); @@ -754,12 +837,28 @@ void tst_QDateTime::addYears() { QFETCH(int, years1); QFETCH(int, years2); - QFETCH(QDate, start); - QFETCH(QDate, dt); - - QDateTime startdt(start, QTime(14, 25, 36)); - QCOMPARE(startdt.addYears(years1).addYears(years2).date(), dt); - QCOMPARE(startdt.addYears(years1).addYears(years2).time(), QTime(14, 25, 36)); + QFETCH(QDate, startDate); + QFETCH(QDate, resultDate); + + QTime testTime(14, 25, 36); + QDateTime start(startDate, testTime); + QDateTime end = start.addYears(years1).addYears(years2); + QCOMPARE(end.date(), resultDate); + QCOMPARE(end.time(), testTime); + QCOMPARE(end.timeSpec(), Qt::LocalTime); + + start = QDateTime(startDate, testTime, Qt::UTC); + end = start.addYears(years1).addYears(years2); + QCOMPARE(end.date(), resultDate); + QCOMPARE(end.time(), testTime); + QCOMPARE(end.timeSpec(), Qt::UTC); + + start = QDateTime(startDate, testTime, Qt::OffsetFromUTC, 60 * 60); + end = start.addYears(years1).addYears(years2); + QCOMPARE(end.date(), resultDate); + QCOMPARE(end.time(), testTime); + QCOMPARE(end.timeSpec(), Qt::OffsetFromUTC); + QCOMPARE(end.offsetFromUtc(), 60 * 60); } void tst_QDateTime::addSecs_data() @@ -831,6 +930,13 @@ void tst_QDateTime::addSecs_data() << QDateTime(QDate(1, 1, 1), QTime(0, 0, 0), Qt::UTC); QTest::newRow("invalid") << invalidDateTime() << 1 << invalidDateTime(); + + // Check Offset details are preserved + QTest::newRow("offset0") << QDateTime(QDate(2013, 1, 1), QTime(1, 2, 3), + Qt::OffsetFromUTC, 60 * 60) + << 60 * 60 + << QDateTime(QDate(2013, 1, 1), QTime(2, 2, 3), + Qt::OffsetFromUTC, 60 * 60); } void tst_QDateTime::addSecs() @@ -842,7 +948,11 @@ void tst_QDateTime::addSecs() #ifdef Q_OS_IRIX QEXPECT_FAIL("cet4", "IRIX databases say 1970 had DST", Abort); #endif - QCOMPARE(dt.addSecs(nsecs), result); + QDateTime test = dt.addSecs(nsecs); + QCOMPARE(test, result); + QCOMPARE(test.timeSpec(), dt.timeSpec()); + if (test.timeSpec() == Qt::OffsetFromUTC) + QCOMPARE(test.offsetFromUtc(), dt.offsetFromUtc()); QCOMPARE(result.addSecs(-nsecs), dt); } @@ -860,14 +970,18 @@ void tst_QDateTime::addMSecs() #ifdef Q_OS_IRIX QEXPECT_FAIL("cet4", "IRIX databases say 1970 had DST", Abort); #endif - QCOMPARE(dt.addMSecs(qint64(nsecs) * 1000), result); + QDateTime test = dt.addMSecs(qint64(nsecs) * 1000); + QCOMPARE(test, result); + QCOMPARE(test.timeSpec(), dt.timeSpec()); + if (test.timeSpec() == Qt::OffsetFromUTC) + QCOMPARE(test.offsetFromUtc(), dt.offsetFromUtc()); QCOMPARE(result.addMSecs(qint64(-nsecs) * 1000), dt); } void tst_QDateTime::toTimeSpec_data() { - QTest::addColumn<QDateTime>("utc"); - QTest::addColumn<QDateTime>("local"); + QTest::addColumn<QDateTime>("fromUtc"); + QTest::addColumn<QDateTime>("fromLocal"); QTime utcTime(4, 20, 30); QTime localStandardTime(5, 20, 30); @@ -946,18 +1060,59 @@ void tst_QDateTime::toTimeSpec_data() void tst_QDateTime::toTimeSpec() { if (europeanTimeZone) { - QFETCH(QDateTime, utc); - QFETCH(QDateTime, local); + QFETCH(QDateTime, fromUtc); + QFETCH(QDateTime, fromLocal); + + QDateTime utcToUtc = fromUtc.toTimeSpec(Qt::UTC); + QDateTime localToLocal = fromLocal.toTimeSpec(Qt::LocalTime); + QDateTime utcToLocal = fromUtc.toTimeSpec(Qt::LocalTime); + QDateTime localToUtc = fromLocal.toTimeSpec(Qt::UTC); + QDateTime utcToOffset = fromUtc.toTimeSpec(Qt::OffsetFromUTC); + QDateTime localToOffset = fromLocal.toTimeSpec(Qt::OffsetFromUTC); + + QCOMPARE(utcToUtc, fromUtc); + QCOMPARE(utcToUtc.date(), fromUtc.date()); + QCOMPARE(utcToUtc.time(), fromUtc.time()); + QCOMPARE(utcToUtc.timeSpec(), Qt::UTC); + + QCOMPARE(localToLocal, fromLocal); + QCOMPARE(localToLocal.date(), fromLocal.date()); + QCOMPARE(localToLocal.time(), fromLocal.time()); + QCOMPARE(localToLocal.timeSpec(), Qt::LocalTime); - QCOMPARE(utc.toTimeSpec(Qt::UTC), utc); - QCOMPARE(local.toTimeSpec(Qt::LocalTime), local); #ifdef Q_OS_IRIX QEXPECT_FAIL("summer2", "IRIX databases say 1970 had DST", Abort); #endif - QCOMPARE(utc.toTimeSpec(Qt::LocalTime), local); - QCOMPARE(local.toTimeSpec(Qt::UTC), utc); - QCOMPARE(utc.toTimeSpec(Qt::UTC), local.toTimeSpec(Qt::UTC)); - QCOMPARE(utc.toTimeSpec(Qt::LocalTime), local.toTimeSpec(Qt::LocalTime)); + QCOMPARE(utcToLocal, fromLocal); + QCOMPARE(utcToLocal.date(), fromLocal.date()); + QCOMPARE(utcToLocal.time(), fromLocal.time()); + QCOMPARE(utcToLocal.timeSpec(), Qt::LocalTime); + + QCOMPARE(localToUtc, fromUtc); + QCOMPARE(localToUtc.date(), fromUtc.date()); + QCOMPARE(localToUtc.time(), fromUtc.time()); + QCOMPARE(localToUtc.timeSpec(), Qt::UTC); + + QCOMPARE(utcToUtc, localToUtc); + QCOMPARE(utcToUtc.date(), localToUtc.date()); + QCOMPARE(utcToUtc.time(), localToUtc.time()); + QCOMPARE(utcToUtc.timeSpec(), Qt::UTC); + + QCOMPARE(utcToLocal, localToLocal); + QCOMPARE(utcToLocal.date(), localToLocal.date()); + QCOMPARE(utcToLocal.time(), localToLocal.time()); + QCOMPARE(utcToLocal.timeSpec(), Qt::LocalTime); + + // OffsetToUTC becomes UTC + QCOMPARE(utcToOffset, fromUtc); + QCOMPARE(utcToOffset.date(), fromUtc.date()); + QCOMPARE(utcToOffset.time(), fromUtc.time()); + QCOMPARE(utcToOffset.timeSpec(), Qt::UTC); + + QCOMPARE(localToOffset, fromUtc); + QCOMPARE(localToOffset.date(), fromUtc.date()); + QCOMPARE(localToOffset.time(), fromUtc.time()); + QCOMPARE(localToOffset.timeSpec(), Qt::UTC); } else { QSKIP("Not tested with timezone other than Central European (CET/CST)"); } @@ -971,15 +1126,15 @@ void tst_QDateTime::toLocalTime_data() void tst_QDateTime::toLocalTime() { if (europeanTimeZone) { - QFETCH(QDateTime, utc); - QFETCH(QDateTime, local); + QFETCH(QDateTime, fromUtc); + QFETCH(QDateTime, fromLocal); - QCOMPARE(local.toLocalTime(), local); + QCOMPARE(fromLocal.toLocalTime(), fromLocal); #ifdef Q_OS_IRIX QEXPECT_FAIL("summer2", "IRIX databases say 1970 had DST", Abort); #endif - QCOMPARE(utc.toLocalTime(), local); - QCOMPARE(utc.toLocalTime(), local.toLocalTime()); + QCOMPARE(fromUtc.toLocalTime(), fromLocal); + QCOMPARE(fromUtc.toLocalTime(), fromLocal.toLocalTime()); } else { QSKIP("Not tested with timezone other than Central European (CET/CST)"); } @@ -993,15 +1148,15 @@ void tst_QDateTime::toUTC_data() void tst_QDateTime::toUTC() { if (europeanTimeZone) { - QFETCH(QDateTime, utc); - QFETCH(QDateTime, local); + QFETCH(QDateTime, fromUtc); + QFETCH(QDateTime, fromLocal); - QCOMPARE(utc.toUTC(), utc); + QCOMPARE(fromUtc.toUTC(), fromUtc); #ifdef Q_OS_IRIX QEXPECT_FAIL("summer2", "IRIX databases say 1970 had DST", Abort); #endif - QCOMPARE(local.toUTC(), utc); - QCOMPARE(utc.toUTC(), local.toUTC()); + QCOMPARE(fromLocal.toUTC(), fromUtc); + QCOMPARE(fromUtc.toUTC(), fromLocal.toUTC()); } else { QSKIP("Not tested with timezone other than Central European (CET/CST)"); } @@ -1331,9 +1486,9 @@ void tst_QDateTime::operator_eqeq_data() QDateTime dateTime3b = dateTime3.addDays(-1); // Ensure that different times may be equal when considering timezone. QDateTime dateTime3c(dateTime3.addSecs(3600)); - dateTime3c.setUtcOffset(3600); + dateTime3c.setOffsetFromUtc(3600); QDateTime dateTime3d(dateTime3.addSecs(-3600)); - dateTime3d.setUtcOffset(-3600); + dateTime3d.setOffsetFromUtc(-3600); // Convert from UTC to local. QDateTime dateTime3e(dateTime3.date(), dateTime3.time()); @@ -1666,12 +1821,10 @@ void tst_QDateTime::fromStringDateFormat_data() << Qt::ISODate << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), Qt::UTC); QTest::newRow("ISO -01:00") << QString::fromLatin1("1987-02-13T13:24:51-01:00") << Qt::ISODate << QDateTime(QDate(1987, 2, 13), QTime(14, 24, 51), Qt::UTC); - // Not sure about these two... it will currently be created as LocalTime, but it - // should probably be UTC according to the ISO 8601 spec (see 4.2.5.1). QTest::newRow("ISO +0000") << QString::fromLatin1("1970-01-01T00:12:34+0000") - << Qt::ISODate << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::LocalTime); + << Qt::ISODate << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC); QTest::newRow("ISO +00:00") << QString::fromLatin1("1970-01-01T00:12:34+00:00") - << Qt::ISODate << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::LocalTime); + << Qt::ISODate << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC); // No time specified - defaults to Qt::LocalTime. QTest::newRow("ISO data3") << QString::fromLatin1("2002-10-01") << Qt::ISODate << QDateTime(QDate(2002, 10, 1), QTime(0, 0, 0, 0), Qt::LocalTime); @@ -1922,25 +2075,47 @@ void tst_QDateTime::fromStringToStringLocale() QLocale::setDefault(def); } -void tst_QDateTime::utcOffset() +void tst_QDateTime::offsetFromUtc() { /* Check default value. */ - QCOMPARE(QDateTime().utcOffset(), 0); + QCOMPARE(QDateTime().offsetFromUtc(), 0); + + // Offset constructor + QDateTime dt1(QDate(2013, 1, 1), QTime(1, 0, 0), Qt::OffsetFromUTC, 60 * 60); + QCOMPARE(dt1.offsetFromUtc(), 60 * 60); + dt1 = QDateTime(QDate(2013, 1, 1), QTime(1, 0, 0), Qt::OffsetFromUTC, -60 * 60); + QCOMPARE(dt1.offsetFromUtc(), -60 * 60); + + // UTC should be 0 offset + QDateTime dt2(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::UTC); + QCOMPARE(dt2.offsetFromUtc(), 0); + + // LocalTime should vary + if (europeanTimeZone) { + // Time definitely in Standard Time so 1 hour ahead + QDateTime dt3(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::LocalTime); + QCOMPARE(dt3.offsetFromUtc(), 1 * 60 * 60); + // Time definitely in Daylight Time so 2 hours ahead + QDateTime dt4(QDate(2013, 6, 1), QTime(0, 0, 0), Qt::LocalTime); + QCOMPARE(dt4.offsetFromUtc(), 2 * 60 * 60); + } else { + QSKIP("You must test using Central European (CET/CEST) time zone, e.g. TZ=Europe/Oslo"); + } } -void tst_QDateTime::setUtcOffset() +void tst_QDateTime::setOffsetFromUtc() { /* Basic tests. */ { QDateTime dt(QDateTime::currentDateTime()); dt.setTimeSpec(Qt::LocalTime); - dt.setUtcOffset(0); - QCOMPARE(dt.utcOffset(), 0); + dt.setOffsetFromUtc(0); + QCOMPARE(dt.offsetFromUtc(), 0); QCOMPARE(dt.timeSpec(), Qt::UTC); - dt.setUtcOffset(-100); - QCOMPARE(dt.utcOffset(), -100); + dt.setOffsetFromUtc(-100); + QCOMPARE(dt.offsetFromUtc(), -100); QCOMPARE(dt.timeSpec(), Qt::OffsetFromUTC); } @@ -1948,32 +2123,80 @@ void tst_QDateTime::setUtcOffset() { QDateTime dt(QDateTime::currentDateTime()); QDateTime dt2(dt); + int offset2 = dt2.offsetFromUtc(); - dt.setUtcOffset(501); + dt.setOffsetFromUtc(501); - QCOMPARE(dt.utcOffset(), 501); - QCOMPARE(dt2.utcOffset(), 0); + QCOMPARE(dt.offsetFromUtc(), 501); + QCOMPARE(dt2.offsetFromUtc(), offset2); } /* Check copying. */ { QDateTime dt(QDateTime::currentDateTime()); - dt.setUtcOffset(502); - QCOMPARE(dt.utcOffset(), 502); + dt.setOffsetFromUtc(502); + QCOMPARE(dt.offsetFromUtc(), 502); QDateTime dt2(dt); - QCOMPARE(dt2.utcOffset(), 502); + QCOMPARE(dt2.offsetFromUtc(), 502); } /* Check assignment. */ { QDateTime dt(QDateTime::currentDateTime()); - dt.setUtcOffset(502); + dt.setOffsetFromUtc(502); QDateTime dt2; dt2 = dt; - QCOMPARE(dt2.utcOffset(), 502); + QCOMPARE(dt2.offsetFromUtc(), 502); } + + // Check spec persists + QDateTime dt1(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::OffsetFromUTC, 60 * 60); + dt1.setMSecsSinceEpoch(123456789); + QCOMPARE(dt1.timeSpec(), Qt::OffsetFromUTC); + QCOMPARE(dt1.offsetFromUtc(), 60 * 60); + dt1.setTime_t(123456789); + QCOMPARE(dt1.timeSpec(), Qt::OffsetFromUTC); + QCOMPARE(dt1.offsetFromUtc(), 60 * 60); + + // Check datastream serialises the offset seconds + QByteArray tmp; + { + QDataStream ds(&tmp, QIODevice::WriteOnly); + ds << dt1; + } + QDateTime dt2; + { + QDataStream ds(&tmp, QIODevice::ReadOnly); + ds >> dt2; + } + QCOMPARE(dt2, dt1); + QCOMPARE(dt2.timeSpec(), Qt::OffsetFromUTC); + QCOMPARE(dt2.offsetFromUtc(), 60 * 60); +} + +void tst_QDateTime::toOffsetFromUtc() +{ + QDateTime dt1(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::UTC); + + QDateTime dt2 = dt1.toOffsetFromUtc(60 * 60); + QCOMPARE(dt2, dt1); + QCOMPARE(dt2.timeSpec(), Qt::OffsetFromUTC); + QCOMPARE(dt2.date(), QDate(2013, 1, 1)); + QCOMPARE(dt2.time(), QTime(1, 0, 0)); + + dt2 = dt1.toOffsetFromUtc(0); + QCOMPARE(dt2, dt1); + QCOMPARE(dt2.timeSpec(), Qt::UTC); + QCOMPARE(dt2.date(), QDate(2013, 1, 1)); + QCOMPARE(dt2.time(), QTime(0, 0, 0)); + + dt2 = dt1.toTimeSpec(Qt::OffsetFromUTC); + QCOMPARE(dt2, dt1); + QCOMPARE(dt2.timeSpec(), Qt::UTC); + QCOMPARE(dt2.date(), QDate(2013, 1, 1)); + QCOMPARE(dt2.time(), QTime(0, 0, 0)); } void tst_QDateTime::getDate() @@ -2050,8 +2273,8 @@ void tst_QDateTime::utcOffsetLessThan() const QDateTime dt1(QDate(2002, 10, 10), QTime(0, 0, 0)); QDateTime dt2(dt1); - dt1.setUtcOffset(-(2 * 60 * 60)); // Minus two hours. - dt2.setUtcOffset(-(3 * 60 * 60)); // Minus three hours. + dt1.setOffsetFromUtc(-(2 * 60 * 60)); // Minus two hours. + dt2.setOffsetFromUtc(-(3 * 60 * 60)); // Minus three hours. QVERIFY(dt1 != dt2); QVERIFY(!(dt1 == dt2)); |