Port QDateTimeEdit internals to QTimeZone

In the process, centralize the creation of date-time values, where
doing so requires catching invalid results caused by spring-forward
gaps; this saves some repetition and extends the treatment to more
places that did need it. Also, de-inline two overrides of virtuals;
being inline does them no good.

Replace the Qt::TimeSpec member of QDTEPrivate with a QTimeZone so
that creation of values can be streamlined and to make it easier to
add support for (currently unsupported) OffsetFromUTC and TimeZone
timespecs in the public QDTE API.

This greatly simplifies a lot of the code, while preparing it for a
long-needed extension to its functionality.

Task-number: QTBUG-80417
Task-number: QTBUG-108199
Change-Id: I0ac2c78025013bf89899e3ef1a56e89392f67ce5
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Edward Welbourne 2022-08-24 16:07:26 +02:00
parent 3f282e8896
commit 5da038ab51
3 changed files with 119 additions and 135 deletions

View File

@ -16,9 +16,6 @@
#include <qset.h> #include <qset.h>
#include <qstyle.h> #include <qstyle.h>
#include <qstylepainter.h> #include <qstylepainter.h>
#if QT_CONFIG(timezone)
#include <QTimeZone>
#endif
#include <algorithm> #include <algorithm>
@ -190,8 +187,8 @@ QDateTimeEdit::QDateTimeEdit(QTime time, QWidget *parent)
\internal \internal
*/ */
QDateTimeEdit::QDateTimeEdit(const QVariant &var, QMetaType::Type parserType, QWidget *parent) QDateTimeEdit::QDateTimeEdit(const QVariant &var, QMetaType::Type parserType, QWidget *parent)
: QAbstractSpinBox(*new QDateTimeEditPrivate( : QAbstractSpinBox(*new QDateTimeEditPrivate(parserType == QMetaType::QDateTime
parserType == QMetaType::QDateTime ? Qt::LocalTime : Qt::UTC), ? QTimeZone::LocalTime : QTimeZone::UTC),
parent) parent)
{ {
Q_D(QDateTimeEdit); Q_D(QDateTimeEdit);
@ -210,8 +207,8 @@ QDateTimeEdit::~QDateTimeEdit()
\property QDateTimeEdit::dateTime \property QDateTimeEdit::dateTime
\brief The QDateTime that is set in the QDateTimeEdit. \brief The QDateTime that is set in the QDateTimeEdit.
When setting this property, the new QDateTime is converted to the timespec of When setting this property, the new QDateTime is converted to the time system
the QDateTimeEdit, which thus remains unchanged. of the QDateTimeEdit, which thus remains unchanged.
By default, this property is set to the start of 2000 CE. It can only be set By default, this property is set to the start of 2000 CE. It can only be set
to a valid QDateTime value. If any operation causes this property to have an to a valid QDateTime value. If any operation causes this property to have an
@ -235,8 +232,8 @@ void QDateTimeEdit::setDateTime(const QDateTime &datetime)
{ {
Q_D(QDateTimeEdit); Q_D(QDateTimeEdit);
if (datetime.isValid()) { if (datetime.isValid()) {
QDateTime when = d->convertTimeSpec(datetime); QDateTime when = d->convertTimeZone(datetime);
Q_ASSERT(when.timeSpec() == d->spec); Q_ASSERT(when.timeRepresentation() == d->timeZone);
d->clearCache(); d->clearCache();
const QDate date = when.date(); const QDate date = when.date();
@ -272,14 +269,10 @@ void QDateTimeEdit::setDate(QDate date)
setDateRange(date, date); setDateRange(date, date);
d->clearCache(); d->clearCache();
QDateTime when(date, d->value.toTime(), d->spec); QDateTime when = d->dateTimeValue(date, d->value.toTime());
// The specified time might not exist on the specified day,
// i.e. the time is in the gap a spring-forward jumps over.
if (!when.isValid())
when = QDateTime::fromMSecsSinceEpoch(when.toMSecsSinceEpoch(), d->spec);
Q_ASSERT(when.isValid()); Q_ASSERT(when.isValid());
d->setValue(when, EmitIfChanged); d->setValue(when, EmitIfChanged);
d->updateTimeSpec(); d->updateTimeZone();
} }
} }
@ -306,7 +299,7 @@ void QDateTimeEdit::setTime(QTime time)
Q_D(QDateTimeEdit); Q_D(QDateTimeEdit);
if (time.isValid()) { if (time.isValid()) {
d->clearCache(); d->clearCache();
d->setValue(QDateTime(d->value.toDate(), time, d->spec), EmitIfChanged); d->setValue(d->dateTimeValue(d->value.toDate(), time), EmitIfChanged);
} }
} }
@ -363,7 +356,7 @@ void QDateTimeEdit::setMinimumDateTime(const QDateTime &dt)
{ {
Q_D(QDateTimeEdit); Q_D(QDateTimeEdit);
if (dt.isValid() && dt.date() >= QDATETIMEEDIT_DATE_MIN) { if (dt.isValid() && dt.date() >= QDATETIMEEDIT_DATE_MIN) {
const QDateTime m = dt.toTimeSpec(d->spec); const QDateTime m = dt.toTimeZone(d->timeZone);
const QDateTime max = d->maximum.toDateTime(); const QDateTime max = d->maximum.toDateTime();
d->setRange(m, (max > m ? max : m)); d->setRange(m, (max > m ? max : m));
} }
@ -405,7 +398,7 @@ void QDateTimeEdit::setMaximumDateTime(const QDateTime &dt)
{ {
Q_D(QDateTimeEdit); Q_D(QDateTimeEdit);
if (dt.isValid() && dt.date() <= QDATETIMEEDIT_DATE_MAX) { if (dt.isValid() && dt.date() <= QDATETIMEEDIT_DATE_MAX) {
const QDateTime m = dt.toTimeSpec(d->spec); const QDateTime m = dt.toTimeZone(d->timeZone);
const QDateTime min = d->minimum.toDateTime(); const QDateTime min = d->minimum.toDateTime();
d->setRange((min < m ? min : m), m); d->setRange((min < m ? min : m), m);
} }
@ -439,8 +432,8 @@ void QDateTimeEdit::setDateTimeRange(const QDateTime &min, const QDateTime &max)
{ {
Q_D(QDateTimeEdit); Q_D(QDateTimeEdit);
// FIXME: does none of the range checks applied to setMin/setMax methods ! // FIXME: does none of the range checks applied to setMin/setMax methods !
const QDateTime minimum = min.toTimeSpec(d->spec); const QDateTime minimum = min.toTimeZone(d->timeZone);
const QDateTime maximum = (min > max ? minimum : max.toTimeSpec(d->spec)); const QDateTime maximum = (min > max ? minimum : max.toTimeZone(d->timeZone));
d->setRange(minimum, maximum); d->setRange(minimum, maximum);
} }
@ -475,9 +468,8 @@ QDate QDateTimeEdit::minimumDate() const
void QDateTimeEdit::setMinimumDate(QDate min) void QDateTimeEdit::setMinimumDate(QDate min)
{ {
Q_D(QDateTimeEdit); Q_D(QDateTimeEdit);
if (min.isValid() && min >= QDATETIMEEDIT_DATE_MIN) { if (min.isValid() && min >= QDATETIMEEDIT_DATE_MIN)
setMinimumDateTime(QDateTime(min, d->minimum.toTime(), d->spec)); setMinimumDateTime(d->dateTimeValue(min, d->minimum.toTime()));
}
} }
void QDateTimeEdit::clearMinimumDate() void QDateTimeEdit::clearMinimumDate()
@ -517,7 +509,7 @@ void QDateTimeEdit::setMaximumDate(QDate max)
{ {
Q_D(QDateTimeEdit); Q_D(QDateTimeEdit);
if (max.isValid()) if (max.isValid())
setMaximumDateTime(QDateTime(max, d->maximum.toTime(), d->spec)); setMaximumDateTime(d->dateTimeValue(max, d->maximum.toTime()));
} }
void QDateTimeEdit::clearMaximumDate() void QDateTimeEdit::clearMaximumDate()
@ -554,10 +546,8 @@ QTime QDateTimeEdit::minimumTime() const
void QDateTimeEdit::setMinimumTime(QTime min) void QDateTimeEdit::setMinimumTime(QTime min)
{ {
Q_D(QDateTimeEdit); Q_D(QDateTimeEdit);
if (min.isValid()) { if (min.isValid())
const QDateTime m(d->minimum.toDate(), min, d->spec); setMinimumDateTime(d->dateTimeValue(d->minimum.toDate(), min));
setMinimumDateTime(m);
}
} }
void QDateTimeEdit::clearMinimumTime() void QDateTimeEdit::clearMinimumTime()
@ -593,10 +583,8 @@ QTime QDateTimeEdit::maximumTime() const
void QDateTimeEdit::setMaximumTime(QTime max) void QDateTimeEdit::setMaximumTime(QTime max)
{ {
Q_D(QDateTimeEdit); Q_D(QDateTimeEdit);
if (max.isValid()) { if (max.isValid())
const QDateTime m(d->maximum.toDate(), max, d->spec); setMaximumDateTime(d->dateTimeValue(d->maximum.toDate(), max));
setMaximumDateTime(m);
}
} }
void QDateTimeEdit::clearMaximumTime() void QDateTimeEdit::clearMaximumTime()
@ -634,8 +622,8 @@ void QDateTimeEdit::setDateRange(QDate min, QDate max)
{ {
Q_D(QDateTimeEdit); Q_D(QDateTimeEdit);
if (min.isValid() && max.isValid()) { if (min.isValid() && max.isValid()) {
setDateTimeRange(QDateTime(min, d->minimum.toTime(), d->spec), setDateTimeRange(d->dateTimeValue(min, d->minimum.toTime()),
QDateTime(max, d->maximum.toTime(), d->spec)); d->dateTimeValue(max, d->maximum.toTime()));
} }
} }
@ -673,8 +661,8 @@ void QDateTimeEdit::setTimeRange(QTime min, QTime max)
{ {
Q_D(QDateTimeEdit); Q_D(QDateTimeEdit);
if (min.isValid() && max.isValid()) { if (min.isValid() && max.isValid()) {
setDateTimeRange(QDateTime(d->minimum.toDate(), min, d->spec), setDateTimeRange(d->dateTimeValue(d->minimum.toDate(), min),
QDateTime(d->maximum.toDate(), max, d->spec)); d->dateTimeValue(d->maximum.toDate(), max));
} }
} }
@ -957,7 +945,7 @@ void QDateTimeEdit::setDisplayFormat(const QString &format)
} }
} else if (dateShown && !timeShown) { } else if (dateShown && !timeShown) {
setTimeRange(QDATETIMEEDIT_TIME_MIN, QDATETIMEEDIT_TIME_MAX); setTimeRange(QDATETIMEEDIT_TIME_MIN, QDATETIMEEDIT_TIME_MAX);
d->value = d->value.toDate().startOfDay(d->spec); d->value = d->value.toDate().startOfDay(d->timeZone);
} }
d->updateEdit(); d->updateEdit();
d->_q_editorCursorPositionChanged(-1, 0); d->_q_editorCursorPositionChanged(-1, 0);
@ -1005,15 +993,27 @@ void QDateTimeEdit::setCalendarPopup(bool enable)
Qt::TimeSpec QDateTimeEdit::timeSpec() const Qt::TimeSpec QDateTimeEdit::timeSpec() const
{ {
Q_D(const QDateTimeEdit); Q_D(const QDateTimeEdit);
return d->spec; return d->timeZone.timeSpec();
} }
void QDateTimeEdit::setTimeSpec(Qt::TimeSpec spec) void QDateTimeEdit::setTimeSpec(Qt::TimeSpec spec)
{ {
Q_D(QDateTimeEdit); Q_D(QDateTimeEdit);
if (spec != d->spec) { if (spec != d->timeZone.timeSpec()) {
d->spec = spec; switch (spec) {
d->updateTimeSpec(); case Qt::UTC:
d->timeZone = QTimeZone::UTC;
break;
case Qt::LocalTime:
d->timeZone = QTimeZone::LocalTime;
break;
default:
qWarning() << "Ignoring attempt to set time-spec" << spec
<< "which is not yet supported by QDateTimeEdit";
// TODO: fix that QTBUG-80417.
return;
}
d->updateTimeZone();
} }
} }
@ -1389,7 +1389,7 @@ void QDateTimeEdit::stepBy(int steps)
d->updateCache(d->value, d->displayText()); d->updateCache(d->value, d->displayText());
d->setSelected(d->currentSectionIndex); d->setSelected(d->currentSectionIndex);
d->updateTimeSpec(); d->updateTimeZone();
} }
/*! /*!
@ -1421,6 +1421,8 @@ QDateTime QDateTimeEdit::dateTimeFromText(const QString &text) const
QString copy = text; QString copy = text;
int pos = d->edit->cursorPosition(); int pos = d->edit->cursorPosition();
QValidator::State state = QValidator::Acceptable; QValidator::State state = QValidator::Acceptable;
// TODO: if the format specifies time-zone, d->timeZone should change as
// determined by the parsed text.
return d->validateAndInterpret(copy, pos, state); return d->validateAndInterpret(copy, pos, state);
} }
@ -1454,7 +1456,8 @@ void QDateTimeEdit::fixup(QString &input) const
CorrectToPreviousValue correction is handled by QAbstractSpinBox. CorrectToPreviousValue correction is handled by QAbstractSpinBox.
*/ */
if (!value.isValid() && d->correctionMode == QAbstractSpinBox::CorrectToNearestValue) { if (!value.isValid() && d->correctionMode == QAbstractSpinBox::CorrectToNearestValue) {
value = QDateTime::fromMSecsSinceEpoch(value.toMSecsSinceEpoch(), value.timeSpec()); value = QDateTime::fromMSecsSinceEpoch(value.toMSecsSinceEpoch(),
value.timeRepresentation());
input = textFromDateTime(value); input = textFromDateTime(value);
} }
} }
@ -1703,54 +1706,46 @@ QDateEdit::~QDateEdit()
*/ */
QDateTimeEditPrivate::QDateTimeEditPrivate(Qt::TimeSpec timeSpec) QDateTimeEditPrivate::QDateTimeEditPrivate(const QTimeZone &zone)
: QDateTimeParser(QMetaType::QDateTime, QDateTimeParser::DateTimeEdit, QCalendar()), : QDateTimeParser(QMetaType::QDateTime, QDateTimeParser::DateTimeEdit, QCalendar()),
spec(timeSpec) timeZone(zone)
{ {
fixday = true; fixday = true;
type = QMetaType::QDateTime; type = QMetaType::QDateTime;
currentSectionIndex = FirstSectionIndex; currentSectionIndex = FirstSectionIndex;
first.pos = 0; first.pos = 0;
minimum = QDATETIMEEDIT_COMPAT_DATE_MIN.startOfDay(spec); minimum = QDATETIMEEDIT_COMPAT_DATE_MIN.startOfDay(timeZone);
maximum = QDATETIMEEDIT_DATE_MAX.endOfDay(spec); maximum = QDATETIMEEDIT_DATE_MAX.endOfDay(timeZone);
readLocaleSettings(); readLocaleSettings();
} }
QDateTime QDateTimeEditPrivate::convertTimeSpec(const QDateTime &datetime) QDateTime QDateTimeEditPrivate::convertTimeZone(const QDateTime &datetime)
{ {
Q_ASSERT(value.toDateTime().timeSpec() == spec); return datetime.toTimeZone(timeZone);
switch (spec) {
case Qt::UTC:
return datetime.toUTC();
case Qt::LocalTime:
return datetime.toLocalTime();
case Qt::OffsetFromUTC:
return datetime.toOffsetFromUtc(value.toDateTime().offsetFromUtc());
case Qt::TimeZone:
#if QT_CONFIG(timezone)
return datetime.toTimeZone(value.toDateTime().timeZone());
#else
qWarning("QDateTimeEdit: Internal: enable timezone feature to support Qt::TimeZone");
return datetime;
#endif
}
Q_UNREACHABLE();
} }
// FIXME: architecturaly incompatible with OffsetFromUTC or TimeZone as spec (QTBUG-80417). QDateTime QDateTimeEditPrivate::dateTimeValue(QDate date, QTime time) const
void QDateTimeEditPrivate::updateTimeSpec()
{ {
minimum = minimum.toDateTime().toTimeSpec(spec); QDateTime when = QDateTime(date, time, timeZone);
maximum = maximum.toDateTime().toTimeSpec(spec); if (when.isValid())
value = value.toDateTime().toTimeSpec(spec); return when;
// Hit a spring-forward gap
return QDateTime::fromMSecsSinceEpoch(when.toMSecsSinceEpoch(), timeZone);
}
void QDateTimeEditPrivate::updateTimeZone()
{
minimum = minimum.toDateTime().toTimeZone(timeZone);
maximum = maximum.toDateTime().toTimeZone(timeZone);
value = value.toDateTime().toTimeZone(timeZone);
// time zone changes can lead to 00:00:00 becomes 01:00:00 and 23:59:59 becomes 00:59:59 (invalid range) // time zone changes can lead to 00:00:00 becomes 01:00:00 and 23:59:59 becomes 00:59:59 (invalid range)
const bool dateShown = (sections & QDateTimeEdit::DateSections_Mask); const bool dateShown = (sections & QDateTimeEdit::DateSections_Mask);
if (!dateShown) { if (!dateShown) {
if (minimum.toTime() >= maximum.toTime()){ if (minimum.toTime() >= maximum.toTime()){
minimum = value.toDate().startOfDay(spec); minimum = value.toDate().startOfDay(timeZone);
maximum = value.toDate().endOfDay(spec); maximum = value.toDate().endOfDay(timeZone);
} }
} }
} }
@ -1785,6 +1780,27 @@ void QDateTimeEditPrivate::updateEdit()
} }
} }
QDateTime QDateTimeEditPrivate::getMinimum() const
{
if (keyboardTracking)
return minimum.toDateTime();
if (timeZone.timeSpec() == Qt::LocalTime)
return QDateTimeParser::getMinimum();
return QDATETIMEEDIT_DATE_MIN.startOfDay(timeZone);
}
QDateTime QDateTimeEditPrivate::getMaximum() const
{
if (keyboardTracking)
return maximum.toDateTime();
if (timeZone.timeSpec() == Qt::LocalTime)
return QDateTimeParser::getMaximum();
return QDATETIMEEDIT_DATE_MAX.endOfDay(timeZone);
}
/*! /*!
\internal \internal
@ -1997,8 +2013,8 @@ QDateTime QDateTimeEditPrivate::validateAndInterpret(QString &input, int &positi
StateNode tmp = parse(input, position, value.toDateTime(), fixup); StateNode tmp = parse(input, position, value.toDateTime(), fixup);
// Take note of any corrections imposed during parsing: // Take note of any corrections imposed during parsing:
input = m_text; input = m_text;
// Impose this widget's spec: // Impose this widget's time system:
tmp.value = tmp.value.toTimeSpec(spec); tmp.value = tmp.value.toTimeZone(timeZone);
// ... but that might turn a valid datetime into an invalid one: // ... but that might turn a valid datetime into an invalid one:
if (!tmp.value.isValid() && tmp.state == Acceptable) if (!tmp.value.isValid() && tmp.state == Acceptable)
tmp.state = Intermediate; tmp.state = Intermediate;
@ -2044,7 +2060,7 @@ QString QDateTimeEditPrivate::textFromValue(const QVariant &f) const
QVariant QDateTimeEditPrivate::valueFromText(const QString &f) const QVariant QDateTimeEditPrivate::valueFromText(const QString &f) const
{ {
Q_Q(const QDateTimeEdit); Q_Q(const QDateTimeEdit);
return q->dateTimeFromText(f).toTimeSpec(spec); return q->dateTimeFromText(f).toTimeZone(timeZone);
} }
@ -2124,7 +2140,7 @@ QDateTime QDateTimeEditPrivate::stepBy(int sectionIndex, int steps, bool test) c
// decreasing from e.g 3am to 2am would get us back to 3am, but we want 1am // decreasing from e.g 3am to 2am would get us back to 3am, but we want 1am
if (steps < 0 && sn.type & HourSectionMask) if (steps < 0 && sn.type & HourSectionMask)
msecsSinceEpoch -= 3600 * 1000; msecsSinceEpoch -= 3600 * 1000;
v = QDateTime::fromMSecsSinceEpoch(msecsSinceEpoch, v.timeSpec()); v = QDateTime::fromMSecsSinceEpoch(msecsSinceEpoch, v.timeRepresentation());
} }
// if this sets year or month it will make // if this sets year or month it will make
// sure that days are lowered if needed. // sure that days are lowered if needed.
@ -2220,8 +2236,7 @@ QDateTime QDateTimeEditPrivate::stepBy(int sectionIndex, int steps, bool test) c
} }
} }
const QDateTime ret = bound(v, value, steps).toDateTime().toTimeSpec(spec); return bound(v, value, steps).toDateTime().toTimeZone(timeZone);
return ret;
} }
/*! /*!
@ -2439,7 +2454,7 @@ void QDateTimeEditPrivate::interpret(EmitPolicy ep)
|| currentSectionIndex < 0 || currentSectionIndex < 0
|| !(fieldInfo(currentSectionIndex) & AllowPartial))) { || !(fieldInfo(currentSectionIndex) & AllowPartial))) {
setValue(value, ep); setValue(value, ep);
updateTimeSpec(); updateTimeZone();
} else { } else {
QAbstractSpinBoxPrivate::interpret(ep); QAbstractSpinBoxPrivate::interpret(ep);
} }
@ -2480,22 +2495,22 @@ void QDateTimeEditPrivate::init(const QVariant &var)
Q_Q(QDateTimeEdit); Q_Q(QDateTimeEdit);
switch (var.userType()) { switch (var.userType()) {
case QMetaType::QDate: case QMetaType::QDate:
value = var.toDate().startOfDay(spec); value = var.toDate().startOfDay(timeZone);
updateTimeSpec(); updateTimeZone();
q->setDisplayFormat(defaultDateFormat); q->setDisplayFormat(defaultDateFormat);
if (sectionNodes.isEmpty()) // ### safeguard for broken locale if (sectionNodes.isEmpty()) // ### safeguard for broken locale
q->setDisplayFormat("dd/MM/yyyy"_L1); q->setDisplayFormat("dd/MM/yyyy"_L1);
break; break;
case QMetaType::QDateTime: case QMetaType::QDateTime:
value = var; value = var;
updateTimeSpec(); updateTimeZone();
q->setDisplayFormat(defaultDateTimeFormat); q->setDisplayFormat(defaultDateTimeFormat);
if (sectionNodes.isEmpty()) // ### safeguard for broken locale if (sectionNodes.isEmpty()) // ### safeguard for broken locale
q->setDisplayFormat("dd/MM/yyyy hh:mm:ss"_L1); q->setDisplayFormat("dd/MM/yyyy hh:mm:ss"_L1);
break; break;
case QMetaType::QTime: case QMetaType::QTime:
value = QDateTime(QDATETIMEEDIT_DATE_INITIAL, var.toTime(), spec); value = dateTimeValue(QDATETIMEEDIT_DATE_INITIAL, var.toTime());
updateTimeSpec(); updateTimeZone();
q->setDisplayFormat(defaultTimeFormat); q->setDisplayFormat(defaultTimeFormat);
if (sectionNodes.isEmpty()) // ### safeguard for broken locale if (sectionNodes.isEmpty()) // ### safeguard for broken locale
q->setDisplayFormat("hh:mm:ss"_L1); q->setDisplayFormat("hh:mm:ss"_L1);
@ -2573,7 +2588,7 @@ void QDateTimeEditPrivate::updateEditFieldGeometry()
QVariant QDateTimeEditPrivate::getZeroVariant() const QVariant QDateTimeEditPrivate::getZeroVariant() const
{ {
Q_ASSERT(type == QMetaType::QDateTime); Q_ASSERT(type == QMetaType::QDateTime);
return QDateTime(QDATETIMEEDIT_DATE_INITIAL, QTime(), spec); return QDATETIMEEDIT_DATE_INITIAL.startOfDay(timeZone);
} }
void QDateTimeEditPrivate::setRange(const QVariant &min, const QVariant &max) void QDateTimeEditPrivate::setRange(const QVariant &min, const QVariant &max)

View File

@ -17,6 +17,8 @@
#include <QtWidgets/private/qtwidgetsglobal_p.h> #include <QtWidgets/private/qtwidgetsglobal_p.h>
#include <QtCore/qcalendar.h> #include <QtCore/qcalendar.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qtimezone.h>
#include "QtWidgets/qcalendarwidget.h" #include "QtWidgets/qcalendarwidget.h"
#include "QtWidgets/qspinbox.h" #include "QtWidgets/qspinbox.h"
#include "QtWidgets/qtoolbutton.h" #include "QtWidgets/qtoolbutton.h"
@ -34,7 +36,7 @@ class Q_AUTOTEST_EXPORT QDateTimeEditPrivate : public QAbstractSpinBoxPrivate, p
{ {
Q_DECLARE_PUBLIC(QDateTimeEdit) Q_DECLARE_PUBLIC(QDateTimeEdit)
public: public:
QDateTimeEditPrivate(Qt::TimeSpec timeSpec = Qt::LocalTime); QDateTimeEditPrivate(const QTimeZone &zone = QTimeZone::LocalTime);
void init(const QVariant &var); void init(const QVariant &var);
void readLocaleSettings(); void readLocaleSettings();
@ -58,22 +60,8 @@ public:
// Override QDateTimeParser: // Override QDateTimeParser:
QString displayText() const override { return edit->text(); } QString displayText() const override { return edit->text(); }
QDateTime getMinimum() const override QDateTime getMinimum() const override;
{ QDateTime getMaximum() const override;
if (keyboardTracking)
return minimum.toDateTime();
if (spec != Qt::LocalTime)
return QDateTime(QDATETIMEEDIT_DATE_MIN.startOfDay(spec));
return QDateTimeParser::getMinimum();
}
QDateTime getMaximum() const override
{
if (keyboardTracking)
return maximum.toDateTime();
if (spec != Qt::LocalTime)
return QDateTime(QDATETIMEEDIT_DATE_MAX.endOfDay(spec));
return QDateTimeParser::getMaximum();
}
QLocale locale() const override { return q_func()->locale(); } QLocale locale() const override { return q_func()->locale(); }
int cursorPosition() const override { return edit ? edit->cursorPosition() : -1; } int cursorPosition() const override { return edit ? edit->cursorPosition() : -1; }
@ -87,9 +75,10 @@ public:
void updateCache(const QVariant &val, const QString &str) const; void updateCache(const QVariant &val, const QString &str) const;
QDateTime convertTimeSpec(const QDateTime &datetime); QDateTime convertTimeZone(const QDateTime &datetime);
void updateTimeSpec(); void updateTimeZone();
QString valueToText(const QVariant &var) const { return textFromValue(var); } QString valueToText(const QVariant &var) const { return textFromValue(var); }
QDateTime dateTimeValue(QDate date, QTime time) const;
void _q_resetButton(); void _q_resetButton();
void updateArrow(QStyle::StateFlag state); void updateArrow(QStyle::StateFlag state);
@ -117,7 +106,7 @@ public:
bool focusOnButton = false; bool focusOnButton = false;
#endif #endif
Qt::TimeSpec spec; QTimeZone timeZone;
}; };

View File

@ -1316,7 +1316,7 @@ void tst_QDateTimeEdit::editingRanged_data()
<< QDate(2010, 12, 30) << QTime() << QDate(2010, 12, 30) << QTime()
<< QDate(2011, 1, 2) << QTime() << QDate(2011, 1, 2) << QTime()
<< QString::fromLatin1("01012011") << QString::fromLatin1("01012011")
<< QDateTime(QDate(2011, 1, 1), QTime(), Qt::UTC); << QDateTime(QDate(2011, 1, 1), QTime(), QTimeZone::UTC);
} }
void tst_QDateTimeEdit::editingRanged() void tst_QDateTimeEdit::editingRanged()
@ -3523,7 +3523,7 @@ void tst_QDateTimeEdit::timeSpec()
QCOMPARE(edit.timeSpec(), Qt::LocalTime); QCOMPARE(edit.timeSpec(), Qt::LocalTime);
const QDateTime utc = dt.toUTC(); const QDateTime utc = dt.toUTC();
if (dt.time() != utc.time()) { if (dt.time() != utc.time()) {
const QDateTime min(QDate(1999, 1, 1), QTime(1, 0, 0), Qt::LocalTime); const QDateTime min(QDate(1999, 1, 1), QTime(1, 0));
edit.setMinimumDateTime(min); edit.setMinimumDateTime(min);
QCOMPARE(edit.minimumTime(), min.time()); QCOMPARE(edit.minimumTime(), min.time());
if (useSetProperty) { if (useSetProperty) {
@ -3553,51 +3553,31 @@ void tst_QDateTimeEdit::timeSpecBug()
void tst_QDateTimeEdit::timeSpecInit() void tst_QDateTimeEdit::timeSpecInit()
{ {
QDateTime utc(QDate(2000, 1, 1), QTime(12, 0, 0), Qt::UTC); QDateTime utc(QDate(2000, 1, 1), QTime(12, 0), QTimeZone::UTC);
QDateTimeEdit widget(utc); QDateTimeEdit widget(utc);
QCOMPARE(widget.dateTime(), utc); QCOMPARE(widget.dateTime(), utc);
} }
void tst_QDateTimeEdit::setDateTime_data() void tst_QDateTimeEdit::setDateTime_data()
{ {
QDateTime localNoon(QDate(2019, 12, 24), QTime(12, 0));
// TODO QTBUG-80417: port away from spec, to use QTimeZone instead.
QTest::addColumn<Qt::TimeSpec>("spec"); QTest::addColumn<Qt::TimeSpec>("spec");
QDateTime localNoon(QDate(2019, 12, 24), QTime(12, 0), Qt::LocalTime);
#if 0 // Not yet supported
QTest::addColumn<int>("offset");
QTest::addColumn<QByteArray>("zoneName");
QTest::newRow("OffsetFromUTC/LocalTime")
<< Qt::OffsetFromUTC << 7200 << ""
<< localNoon << localNoon.toOffsetFromUtc(7200);
#if QT_CONFIG(timezone)
QTest::newRow("TimeZone/LocalTime")
<< Qt::TimeZone << 0 << "Europe/Berlin"
<< localNoon << localNoon.toTimeZone(QTimeZone("Europe/Berlin"));
#endif
#endif // unsupported
QTest::addColumn<QDateTime>("store"); QTest::addColumn<QDateTime>("store");
QTest::addColumn<QDateTime>("expect"); QTest::addColumn<QDateTime>("expect");
QTest::newRow("LocalTime/LocalTime") QTest::newRow("LocalTime/LocalTime")
<< Qt::LocalTime // << 0 << "" << Qt::LocalTime << localNoon << localNoon;
<< localNoon << localNoon;
QTest::newRow("LocalTime/UTC") QTest::newRow("LocalTime/UTC")
<< Qt::LocalTime // << 0 << "" << Qt::LocalTime << localNoon.toUTC() << localNoon;
<< localNoon.toUTC() << localNoon;
QTest::newRow("UTC/LocalTime") QTest::newRow("UTC/LocalTime")
<< Qt::UTC // << 0 << "" << Qt::UTC << localNoon << localNoon.toUTC();
<< localNoon << localNoon.toUTC();
QTest::newRow("UTC/UTC") QTest::newRow("UTC/UTC")
<< Qt::UTC // << 0 << "" << Qt::UTC << localNoon.toUTC() << localNoon.toUTC();
<< localNoon.toUTC() << localNoon.toUTC();
} }
void tst_QDateTimeEdit::setDateTime() void tst_QDateTimeEdit::setDateTime()
{ {
QFETCH(const Qt::TimeSpec, spec); QFETCH(const Qt::TimeSpec, spec);
#if 0 // Not yet supported
QFETCH(const int, offset);
QFETCH(const QByteArray, zoneName);
#endif // configuring the spec, when OffsetFromUTC or TimeZone
QFETCH(const QDateTime, store); QFETCH(const QDateTime, store);
QFETCH(const QDateTime, expect); QFETCH(const QDateTime, expect);
QDateTimeEdit editor; QDateTimeEdit editor;
@ -3798,7 +3778,7 @@ void tst_QDateTimeEdit::focusNextPrevChild()
void tst_QDateTimeEdit::taskQTBUG_12384_timeSpecShowTimeOnly() void tst_QDateTimeEdit::taskQTBUG_12384_timeSpecShowTimeOnly()
{ {
QDateTime time = QDateTime::fromString("20100723 04:02:40", "yyyyMMdd hh:mm:ss"); QDateTime time = QDateTime::fromString("20100723 04:02:40", "yyyyMMdd hh:mm:ss");
time.setTimeSpec(Qt::UTC); time.setTimeZone(QTimeZone::UTC);
EditorDateEdit edit; EditorDateEdit edit;
edit.setDisplayFormat("hh:mm:ss"); edit.setDisplayFormat("hh:mm:ss");