Adapt QDateTime to route QTimeSpec uses via QTimeZone

Free most APIs using QTimeZone from feature timezone and route all
APIs taking a naked QTimeSpec via these, in preparation for their
eventual deprecation. Since qtimezone.h includes qdatetime.h (and MSVC
blocks our ability to remove the need for that), qdatetime.h's
declarations can't use a default value for QTimeZone parameters; so
add overloads taking no zone (or spec) to handle that.

[ChangeLog][QtCore][QDateTime] All QDateTime APIs involving a
Qt::TimeSpec can now be routed via QTimeZone's lightweight time
description support, saving the need to have different code paths for
different time specs. In the process, QDateTime gains a
timeRepresentation() method to return a QTimeZone reporting the
(possibly lightweight) time description it uses. (The older timeZone()
method always returns a non-lightweight QTimeZone, whose timeSpec() is
Qt::TimeZone.)

Task-number: QTBUG-108199
Change-Id: I23e43401eb2dbe9b7b534ca6401389920dd96b3c
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Edward Welbourne 2022-11-22 20:54:54 +01:00
parent ae6186c7e8
commit f46c18c627
5 changed files with 502 additions and 416 deletions

View File

@ -189,3 +189,11 @@ QDate firstMonday = 2020y / January / Monday[0];
// Last Monday of January 2020:
QDate lastMonday = 2020y / January / Monday[last];
//! [22]
//! [23]
QDateTime local(QDateTime::currentDateTime());
QDateTime UTC(local.toTimeSpec(QTimeZone::UTC));
qDebug() << "Local time is:" << local;
qDebug() << "UTC time is:" << UTC;
qDebug() << "No difference between times represented:" << local.secsTo(UTC);
//! [23]

File diff suppressed because it is too large Load Diff

View File

@ -5,10 +5,10 @@
#ifndef QDATETIME_H
#define QDATETIME_H
#include <QtCore/qstring.h>
#include <QtCore/qcalendar.h>
#include <QtCore/qnamespace.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qcalendar.h>
#include <QtCore/qstring.h>
#include <limits>
#include <chrono>
@ -20,9 +20,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(NSDate);
QT_BEGIN_NAMESPACE
#if QT_CONFIG(timezone)
class QTimeZone;
#endif
class QDateTime;
class Q_CORE_EXPORT QDate
@ -105,12 +103,12 @@ public:
int daysInMonth(QCalendar cal) const;
int daysInYear(QCalendar cal) const;
QDateTime startOfDay(Qt::TimeSpec spec = Qt::LocalTime, int offsetSeconds = 0) const;
QDateTime endOfDay(Qt::TimeSpec spec = Qt::LocalTime, int offsetSeconds = 0) const;
#if QT_CONFIG(timezone)
QDateTime startOfDay(Qt::TimeSpec spec, int offsetSeconds = 0) const;
QDateTime endOfDay(Qt::TimeSpec spec, int offsetSeconds = 0) const;
QDateTime startOfDay(const QTimeZone &zone) const;
QDateTime endOfDay(const QTimeZone &zone) const;
#endif
QDateTime startOfDay() const;
QDateTime endOfDay() const;
#if QT_CONFIG(datestring)
QString toString(Qt::DateFormat format = Qt::TextDate) const;
@ -286,7 +284,7 @@ class Q_CORE_EXPORT QDateTime
};
Data() noexcept;
Data(Qt::TimeSpec);
Data(const QTimeZone &);
Data(const Data &other) noexcept;
Data(Data &&other) noexcept;
Data &operator=(const Data &other) noexcept;
@ -298,6 +296,7 @@ class Q_CORE_EXPORT QDateTime
bool isShort() const;
void detach();
QTimeZone timeZone() const;
const QDateTimePrivate *operator->() const;
QDateTimePrivate *operator->();
@ -308,10 +307,9 @@ class Q_CORE_EXPORT QDateTime
public:
QDateTime() noexcept;
QDateTime(QDate date, QTime time, Qt::TimeSpec spec = Qt::LocalTime, int offsetSeconds = 0);
#if QT_CONFIG(timezone)
QDateTime(QDate date, QTime time, Qt::TimeSpec spec, int offsetSeconds = 0);
QDateTime(QDate date, QTime time, const QTimeZone &timeZone);
#endif // timezone
QDateTime(QDate date, QTime time);
QDateTime(const QDateTime &other) noexcept;
QDateTime(QDateTime &&other) noexcept;
~QDateTime();
@ -328,6 +326,7 @@ public:
QTime time() const;
Qt::TimeSpec timeSpec() const;
int offsetFromUtc() const;
QTimeZone timeRepresentation() const;
#if QT_CONFIG(timezone)
QTimeZone timeZone() const;
#endif // timezone
@ -341,9 +340,7 @@ public:
void setTime(QTime time);
void setTimeSpec(Qt::TimeSpec spec);
void setOffsetFromUtc(int offsetSeconds);
#if QT_CONFIG(timezone)
void setTimeZone(const QTimeZone &toZone);
#endif // timezone
void setMSecsSinceEpoch(qint64 msecs);
void setSecsSinceEpoch(qint64 secs);
@ -367,9 +364,7 @@ public:
QDateTime toLocalTime() const;
QDateTime toUTC() const;
QDateTime toOffsetFromUtc(int offsetSeconds) const;
#if QT_CONFIG(timezone)
QDateTime toTimeZone(const QTimeZone &toZone) const;
#endif // timezone
qint64 daysTo(const QDateTime &) const;
qint64 secsTo(const QDateTime &) const;
@ -391,15 +386,13 @@ public:
{ return fromString(string, qToStringViewIgnoringNull(format), cal); }
#endif
static QDateTime fromMSecsSinceEpoch(qint64 msecs, Qt::TimeSpec spec = Qt::LocalTime,
int offsetFromUtc = 0);
static QDateTime fromSecsSinceEpoch(qint64 secs, Qt::TimeSpec spec = Qt::LocalTime,
int offsetFromUtc = 0);
static QDateTime fromMSecsSinceEpoch(qint64 msecs, Qt::TimeSpec spec, int offsetFromUtc = 0);
static QDateTime fromSecsSinceEpoch(qint64 secs, Qt::TimeSpec spec, int offsetFromUtc = 0);
#if QT_CONFIG(timezone)
static QDateTime fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone);
static QDateTime fromSecsSinceEpoch(qint64 secs, const QTimeZone &timeZone);
#endif
static QDateTime fromMSecsSinceEpoch(qint64 msecs);
static QDateTime fromSecsSinceEpoch(qint64 secs);
static qint64 currentMSecsSinceEpoch() noexcept;
static qint64 currentSecsSinceEpoch() noexcept;

View File

@ -21,6 +21,7 @@
#include "QtCore/qatomic.h"
#include "QtCore/qdatetime.h"
#include "QtCore/qshareddata.h"
#include "QtCore/qtimezone.h"
#if QT_CONFIG(timezone)
#include "qtimezone.h"
@ -88,12 +89,8 @@ public:
: when(w), offset(o), dst(d), valid(v) {}
};
static QDateTime::Data create(QDate toDate, QTime toTime, Qt::TimeSpec toSpec,
int offsetSeconds);
static QDateTime::Data create(QDate toDate, QTime toTime, const QTimeZone &timeZone);
#if QT_CONFIG(timezone)
static QDateTime::Data create(QDate toDate, QTime toTime, const QTimeZone & timeZone);
static ZoneState zoneStateAtMillis(const QTimeZone &zone, qint64 millis, DaylightStatus dst);
#endif // timezone
@ -105,9 +102,7 @@ public:
StatusFlags m_status = StatusFlag(Qt::LocalTime << TimeSpecShift);
qint64 m_msecs = 0;
int m_offsetFromUtc = 0;
#if QT_CONFIG(timezone)
QTimeZone m_timeZone;
#endif // timezone
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimePrivate::StatusFlags)

View File

@ -40,6 +40,8 @@ private Q_SLOTS:
void setDate();
void setTime_data();
void setTime();
void setTimeZone_data();
void setTimeZone();
void setTimeSpec_data();
void setTimeSpec();
void setSecsSinceEpoch();
@ -520,6 +522,57 @@ void tst_QDateTime::setTime()
QCOMPARE(dateTime.timeSpec(), expectedTimeSpec);
}
void tst_QDateTime::setTimeZone_data()
{
QTest::addColumn<QDateTime>("dateTime");
QTest::addColumn<QTimeZone>("zone");
const QDate day(2004, 3, 25);
const QTime time(0, 45, 57);
struct {
const char *id;
QTimeZone zone;
} data[] = {
{ nullptr, QTimeZone() }, // For time-zone, when supported.
{ "UTC", QTimeZone::UTC },
{ "LocalTime", QTimeZone() },
{ "Offset", QTimeZone::fromSecondsAheadOfUtc(3600) }
};
#if QT_CONFIG(timezone)
const QTimeZone cet("Europe/Oslo");
if (cet.isValid()) {
data[0].zone = cet;
data[0].id = "Zone";
}
#endif
for (const auto &from : data) {
if (from.id) {
for (const auto &to : data) {
if (to.id) {
QTest::addRow("%s => %s", from.id, to.id)
<< QDateTime(day, time, from.zone) << to.zone;
}
}
}
}
}
void tst_QDateTime::setTimeZone()
{
QFETCH(QDateTime, dateTime);
QFETCH(QTimeZone, zone);
// QDateTime::setTimeZone() preserves the date and time rather than
// converting to the new time representation.
const QDate expectedDate(dateTime.date());
const QTime expectedTime(dateTime.time());
dateTime.setTimeZone(zone);
QCOMPARE(dateTime.date(), expectedDate);
QCOMPARE(dateTime.time(), expectedTime);
QCOMPARE(dateTime.timeRepresentation(), zone);
}
void tst_QDateTime::setTimeSpec_data()
{
QTest::addColumn<QDateTime>("dateTime");