QDateTime - Add QTimeZone support

Add support to QDateTime for time zones using the new QTimeZone class.

[ChangeLog][QtCore][QDateTime] Add support for a new Qt::TimeZone
spec to be used with QTimeZone to define times in a specific
time zone.

Change-Id: I21bfa52a8ba8989b55bb74e025d1f2b2b623b2a7
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
John Layt 2013-02-11 13:44:37 +00:00 committed by The Qt Project
parent 8af776d414
commit 55f5b29d79
11 changed files with 713 additions and 16 deletions

View File

@ -1196,7 +1196,8 @@ public:
enum TimeSpec {
LocalTime,
UTC,
OffsetFromUTC
OffsetFromUTC,
TimeZone
};
enum DayOfWeek {

View File

@ -604,6 +604,7 @@
\value LocalTime Locale dependent time (Timezones and Daylight Savings Time).
\value UTC Coordinated Universal Time, replaces Greenwich Mean Time.
\value OffsetFromUTC An offset in seconds from Coordinated Universal Time.
\value TimeZone A named time zone using a specific set of Daylight Savings rules.
*/
/*!

View File

@ -47,6 +47,7 @@
#include "qset.h"
#include "qlocale.h"
#include "qdatetime.h"
#include "qtimezoneprivate_p.h"
#include "qregexp.h"
#include "qdebug.h"
#ifndef Q_OS_WIN
@ -2597,9 +2598,26 @@ QDateTimePrivate::QDateTimePrivate(const QDate &toDate, const QTime &toTime, Qt:
setDateTime(toDate, toTime);
}
#ifndef QT_BOOTSTRAPPED
QDateTimePrivate::QDateTimePrivate(const QDate &toDate, const QTime &toTime,
const QTimeZone &toTimeZone)
: m_spec(Qt::TimeZone),
m_offsetFromUtc(0),
m_timeZone(toTimeZone),
m_status(0)
{
setDateTime(toDate, toTime);
}
#endif // QT_BOOTSTRAPPED
void QDateTimePrivate::setTimeSpec(Qt::TimeSpec spec, int offsetSeconds)
{
clearValidDateTime();
clearTimeZoneCached();
#ifndef QT_BOOTSTRAPPED
m_timeZone = QTimeZone();
#endif // QT_BOOTSTRAPPED
switch (spec) {
case Qt::OffsetFromUTC:
@ -2611,6 +2629,11 @@ void QDateTimePrivate::setTimeSpec(Qt::TimeSpec spec, int offsetSeconds)
m_offsetFromUtc = offsetSeconds;
}
break;
case Qt::TimeZone:
// Use system time zone instead
m_spec = Qt::LocalTime;
m_offsetFromUtc = 0;
break;
case Qt::UTC:
case Qt::LocalTime:
m_spec = spec;
@ -2676,6 +2699,12 @@ void QDateTimePrivate::checkValidDateTime()
else
clearValidDateTime();
break;
case Qt::TimeZone:
// Defer checking until required as can be expensive
clearValidDateTime();
clearTimeZoneCached();
m_offsetFromUtc = 0;
break;
case Qt::LocalTime:
// Defer checking until required as can be expensive
clearValidDateTime();
@ -2687,9 +2716,21 @@ void QDateTimePrivate::checkValidDateTime()
// Refresh the LocalTime validity and offset
void QDateTimePrivate::refreshDateTime()
{
// Always set by setDateTime so just return
if (m_spec == Qt::UTC || m_spec == Qt::OffsetFromUTC)
switch (m_spec) {
case Qt::OffsetFromUTC:
case Qt::UTC:
// Always set by setDateTime so just return
return;
case Qt::TimeZone:
// If already cached then don't need to refresh as tz won't change
if (isTimeZoneCached())
return;
// Flag that will have a cached result after calculations
setTimeZoneCached();
break;
case Qt::LocalTime:
break;
}
// If not valid date and time then is invalid
if (!isValidDate() || !isValidTime()) {
@ -2698,7 +2739,7 @@ void QDateTimePrivate::refreshDateTime()
return;
}
// We have a valid date and time and a Qt::LocalTime that needs calculating
// We have a valid date and time and a Qt::LocalTime or Qt::TimeZone that needs calculating
QDate date;
QTime time;
getDateTime(&date, &time);
@ -2706,7 +2747,13 @@ void QDateTimePrivate::refreshDateTime()
// Calling toEpochMSecs will adjust the returned date/time if it does
QDate testDate;
QTime testTime;
qint64 epochMSecs = localMSecsToEpochMSecs(m_msecs, &testDate, &testTime);
qint64 epochMSecs = 0;
#ifndef QT_BOOTSTRAPPED
if (m_spec == Qt::TimeZone)
epochMSecs = zoneMSecsToEpochMSecs(m_msecs, m_timeZone, &testDate, &testTime);
else
#endif // QT_BOOTSTRAPPED
epochMSecs = localMSecsToEpochMSecs(m_msecs, &testDate, &testTime);
if (testDate == date && testTime == time) {
setValidDateTime();
// Cache the offset to use in toMSecsSinceEpoch()
@ -2717,6 +2764,25 @@ void QDateTimePrivate::refreshDateTime()
}
}
#ifndef QT_BOOTSTRAPPED
// Convert a TimeZone time expressed in zone msecs encoding into a UTC epoch msecs
qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QTimeZone &zone,
QDate *localDate, QTime *localTime)
{
// Get the effective data from QTimeZone
QTimeZonePrivate::Data data = zone.d->dataForLocalTime(zoneMSecs);
// Docs state any LocalTime before 1970-01-01 will *not* have any Daylight Time applied
// but all times afterwards will have Daylight Time applied.
if (data.atMSecsSinceEpoch >= 0) {
msecsToTime(data.atMSecsSinceEpoch + (data.offsetFromUtc * 1000), localDate, localTime);
return data.atMSecsSinceEpoch;
} else {
msecsToTime(zoneMSecs, localDate, localTime);
return zoneMSecs - (data.standardTimeOffset * 1000);
}
}
#endif // QT_BOOTSTRAPPED
/*****************************************************************************
QDateTime member functions
*****************************************************************************/
@ -2833,7 +2899,17 @@ void QDateTimePrivate::refreshDateTime()
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
\section2 Time Zone Support
A Qt::TimeSpec of Qt::TimeZone is also supported in conjunction with the
QTimeZone class. This allows you to define a datetime in a named time zone
adhering to a consistent set of daylight savings transition rules. For
example a time zone of "Europe/Berlin" will apply the daylight savings
rules as used in Germany since 1970. Note that the transition rules
applied depend on the platform support. See the QTimeZone documentation
for more details.
\sa QDate, QTime, QDateTimeEdit, QTimeZone
*/
/*!
@ -2867,6 +2943,10 @@ QDateTime::QDateTime(const QDate &date)
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.
If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime,
i.e. the current system time zone. To create a Qt::TimeZone datetime
use the correct constructor.
*/
QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec)
@ -2886,6 +2966,10 @@ QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec)
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.
If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime,
i.e. the current system time zone. To create a Qt::TimeZone datetime
use the correct constructor.
*/
QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec, int offsetSeconds)
@ -2893,6 +2977,24 @@ QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec, in
{
}
#ifndef QT_BOOTSTRAPPED
/*!
\since 5.2
Constructs a datetime with the given \a date and \a time, using
the Time Zone specified by \a timeZone.
If \a date is valid and \a time is not, the time will be set to 00:00:00.
If \a timeZone is invalid then the datetime will be invalid.
*/
QDateTime::QDateTime(const QDate &date, const QTime &time, const QTimeZone &timeZone)
: d(new QDateTimePrivate(date, time, timeZone))
{
}
#endif // QT_BOOTSTRAPPED
/*!
Constructs a copy of the \a other datetime.
*/
@ -2943,7 +3045,7 @@ bool QDateTime::isNull() const
Returns true if both the date and the time are valid and they are valid in
the current Qt::TimeSpec, otherwise returns false.
If the timeSpec() is Qt::LocalTime then the date and time are
If the timeSpec() is Qt::LocalTime or Qt::TimeZone then the date and time are
checked to see if they fall in the Standard Time to Daylight Time transition
hour, i.e. if the transition is at 2am and the clock goes forward to 3am
then the time from 02:00:00 to 02:59:59.999 is considered to be invalid.
@ -2996,6 +3098,39 @@ Qt::TimeSpec QDateTime::timeSpec() const
return d->m_spec;
}
#ifndef QT_BOOTSTRAPPED
/*!
\since 5.2
Returns the time zone of the datetime.
If the timeSpec() is Qt::LocalTime then an instance of the current system
time zone will be returned. Note however that if you copy this time zone
the instance will not remain in sync if the system time zone changes.
\sa setTimeZone(), Qt::TimeSpec
*/
QTimeZone QDateTime::timeZone() const
{
switch (d->m_spec) {
case Qt::OffsetFromUTC:
if (!d->m_timeZone.isValid())
d->m_timeZone = QTimeZone(d->m_offsetFromUtc);
return d->m_timeZone;
case Qt::UTC:
if (!d->m_timeZone.isValid())
d->m_timeZone = QTimeZone("UTC");
return d->m_timeZone;
case Qt::TimeZone :
return d->m_timeZone;
case Qt::LocalTime:
return QTimeZone(QTimeZone::systemTimeZoneId());
}
return QTimeZone();
}
#endif // QT_BOOTSTRAPPED
/*!
\since 5.2
@ -3003,6 +3138,9 @@ Qt::TimeSpec QDateTime::timeSpec() const
If the timeSpec() is Qt::OffsetFromUTC this will be the value originally set.
If the timeSpec() is Qt::TimeZone this will be the offset effective in the
Time Zone including any Daylight Saving Offset.
If the timeSpec() is Qt::LocalTime this will be the difference between the
Local Time and UTC including any Daylight Saving Offset.
@ -3045,6 +3183,10 @@ QString QDateTime::timeZoneAbbreviation() const
return QStringLiteral("UTC");
case Qt::OffsetFromUTC:
return QLatin1String("UTC") + toOffsetString(Qt::ISODate, d->m_offsetFromUtc);
case Qt::TimeZone:
#ifndef QT_BOOTSTRAPPED
return d->m_timeZone.d->abbreviation(d->toMSecsSinceEpoch());
#endif // QT_BOOTSTRAPPED
case Qt::LocalTime: {
QString abbrev;
localMSecsToEpochMSecs(d->m_msecs, 0, 0, 0, &abbrev);
@ -3059,7 +3201,7 @@ QString QDateTime::timeZoneAbbreviation() const
Returns if this datetime falls in Daylight Savings Time.
If the Qt::TimeSpec is not Qt::LocalTime then will always
If the Qt::TimeSpec is not Qt::LocalTime or Qt::TimeZone then will always
return false.
\sa timeSpec()
@ -3071,6 +3213,10 @@ bool QDateTime::isDaylightTime() const
case Qt::UTC:
case Qt::OffsetFromUTC:
return false;
case Qt::TimeZone:
#ifndef QT_BOOTSTRAPPED
return d->m_timeZone.d->isDaylightTime(toMSecsSinceEpoch());
#endif // QT_BOOTSTRAPPED
case Qt::LocalTime: {
QDateTimePrivate::DaylightStatus status;
localMSecsToEpochMSecs(d->m_msecs, 0, 0, &status, 0);
@ -3112,10 +3258,13 @@ void QDateTime::setTime(const QTime &time)
If \a spec is Qt::OffsetFromUTC then the timeSpec() will be set
to Qt::UTC, i.e. an effective offset of 0.
If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime,
i.e. the current system time zone.
Example:
\snippet code/src_corelib_tools_qdatetime.cpp 19
\sa timeSpec(), setDate(), setTime(), Qt::TimeSpec
\sa timeSpec(), setDate(), setTime(), setTimeZone(), Qt::TimeSpec
*/
void QDateTime::setTimeSpec(Qt::TimeSpec spec)
@ -3147,6 +3296,28 @@ void QDateTime::setOffsetFromUtc(int offsetSeconds)
d->checkValidDateTime();
}
#ifndef QT_BOOTSTRAPPED
/*!
\since 5.2
Sets the time zone used in this datetime to \a toZone.
The datetime will refer to a different point in time.
If \a toZone is invalid then the datetime will be invalid.
\sa timeZone(), Qt::TimeSpec
*/
void QDateTime::setTimeZone(const QTimeZone &toZone)
{
detach();
d->m_spec = Qt::TimeZone;
d->m_offsetFromUtc = 0;
d->m_timeZone = toZone;
d->m_status = d->m_status & ~QDateTimePrivate::ValidDateTime & ~QDateTimePrivate::TimeZoneCached;
}
#endif // QT_BOOTSTRAPPED
/*!
\since 4.7
@ -3234,6 +3405,22 @@ void QDateTime::setMSecsSinceEpoch(qint64 msecs)
| QDateTimePrivate::ValidTime
| QDateTimePrivate::ValidDateTime;
break;
case Qt::TimeZone:
#ifndef QT_BOOTSTRAPPED
// Docs state any LocalTime before 1970-01-01 will *not* have any Daylight Time applied
// but all times afterwards will have Daylight Time applied.
if (msecs >= 0)
d->m_offsetFromUtc = d->m_timeZone.d->offsetFromUtc(msecs);
else
d->m_offsetFromUtc = d->m_timeZone.d->standardTimeOffset(msecs);
d->m_msecs = msecs + (d->m_offsetFromUtc * 1000);
d->m_status = d->m_status
| QDateTimePrivate::ValidDate
| QDateTimePrivate::ValidTime
| QDateTimePrivate::ValidDateTime
| QDateTimePrivate::TimeZoneCached;
#endif // QT_BOOTSTRAPPED
break;
case Qt::LocalTime: {
QDate dt;
QTime tm;
@ -3499,6 +3686,10 @@ QDateTime QDateTime::addDays(qint64 ndays) const
// so call conversion and use the adjusted returned time
if (d->m_spec == Qt::LocalTime)
localMSecsToEpochMSecs(timeToMSecs(date, time), &date, &time);
#ifndef QT_BOOTSTRAPPED
else if (d->m_spec == Qt::TimeZone)
d->zoneMSecsToEpochMSecs(timeToMSecs(date, time), d->m_timeZone, &date, &time);
#endif // QT_BOOTSTRAPPED
dt.d->setDateTime(date, time);
return dt;
}
@ -3529,6 +3720,10 @@ QDateTime QDateTime::addMonths(int nmonths) const
// so call conversion and use the adjusted returned time
if (d->m_spec == Qt::LocalTime)
localMSecsToEpochMSecs(timeToMSecs(date, time), &date, &time);
#ifndef QT_BOOTSTRAPPED
else if (d->m_spec == Qt::TimeZone)
d->zoneMSecsToEpochMSecs(timeToMSecs(date, time), d->m_timeZone, &date, &time);
#endif // QT_BOOTSTRAPPED
dt.d->setDateTime(date, time);
return dt;
}
@ -3559,6 +3754,10 @@ QDateTime QDateTime::addYears(int nyears) const
// so call conversion and use the adjusted returned time
if (d->m_spec == Qt::LocalTime)
localMSecsToEpochMSecs(timeToMSecs(date, time), &date, &time);
#ifndef QT_BOOTSTRAPPED
else if (d->m_spec == Qt::TimeZone)
d->zoneMSecsToEpochMSecs(timeToMSecs(date, time), d->m_timeZone, &date, &time);
#endif // QT_BOOTSTRAPPED
dt.d->setDateTime(date, time);
return dt;
}
@ -3594,7 +3793,7 @@ QDateTime QDateTime::addMSecs(qint64 msecs) const
QDateTime dt(*this);
dt.detach();
if (d->m_spec == Qt::LocalTime)
if (d->m_spec == Qt::LocalTime || d->m_spec == Qt::TimeZone)
// Convert to real UTC first in case crosses daylight transition
dt.setMSecsSinceEpoch(d->toMSecsSinceEpoch() + msecs);
else
@ -3677,10 +3876,13 @@ qint64 QDateTime::msecsTo(const QDateTime &other) const
If \a spec is Qt::OffsetFromUTC then it is set to Qt::UTC. To set to a
spec of Qt::OffsetFromUTC use toOffsetFromUtc().
If \a spec is Qt::TimeZone then it is set to Qt::LocalTime,
i.e. the local Time Zone.
Example:
\snippet code/src_corelib_tools_qdatetime.cpp 16
\sa timeSpec(), toUTC(), toLocalTime()
\sa timeSpec(), toTimeZone(), toUTC(), toLocalTime()
*/
QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const
@ -3706,6 +3908,21 @@ QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const
return fromMSecsSinceEpoch(toMSecsSinceEpoch(), Qt::OffsetFromUTC, offsetSeconds);
}
#ifndef QT_BOOTSTRAPPED
/*!
\since 5.2
Returns a copy of this datetime converted to the given \a timeZone
\sa timeZone(), toTimeSpec()
*/
QDateTime QDateTime::toTimeZone(const QTimeZone &timeZone) const
{
return fromMSecsSinceEpoch(toMSecsSinceEpoch(), timeZone);
}
#endif // QT_BOOTSTRAPPED
/*!
Returns true if this datetime is equal to the \a other datetime;
otherwise returns false.
@ -3934,6 +4151,22 @@ QDateTime QDateTime::fromTime_t(uint seconds, Qt::TimeSpec spec, int offsetSecon
return fromMSecsSinceEpoch((qint64)seconds * 1000, spec, offsetSeconds);
}
#ifndef QT_BOOTSTRAPPED
/*!
\since 5.2
Returns a datetime whose date and time are the number of \a seconds
that have passed since 1970-01-01T00:00:00, Coordinated Universal
Time (Qt::UTC) and with the given \a timeZone.
\sa toTime_t(), setTime_t()
*/
QDateTime QDateTime::fromTime_t(uint seconds, const QTimeZone &timeZone)
{
return fromMSecsSinceEpoch((qint64)seconds * 1000, timeZone);
}
#endif
/*!
\since 4.7
@ -3968,6 +4201,9 @@ QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs)
ignored. If the \a spec is Qt::OffsetFromUTC and the \a offsetSeconds is 0
then the spec will be set to Qt::UTC, i.e. an offset of 0 seconds.
If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime,
i.e. the current system time zone.
\sa fromTime_t()
*/
QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, Qt::TimeSpec spec, int offsetSeconds)
@ -3979,6 +4215,25 @@ QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, Qt::TimeSpec spec, int of
return dt;
}
#ifndef QT_BOOTSTRAPPED
/*!
\since 5.2
Returns a datetime whose date and time are the number of milliseconds \a msecs
that have passed since 1970-01-01T00:00:00.000, Coordinated Universal
Time (Qt::UTC) and with the given \a timeZone.
\sa fromTime_t()
*/
QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone)
{
QDateTime dt;
dt.setTimeZone(timeZone);
dt.setMSecsSinceEpoch(msecs);
return dt;
}
#endif
#if QT_DEPRECATED_SINCE(5, 2)
/*!
\since 4.4
@ -4480,6 +4735,10 @@ QDataStream &operator<<(QDataStream &out, const QDateTime &dateTime)
out << dt << tm << qint8(dateTime.timeSpec());
if (dateTime.timeSpec() == Qt::OffsetFromUTC)
out << qint32(dateTime.offsetFromUtc());
#ifndef QT_BOOTSTRAPPED
else if (dateTime.timeSpec() == Qt::TimeZone)
out << dateTime.timeZone();
#endif // QT_BOOTSTRAPPED
} else if (out.version() == QDataStream::Qt_5_0) {
@ -4506,6 +4765,11 @@ QDataStream &operator<<(QDataStream &out, const QDateTime &dateTime)
case Qt::OffsetFromUTC:
out << (qint8)QDateTimePrivate::OffsetFromUTC;
break;
case Qt::TimeZone:
#ifndef QT_BOOTSTRAPPED
out << (qint8)QDateTimePrivate::TimeZone;
break;
#endif // QT_BOOTSTRAPPED
case Qt::LocalTime:
out << (qint8)QDateTimePrivate::LocalUnknown;
break;
@ -4540,15 +4804,26 @@ QDataStream &operator>>(QDataStream &in, QDateTime &dateTime)
qint8 ts = 0;
Qt::TimeSpec spec = Qt::LocalTime;
qint32 offset = 0;
#ifndef QT_BOOTSTRAPPED
QTimeZone tz;
#endif // QT_BOOTSTRAPPED
if (in.version() >= QDataStream::Qt_5_2) {
// In 5.2 we switched to using Qt::TimeSpec and added offset support
in >> dt >> tm >> ts;
spec = static_cast<Qt::TimeSpec>(ts);
if (spec == Qt::OffsetFromUTC)
if (spec == Qt::OffsetFromUTC) {
in >> offset;
dateTime = QDateTime(dt, tm, spec, offset);
dateTime = QDateTime(dt, tm, spec, offset);
#ifndef QT_BOOTSTRAPPED
} else if (spec == Qt::TimeZone) {
in >> tz;
dateTime = QDateTime(dt, tm, tz);
#endif // QT_BOOTSTRAPPED
} else {
dateTime = QDateTime(dt, tm, spec);
}
} else if (in.version() == QDataStream::Qt_5_0) {
@ -4569,6 +4844,11 @@ QDataStream &operator>>(QDataStream &in, QDateTime &dateTime)
case QDateTimePrivate::OffsetFromUTC:
spec = Qt::OffsetFromUTC;
break;
case QDateTimePrivate::TimeZone:
#ifndef QT_BOOTSTRAPPED
spec = Qt::TimeZone;
break;
#endif // QT_BOOTSTRAPPED
case QDateTimePrivate::LocalUnknown:
case QDateTimePrivate::LocalStandard:
case QDateTimePrivate::LocalDST:
@ -4616,6 +4896,11 @@ QDebug operator<<(QDebug dbg, const QDateTime &date)
case Qt::OffsetFromUTC:
spec = QString::fromUtf8(" Qt::OffsetFromUTC %1s").arg(date.offsetFromUtc());
break;
case Qt::TimeZone:
#ifndef QT_BOOTSTRAPPED
spec = QStringLiteral(" Qt::TimeZone ") + date.timeZone().id();
break;
#endif // QT_BOOTSTRAPPED
case Qt::LocalTime:
spec = QStringLiteral(" Qt::LocalTime");
break;

View File

@ -50,6 +50,7 @@
QT_BEGIN_NAMESPACE
class QTimeZone;
class Q_CORE_EXPORT QDate
{
@ -208,6 +209,9 @@ public:
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);
#ifndef QT_BOOTSTRAPPED
QDateTime(const QDate &date, const QTime &time, const QTimeZone &timeZone);
#endif // QT_BOOTSTRAPPED
QDateTime(const QDateTime &other);
~QDateTime();
@ -222,6 +226,9 @@ public:
QTime time() const;
Qt::TimeSpec timeSpec() const;
int offsetFromUtc() const;
#ifndef QT_BOOTSTRAPPED
QTimeZone timeZone() const;
#endif // QT_BOOTSTRAPPED
QString timeZoneAbbreviation() const;
bool isDaylightTime() const;
@ -233,6 +240,9 @@ public:
void setTime(const QTime &time);
void setTimeSpec(Qt::TimeSpec spec);
void setOffsetFromUtc(int offsetSeconds);
#ifndef QT_BOOTSTRAPPED
void setTimeZone(const QTimeZone &toZone);
#endif // QT_BOOTSTRAPPED
void setMSecsSinceEpoch(qint64 msecs);
// ### Qt 6: use quint64 instead of uint
void setTime_t(uint secsSince1Jan1970UTC);
@ -251,6 +261,9 @@ public:
inline QDateTime toLocalTime() const { return toTimeSpec(Qt::LocalTime); }
inline QDateTime toUTC() const { return toTimeSpec(Qt::UTC); }
QDateTime toOffsetFromUtc(int offsetSeconds) const;
#ifndef QT_BOOTSTRAPPED
QDateTime toTimeZone(const QTimeZone &toZone) const;
#endif // QT_BOOTSTRAPPED
qint64 daysTo(const QDateTime &) const;
qint64 secsTo(const QDateTime &) const;
@ -279,9 +292,15 @@ public:
// ### Qt 6: Merge with above with default spec = Qt::LocalTime
static QDateTime fromTime_t(uint secsSince1Jan1970UTC, Qt::TimeSpec spec,
int offsetFromUtc = 0);
#ifndef QT_BOOTSTRAPPED
static QDateTime fromTime_t(uint secsSince1Jan1970UTC, const QTimeZone &timeZone);
#endif
static QDateTime fromMSecsSinceEpoch(qint64 msecs);
// ### Qt 6: Merge with above with default spec = Qt::LocalTime
static QDateTime fromMSecsSinceEpoch(qint64 msecs, Qt::TimeSpec spec, int offsetFromUtc = 0);
#ifndef QT_BOOTSTRAPPED
static QDateTime fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone);
#endif
static qint64 currentMSecsSinceEpoch() Q_DECL_NOTHROW;
private:

View File

@ -57,6 +57,8 @@
#include "QtCore/qatomic.h"
#include "QtCore/qdatetime.h"
#include "qtimezone.h"
QT_BEGIN_NAMESPACE
class QDateTimePrivate : public QSharedData
@ -69,7 +71,8 @@ public:
LocalStandard = 0,
LocalDST = 1,
UTC = 2,
OffsetFromUTC = 3
OffsetFromUTC = 3,
TimeZone = 4
};
// Daylight Time Status
@ -86,7 +89,8 @@ public:
NullTime = 0x02,
ValidDate = 0x04,
ValidTime = 0x08,
ValidDateTime = 0x10
ValidDateTime = 0x10,
TimeZoneCached = 0x20
};
Q_DECLARE_FLAGS(StatusFlags, StatusFlag)
@ -99,16 +103,26 @@ public:
QDateTimePrivate(const QDate &toDate, const QTime &toTime, Qt::TimeSpec toSpec,
int offsetSeconds);
#ifndef QT_BOOTSTRAPPED
QDateTimePrivate(const QDate &toDate, const QTime &toTime, const QTimeZone & timeZone);
#endif // QT_BOOTSTRAPPED
QDateTimePrivate(const QDateTimePrivate &other) : QSharedData(other),
m_msecs(other.m_msecs),
m_spec(other.m_spec),
m_offsetFromUtc(other.m_offsetFromUtc),
#ifndef QT_BOOTSTRAPPED
m_timeZone(other.m_timeZone),
#endif // QT_BOOTSTRAPPED
m_status(other.m_status)
{}
qint64 m_msecs;
Qt::TimeSpec m_spec;
int m_offsetFromUtc;
#ifndef QT_BOOTSTRAPPED
QTimeZone m_timeZone;
#endif // QT_BOOTSTRAPPED
StatusFlags m_status;
void setTimeSpec(Qt::TimeSpec spec, int offsetSeconds);
@ -129,6 +143,14 @@ public:
inline bool isValidDateTime() const { return (m_status & ValidDateTime) == ValidDateTime; }
inline void setValidDateTime() { m_status = m_status | ValidDateTime; }
inline void clearValidDateTime() { m_status = m_status & ~ValidDateTime; }
inline bool isTimeZoneCached() const { return (m_status & TimeZoneCached) == TimeZoneCached; }
inline void setTimeZoneCached() { m_status = m_status | TimeZoneCached; }
inline void clearTimeZoneCached() { m_status = m_status & ~TimeZoneCached; }
#ifndef QT_BOOTSTRAPPED
static qint64 zoneMSecsToEpochMSecs(qint64 msecs, const QTimeZone &zone,
QDate *localDate, QTime *localTime);
#endif // QT_BOOTSTRAPPED
static inline qint64 minJd() { return QDate::minJd(); }
static inline qint64 maxJd() { return QDate::maxJd(); }

View File

@ -143,6 +143,8 @@ private:
friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &ds, const QTimeZone &tz);
#endif
friend class QTimeZonePrivate;
friend class QDateTime;
friend class QDateTimePrivate;
QSharedDataPointer<QTimeZonePrivate> d;
};

View File

@ -48,6 +48,10 @@
QT_BEGIN_NAMESPACE
enum {
MSECS_TRAN_WINDOW = 21600000 // 6 hour window for possible recent transitions
};
/*
Static utilities for looking up Windows ID tables
*/
@ -242,6 +246,67 @@ QTimeZonePrivate::Data QTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const
return invalidData();
}
// Private only method for use by QDateTime to convert local msecs to epoch msecs
// TODO Could be platform optimised if needed
QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs) const
{
if (!hasDaylightTime() ||!hasTransitions()) {
// No daylight time means same offset for all local msecs
// Having daylight time but no transitions means we can't calculate, so use nearest
return data(forLocalMSecs - (standardTimeOffset(forLocalMSecs) * 1000));
}
// Get the transition for the local msecs which most of the time should be the right one
// Only around the transition times might it not be the right one
Data tran = previousTransition(forLocalMSecs);
Data nextTran;
// If the local msecs is less than the real local time of the transition
// then get the previous transition to use instead
if (forLocalMSecs < tran.atMSecsSinceEpoch + (tran.offsetFromUtc * 1000)) {
while (forLocalMSecs < tran.atMSecsSinceEpoch + (tran.offsetFromUtc * 1000)) {
nextTran = tran;
tran = previousTransition(tran.atMSecsSinceEpoch);
}
} else {
// The zone msecs is after the transition, so check it is before the next tran
// If not try use the next transition instead
nextTran = nextTransition(tran.atMSecsSinceEpoch);
while (forLocalMSecs >= nextTran.atMSecsSinceEpoch + (nextTran.offsetFromUtc * 1000)) {
tran = nextTran;
nextTran = nextTransition(tran.atMSecsSinceEpoch);
}
}
if (tran.daylightTimeOffset == 0) {
// If tran is in StandardTime, then need to check if falls close either daylight transition
// If it does, then it may need adjusting for missing hour or for second occurrence
qint64 diffPrevTran = forLocalMSecs
- (tran.atMSecsSinceEpoch + (tran.offsetFromUtc * 1000));
qint64 diffNextTran = nextTran.atMSecsSinceEpoch + (nextTran.offsetFromUtc * 1000)
- forLocalMSecs;
if (diffPrevTran >= 0 && diffPrevTran < MSECS_TRAN_WINDOW) {
// If tran picked is for standard time check if changed from daylight in last 6 hours,
// as the local msecs may be ambiguous and represent two valid utc msecs.
// If in last 6 hours then get prev tran and if diff falls within the daylight offset
// then use the prev tran as we default to the FirstOccurrence
// TODO Check if faster to just always get prev tran, or if faster using 6 hour check.
Data dstTran = previousTransition(tran.atMSecsSinceEpoch);
if (dstTran.daylightTimeOffset > 0 && diffPrevTran < (dstTran.daylightTimeOffset * 1000))
tran = dstTran;
} else if (diffNextTran >= 0 && diffNextTran <= (nextTran.daylightTimeOffset * 1000)) {
// If time falls within last hour of standard time then is actually the missing hour
// So return the next tran instead and adjust the local time to be valid
tran = nextTran;
forLocalMSecs = forLocalMSecs + (nextTran.daylightTimeOffset * 1000);
}
}
// tran should now hold the right transition offset to use
tran.atMSecsSinceEpoch = forLocalMSecs - (tran.offsetFromUtc * 1000);
return tran;
}
bool QTimeZonePrivate::hasTransitions() const
{
return false;

View File

@ -120,6 +120,7 @@ public:
virtual bool isDaylightTime(qint64 atMSecsSinceEpoch) const;
virtual Data data(qint64 forMSecsSinceEpoch) const;
virtual Data dataForLocalTime(qint64 forLocalMSecs) const;
virtual bool hasTransitions() const;
virtual Data nextTransition(qint64 afterMSecsSinceEpoch) const;

View File

@ -145,6 +145,7 @@ private slots:
void isDaylightTime() const;
void daylightTransitions() const;
void timeZones() const;
private:
bool europeanTimeZone;
@ -547,6 +548,8 @@ void tst_QDateTime::setMSecsSinceEpoch()
dt.setMSecsSinceEpoch(msecs);
QCOMPARE(dt, utc);
QCOMPARE(dt.date(), utc.date());
QCOMPARE(dt.time(), utc.time());
QCOMPARE(dt.timeSpec(), Qt::UTC);
if (europeanTimeZone) {
@ -561,6 +564,23 @@ void tst_QDateTime::setMSecsSinceEpoch()
if (msecs != std::numeric_limits<qint64>::max())
QCOMPARE(localDt, utc);
QCOMPARE(localDt.timeSpec(), Qt::LocalTime);
// Compare result for LocalTime to TimeZone
QTimeZone europe("Europe/Oslo");
QDateTime dt2;
dt2.setTimeZone(europe);
dt2.setMSecsSinceEpoch(msecs);
QCOMPARE(dt2.date(), european.date());
#ifdef Q_OS_MAC
// NSTimeZone doesn't apply DST to high values
if (msecs < (Q_INT64_C(123456) << 32))
#else
// Linux and Win are OK except when they overflow
if (msecs != std::numeric_limits<qint64>::max())
#endif
QCOMPARE(dt2.time(), european.time());
QCOMPARE(dt2.timeSpec(), Qt::TimeZone);
QCOMPARE(dt2.timeZone(), europe);
}
QCOMPARE(dt.toMSecsSinceEpoch(), msecs);
@ -2107,6 +2127,12 @@ void tst_QDateTime::offsetFromUtc()
} else {
QSKIP("You must test using Central European (CET/CEST) time zone, e.g. TZ=Europe/Oslo");
}
QDateTime dt5(QDate(2013, 1, 1), QTime(0, 0, 0), QTimeZone("Pacific/Auckland"));
QCOMPARE(dt5.offsetFromUtc(), 46800);
QDateTime dt6(QDate(2013, 6, 1), QTime(0, 0, 0), QTimeZone("Pacific/Auckland"));
QCOMPARE(dt6.offsetFromUtc(), 43200);
}
void tst_QDateTime::setOffsetFromUtc()
@ -2232,6 +2258,17 @@ void tst_QDateTime::timeZoneAbbreviation()
} else {
QSKIP("You must test using Central European (CET/CEST) time zone, e.g. TZ=Europe/Oslo");
}
QDateTime dt5(QDate(2013, 1, 1), QTime(0, 0, 0), QTimeZone("Europe/Berlin"));
#ifdef Q_OS_WIN
QEXPECT_FAIL("", "QTimeZone windows backend only returns long name", Continue);
#endif
QCOMPARE(dt5.timeZoneAbbreviation(), QString("CET"));
QDateTime dt6(QDate(2013, 6, 1), QTime(0, 0, 0), QTimeZone("Europe/Berlin"));
#ifdef Q_OS_WIN
QEXPECT_FAIL("", "QTimeZone windows backend only returns long name", Continue);
#endif
QCOMPARE(dt6.timeZoneAbbreviation(), QString("CEST"));
}
void tst_QDateTime::getDate()
@ -2717,5 +2754,168 @@ void tst_QDateTime::daylightTransitions() const
}
}
void tst_QDateTime::timeZones() const
{
QTimeZone nzTz = QTimeZone("Pacific/Auckland");
// During Standard Time NZ is +12:00
QDateTime utcStd(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC);
QDateTime nzStd(QDate(2012, 6, 1), QTime(12, 0, 0), nzTz);
QCOMPARE(nzStd.isValid(), true);
QCOMPARE(nzStd.timeSpec(), Qt::TimeZone);
QCOMPARE(nzStd.date(), QDate(2012, 6, 1));
QCOMPARE(nzStd.time(), QTime(12, 0, 0));
QVERIFY(nzStd.timeZone() == nzTz);
QCOMPARE(nzStd.timeZone().id(), QByteArray("Pacific/Auckland"));
QCOMPARE(nzStd.offsetFromUtc(), 43200);
QCOMPARE(nzStd.isDaylightTime(), false);
QCOMPARE(nzStd.toMSecsSinceEpoch(), utcStd.toMSecsSinceEpoch());
// During Daylight Time NZ is +13:00
QDateTime utcDst(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC);
QDateTime nzDst(QDate(2012, 1, 1), QTime(13, 0, 0), nzTz);
QCOMPARE(nzDst.isValid(), true);
QCOMPARE(nzDst.date(), QDate(2012, 1, 1));
QCOMPARE(nzDst.time(), QTime(13, 0, 0));
QCOMPARE(nzDst.offsetFromUtc(), 46800);
QCOMPARE(nzDst.isDaylightTime(), true);
QCOMPARE(nzDst.toMSecsSinceEpoch(), utcDst.toMSecsSinceEpoch());
QDateTime utc = nzStd.toUTC();
QCOMPARE(utc.date(), utcStd.date());
QCOMPARE(utc.time(), utcStd.time());
utc = nzDst.toUTC();
QCOMPARE(utc.date(), utcDst.date());
QCOMPARE(utc.time(), utcDst.time());
// Sydney is 2 hours behind New Zealand
QTimeZone ausTz = QTimeZone("Australia/Sydney");
QDateTime aus = nzStd.toTimeZone(ausTz);
QCOMPARE(aus.date(), QDate(2012, 6, 1));
QCOMPARE(aus.time(), QTime(10, 0, 0));
QDateTime dt1(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC);
QCOMPARE(dt1.timeSpec(), Qt::UTC);
dt1.setTimeZone(nzTz);
QCOMPARE(dt1.timeSpec(), Qt::TimeZone);
QCOMPARE(dt1.date(), QDate(2012, 6, 1));
QCOMPARE(dt1.time(), QTime(0, 0, 0));
QCOMPARE(dt1.timeZone(), nzTz);
QDateTime dt2 = QDateTime::fromTime_t(1338465600, nzTz);
QCOMPARE(dt2.date(), dt1.date());
QCOMPARE(dt2.time(), dt1.time());
QCOMPARE(dt2.timeSpec(), dt1.timeSpec());
QCOMPARE(dt2.timeZone(), dt1.timeZone());
QDateTime dt3 = QDateTime::fromMSecsSinceEpoch(1338465600000, nzTz);
QCOMPARE(dt3.date(), dt1.date());
QCOMPARE(dt3.time(), dt1.time());
QCOMPARE(dt3.timeSpec(), dt1.timeSpec());
QCOMPARE(dt3.timeZone(), dt1.timeZone());
// Check datastream serialises the time zone
QByteArray tmp;
{
QDataStream ds(&tmp, QIODevice::WriteOnly);
ds << dt1;
}
QDateTime dt4;
{
QDataStream ds(&tmp, QIODevice::ReadOnly);
ds >> dt4;
}
QCOMPARE(dt4, dt1);
QCOMPARE(dt4.timeSpec(), Qt::TimeZone);
QCOMPARE(dt4.timeZone(), nzTz);
// Check handling of transition times
QTimeZone cet("Europe/Oslo");
// Standard Time to Daylight Time 2013 on 2013-03-31 is 2:00 local time / 1:00 UTC
qint64 stdToDstMSecs = 1364691600000;
// Test MSecs to local
// - Test 1 msec before tran = 01:59:59.999
QDateTime beforeDst = QDateTime::fromMSecsSinceEpoch(stdToDstMSecs - 1, cet);
QCOMPARE(beforeDst.date(), QDate(2013, 3, 31));
QCOMPARE(beforeDst.time(), QTime(1, 59, 59, 999));
// - Test at tran = 03:00:00
QDateTime atDst = QDateTime::fromMSecsSinceEpoch(stdToDstMSecs, cet);
QCOMPARE(atDst.date(), QDate(2013, 3, 31));
QCOMPARE(atDst.time(), QTime(3, 0, 0));
// Test local to MSecs
// - Test 1 msec before tran = 01:59:59.999
beforeDst = QDateTime(QDate(2013, 3, 31), QTime(1, 59, 59, 999), cet);
QCOMPARE(beforeDst.toMSecsSinceEpoch(), stdToDstMSecs - 1);
// - Test at tran = 03:00:00
atDst = QDateTime(QDate(2013, 3, 31), QTime(3, 0, 0), cet);
QCOMPARE(atDst.toMSecsSinceEpoch(), stdToDstMSecs);
// - Test transition hole, setting 03:00:00 is valid
atDst = QDateTime(QDate(2013, 3, 31), QTime(3, 0, 0), cet);
QVERIFY(atDst.isValid());
QCOMPARE(atDst.date(), QDate(2013, 3, 31));
QCOMPARE(atDst.time(), QTime(3, 0, 0));
QCOMPARE(atDst.toMSecsSinceEpoch(), stdToDstMSecs);
// - Test transition hole, setting 02:00:00 is invalid
atDst = QDateTime(QDate(2013, 3, 31), QTime(2, 0, 0), cet);
QVERIFY(!atDst.isValid());
QCOMPARE(atDst.date(), QDate(2013, 3, 31));
QCOMPARE(atDst.time(), QTime(2, 0, 0));
// - Test transition hole, setting 02:59:59.999 is invalid
atDst = QDateTime(QDate(2013, 3, 31), QTime(2, 59, 59, 999), cet);
QVERIFY(!atDst.isValid());
QCOMPARE(atDst.date(), QDate(2013, 3, 31));
QCOMPARE(atDst.time(), QTime(2, 59, 59, 999));
// Standard Time to Daylight Time 2013 on 2013-10-27 is 3:00 local time / 1:00 UTC
qint64 dstToStdMSecs = 1382835600000;
// Test MSecs to local
// - Test 1 hour before tran = 02:00:00 local first occurrence
QDateTime hourBeforeStd = QDateTime::fromMSecsSinceEpoch(dstToStdMSecs - 3600000, cet);
QCOMPARE(hourBeforeStd.date(), QDate(2013, 10, 27));
QCOMPARE(hourBeforeStd.time(), QTime(2, 0, 0));
// - Test 1 msec before tran = 02:59:59.999 local first occurrence
QDateTime msecBeforeStd = QDateTime::fromMSecsSinceEpoch(dstToStdMSecs - 1, cet);
QCOMPARE(msecBeforeStd.date(), QDate(2013, 10, 27));
QCOMPARE(msecBeforeStd.time(), QTime(2, 59, 59, 999));
// - Test at tran = 03:00:00 local becomes 02:00:00 local second occurrence
QDateTime atStd = QDateTime::fromMSecsSinceEpoch(dstToStdMSecs, cet);
QCOMPARE(atStd.date(), QDate(2013, 10, 27));
QCOMPARE(atStd.time(), QTime(2, 0, 0));
// - Test 59 mins after tran = 02:59:59.999 local second occurrence
QDateTime afterStd = QDateTime::fromMSecsSinceEpoch(dstToStdMSecs + 3600000 -1, cet);
QCOMPARE(afterStd.date(), QDate(2013, 10, 27));
QCOMPARE(afterStd.time(), QTime(2, 59, 59, 999));
// - Test 1 hour after tran = 03:00:00 local
QDateTime hourAfterStd = QDateTime::fromMSecsSinceEpoch(dstToStdMSecs + 3600000, cet);
QCOMPARE(hourAfterStd.date(), QDate(2013, 10, 27));
QCOMPARE(hourAfterStd.time(), QTime(3, 00, 00));
// Test local to MSecs
// - Test first occurrence 02:00:00 = 1 hour before tran
hourBeforeStd = QDateTime(QDate(2013, 10, 27), QTime(2, 0, 0), cet);
QCOMPARE(hourBeforeStd.toMSecsSinceEpoch(), dstToStdMSecs - 3600000);
// - Test first occurrence 02:59:59.999 = 1 msec before tran
msecBeforeStd = QDateTime(QDate(2013, 10, 27), QTime(2, 59, 59, 999), cet);
QCOMPARE(msecBeforeStd.toMSecsSinceEpoch(), dstToStdMSecs - 1);
// - Test second occurrence 02:00:00 = at tran
atStd = QDateTime(QDate(2013, 10, 27), QTime(2, 0, 0), cet);
QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue);
QCOMPARE(atStd.toMSecsSinceEpoch(), dstToStdMSecs);
// - Test second occurrence 03:00:00 = 59 mins after tran
afterStd = QDateTime(QDate(2013, 10, 27), QTime(2, 59, 59, 999), cet);
QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue);
QCOMPARE(afterStd.toMSecsSinceEpoch(), dstToStdMSecs + 3600000 - 1);
// - Test 03:00:00 = 1 hour after tran
hourAfterStd = QDateTime(QDate(2013, 10, 27), QTime(3, 0, 0), cet);
QCOMPARE(hourAfterStd.toMSecsSinceEpoch(), dstToStdMSecs + 3600000);
}
QTEST_APPLESS_MAIN(tst_QDateTime)
#include "tst_qdatetime.moc"

View File

@ -1303,6 +1303,18 @@ void tst_QLocale::formatTimeZone()
QSKIP("You must test using Central European (CET/CEST) time zone, e.g. TZ=Europe/Oslo");
}
QDateTime dt6(QDate(2013, 1, 1), QTime(0, 0, 0), QTimeZone("Europe/Berlin"));
#ifdef Q_OS_WIN
QEXPECT_FAIL("", "QTimeZone windows backend only returns long name", Continue);
#endif
QCOMPARE(enUS.toString(dt6, "t"), QString("CET"));
QDateTime dt7(QDate(2013, 6, 1), QTime(0, 0, 0), QTimeZone("Europe/Berlin"));
#ifdef Q_OS_WIN
QEXPECT_FAIL("", "QTimeZone windows backend only returns long name", Continue);
#endif
QCOMPARE(enUS.toString(dt7, "t"), QString("CEST"));
// Current datetime should return current abbreviation
QCOMPARE(enUS.toString(QDateTime::currentDateTime(), "t"),
QDateTime::currentDateTime().timeZoneAbbreviation());

View File

@ -39,7 +39,8 @@
**
****************************************************************************/
#include <QLocale>
#include <QDateTime>
#include <QTimeZone>
#include <QTest>
#include <qdebug.h>
@ -71,21 +72,27 @@ private Q_SLOTS:
void toMSecsSinceEpoch();
void toMSecsSinceEpoch1950();
void toMSecsSinceEpoch2050();
void toMSecsSinceEpochTz();
void toMSecsSinceEpoch1950Tz();
void toMSecsSinceEpoch2050Tz();
void toTime_t();
void setDate();
void setTime();
void setTimeSpec();
void setOffsetFromUtc();
void setMSecsSinceEpoch();
void setMSecsSinceEpochTz();
void setTime_t();
void toString();
void toStringTextFormat();
void toStringIsoFormat();
void addDays();
void addDaysTz();
void addMonths();
void addYears();
void addSecs();
void addMSecs();
void addMSecsTz();
void toTimeSpec();
void toOffsetFromUtc();
void daysTo();
@ -106,6 +113,7 @@ private Q_SLOTS:
void fromTime_t();
void fromMSecsSinceEpoch();
void fromMSecsSinceEpochUtc();
void fromMSecsSinceEpochTz();
};
void tst_QDateTime::create()
@ -228,6 +236,42 @@ void tst_QDateTime::toMSecsSinceEpoch2050()
}
}
void tst_QDateTime::toMSecsSinceEpochTz()
{
QTimeZone cet = QTimeZone("Europe/Oslo");
QList<QDateTime> list;
for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd)
list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0), cet));
QBENCHMARK {
foreach (const QDateTime &test, list)
qint64 result = test.toMSecsSinceEpoch();
}
}
void tst_QDateTime::toMSecsSinceEpoch1950Tz()
{
QTimeZone cet = QTimeZone("Europe/Oslo");
QList<QDateTime> list;
for (int jd = JULIAN_DAY_1950; jd < JULIAN_DAY_1960; ++jd)
list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0), cet));
QBENCHMARK {
foreach (const QDateTime &test, list)
qint64 result = test.toMSecsSinceEpoch();
}
}
void tst_QDateTime::toMSecsSinceEpoch2050Tz()
{
QTimeZone cet = QTimeZone("Europe/Oslo");
QList<QDateTime> list;
for (int jd = JULIAN_DAY_2050; jd < JULIAN_DAY_2060; ++jd)
list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0), cet));
QBENCHMARK {
foreach (const QDateTime &test, list)
qint64 result = test.toMSecsSinceEpoch();
}
}
void tst_QDateTime::toTime_t()
{
QList<QDateTime> list;
@ -295,6 +339,18 @@ void tst_QDateTime::setMSecsSinceEpoch()
}
}
void tst_QDateTime::setMSecsSinceEpochTz()
{
QTimeZone cet = QTimeZone("Europe/Oslo");
QList<QDateTime> list;
for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd)
list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0), cet));
QBENCHMARK {
foreach (QDateTime test, list)
test.setMSecsSinceEpoch((JULIAN_DAY_2010 + 180) * MSECS_PER_DAY);
}
}
void tst_QDateTime::setTime_t()
{
time_t secs = time_t(JULIAN_DAY_2010 + 180) * SECS_PER_DAY;
@ -351,6 +407,18 @@ void tst_QDateTime::addDays()
}
}
void tst_QDateTime::addDaysTz()
{
QTimeZone cet = QTimeZone("Europe/Oslo");
QList<QDateTime> list;
for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd)
list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0), cet));
QBENCHMARK {
foreach (const QDateTime &test, list)
QDateTime result = test.addDays(1);
}
}
void tst_QDateTime::addMonths()
{
QList<QDateTime> list;
@ -395,6 +463,18 @@ void tst_QDateTime::addMSecs()
}
}
void tst_QDateTime::addMSecsTz()
{
QTimeZone cet = QTimeZone("Europe/Oslo");
QList<QDateTime> list;
for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd)
list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0), cet));
QBENCHMARK {
foreach (const QDateTime &test, list)
QDateTime result = test.addMSecs(1);
}
}
void tst_QDateTime::toTimeSpec()
{
QList<QDateTime> list;
@ -601,6 +681,15 @@ void tst_QDateTime::fromMSecsSinceEpochUtc()
}
}
void tst_QDateTime::fromMSecsSinceEpochTz()
{
QTimeZone cet = QTimeZone("Europe/Oslo");
QBENCHMARK {
for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd)
QDateTime test = QDateTime::fromMSecsSinceEpoch(jd * MSECS_PER_DAY, cet);
}
}
QTEST_MAIN(tst_QDateTime)
#include "main.moc"