summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Layt <jlayt@kde.org>2013-02-25 13:36:29 +0000
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-08-28 19:08:14 +0200
commit13c16bbd06e0034210ba2164f1be208c49a6e3a7 (patch)
tree2ab887adab4ad7f38b60ff7c903e55623dd6aa72
parent80cb575953e3a282593570e1583938b6475bc0d3 (diff)
QDateTime - Improve and expose Qt::OffsetFromUtc
The Qt::OffsetFromUtc TimeSpec was made public in Qt 4.4 but the access methods were never made public in the apidox effectively meaning the feature was never used. The implementation was also incomplete and inconsistent. This change cleans up the implementation and exports new public API for using the TimeSpec using new method names consistent with the new QTimeZone support. This change increases the QDataStream Version number for Qt 5.2 to 15. The behavior of one constructor has changed slightly to be consistent with the rest of the feature, but this behavior was never documented. [ChangeLog][QtCore][QDateTime] Fully implement support for Qt::TimeSpec of Qt::OffsetFromUTC, added new methods for offsetFromUTC(), toTimeSpec(), and toOffsetFromUTC(). Task-number: QTBUG-26161 Task-number: QTBUG-29666 Change-Id: If3cc7fc9778ca2b831644408ae749448d5975a3a Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Mitch Curtis <mitch.curtis@digia.com>
-rw-r--r--src/corelib/io/qdatastream.cpp5
-rw-r--r--src/corelib/io/qdatastream.h2
-rw-r--r--src/corelib/tools/qdatetime.cpp457
-rw-r--r--src/corelib/tools/qdatetime.h16
-rw-r--r--src/corelib/tools/qdatetime_p.h20
-rw-r--r--tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp3
-rw-r--r--tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp349
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));