Add a QDateTimeEdit::timeZone property

This shall ultimately replace its timeSpec property, which had already
been turned into a derived property of an internal timezone.

[ChangeLog][QWidget][QDateTimeEdit] Added timeZone property to enable
a datetime edit widget to control the timezone used. This makes the
timeSpec property redundant; this old property shall be deprecated
from 6.10.

Fixes: QTBUG-80417
Change-Id: I3cdb686bd2dada0e5067f5b4c1828b73892e424a
Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
This commit is contained in:
Edward Welbourne 2023-09-08 17:14:15 +02:00
parent b7e0f45a85
commit 51cfc973b3
3 changed files with 74 additions and 31 deletions

View File

@ -219,7 +219,7 @@ QDateTimeEdit::~QDateTimeEdit()
widget's date-range to start and end on the date of the new value of this widget's date-range to start and end on the date of the new value of this
property. property.
\sa date, time, minimumDateTime, maximumDateTime \sa date, time, minimumDateTime, maximumDateTime, timeZone
*/ */
QDateTime QDateTimeEdit::dateTime() const QDateTime QDateTimeEdit::dateTime() const
@ -984,10 +984,16 @@ void QDateTimeEdit::setCalendarPopup(bool enable)
update(); update();
} }
#if QT_DEPRECATED_SINCE(6, 10)
/*! /*!
\property QDateTimeEdit::timeSpec \property QDateTimeEdit::timeSpec
\brief The current timespec used by the date time edit.
\since 4.4 \since 4.4
\deprecated[6.10] Use QDateTimeEdit::timeZone instead.
\brief The current timespec used by the date time edit.
Since Qt 6.7 this is an indirect accessor for the timeZone property.
\sa QDateTimeEdit::timeZone
*/ */
Qt::TimeSpec QDateTimeEdit::timeSpec() const Qt::TimeSpec QDateTimeEdit::timeSpec() const
@ -1002,17 +1008,45 @@ void QDateTimeEdit::setTimeSpec(Qt::TimeSpec spec)
if (spec != d->timeZone.timeSpec()) { if (spec != d->timeZone.timeSpec()) {
switch (spec) { switch (spec) {
case Qt::UTC: case Qt::UTC:
d->timeZone = QTimeZone::UTC; setTimeZone(QTimeZone::UTC);
break; break;
case Qt::LocalTime: case Qt::LocalTime:
d->timeZone = QTimeZone::LocalTime; setTimeZone(QTimeZone::LocalTime);
break; break;
default: default:
qWarning() << "Ignoring attempt to set time-spec" << spec qWarning() << "Ignoring attempt to set time-spec" << spec
<< "which is not yet supported by QDateTimeEdit"; << "which needs ancillary data: see setTimeZone()";
// TODO: fix that QTBUG-80417.
return; return;
} }
}
}
#endif // 6.10 deprecation
// TODO: enable user input to control timeZone, when the format includes it.
/*!
\property QDateTimeEdit::timeZone
\since 6.7
\brief The current timezone used by the datetime editing widget
If the datetime format in use includes a timezone indicator - that is, a
\c{t}, \c{tt}, \c{ttt} or \c{tttt} format specifier - the user's input is
re-expressed in this timezone whenever it is parsed, overriding any timezone
the user may have specified.
\sa QDateTimeEdit::displayFormat
*/
QTimeZone QDateTimeEdit::timeZone() const
{
Q_D(const QDateTimeEdit);
return d->timeZone;
}
void QDateTimeEdit::setTimeZone(const QTimeZone &zone)
{
Q_D(QDateTimeEdit);
if (zone != d->timeZone) {
d->timeZone = zone;
d->updateTimeZone(); d->updateTimeZone();
} }
} }
@ -1421,8 +1455,6 @@ 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);
} }
@ -2004,6 +2036,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;
// TODO: if the format specifies time-zone, update timeZone to match the
// parsed text; but we're in const context, so can't - QTBUG-118393.
// Impose this widget's time system: // Impose this widget's time system:
tmp.value = tmp.value.toTimeZone(timeZone); 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:

View File

@ -5,7 +5,7 @@
#define QDATETIMEEDIT_H #define QDATETIMEEDIT_H
#include <QtWidgets/qtwidgetsglobal.h> #include <QtWidgets/qtwidgetsglobal.h>
#include <QtCore/qdatetime.h> #include <QtCore/qtimezone.h>
#include <QtCore/qcalendar.h> #include <QtCore/qcalendar.h>
#include <QtCore/qvariant.h> #include <QtCore/qvariant.h>
#include <QtWidgets/qabstractspinbox.h> #include <QtWidgets/qabstractspinbox.h>
@ -39,7 +39,10 @@ class Q_WIDGETS_EXPORT QDateTimeEdit : public QAbstractSpinBox
Q_PROPERTY(bool calendarPopup READ calendarPopup WRITE setCalendarPopup) Q_PROPERTY(bool calendarPopup READ calendarPopup WRITE setCalendarPopup)
Q_PROPERTY(int currentSectionIndex READ currentSectionIndex WRITE setCurrentSectionIndex) Q_PROPERTY(int currentSectionIndex READ currentSectionIndex WRITE setCurrentSectionIndex)
Q_PROPERTY(int sectionCount READ sectionCount) Q_PROPERTY(int sectionCount READ sectionCount)
#if QT_DEPRECATED_SINCE(6, 10)
Q_PROPERTY(Qt::TimeSpec timeSpec READ timeSpec WRITE setTimeSpec) Q_PROPERTY(Qt::TimeSpec timeSpec READ timeSpec WRITE setTimeSpec)
#endif
Q_PROPERTY(QTimeZone timeZone READ timeZone WRITE setTimeZone)
public: public:
enum Section { // a sub-type of QDateTimeParser's like-named enum. enum Section { // a sub-type of QDateTimeParser's like-named enum.
NoSection = 0x0000, NoSection = 0x0000,
@ -125,8 +128,14 @@ public:
bool calendarPopup() const; bool calendarPopup() const;
void setCalendarPopup(bool enable); void setCalendarPopup(bool enable);
#if QT_DEPRECATED_SINCE(6, 10)
QT_DEPRECATED_VERSION_X_6_10("Use timeZone() instead")
Qt::TimeSpec timeSpec() const; Qt::TimeSpec timeSpec() const;
QT_DEPRECATED_VERSION_X_6_10("Use setTimeZone() instead")
void setTimeSpec(Qt::TimeSpec spec); void setTimeSpec(Qt::TimeSpec spec);
#endif
QTimeZone timeZone() const;
void setTimeZone(const QTimeZone &zone);
QSize sizeHint() const override; QSize sizeHint() const override;

View File

@ -233,10 +233,12 @@ private slots:
void nextPrevSection(); void nextPrevSection();
void dateEditTimeEditFormats(); void dateEditTimeEditFormats();
#if QT_DEPRECATED_SINCE(6, 10)
void timeSpec_data(); void timeSpec_data();
void timeSpec(); void timeSpec();
void timeSpecBug(); #endif
void timeSpecInit(); void timeZoneBug();
void timeZoneInit();
void setDateTime_data(); void setDateTime_data();
void setDateTime(); void setDateTime();
@ -252,7 +254,7 @@ private slots:
void task196924(); void task196924();
void focusNextPrevChild(); void focusNextPrevChild();
void taskQTBUG_12384_timeSpecShowTimeOnly(); void taskQTBUG_12384_timeZoneShowTimeOnly();
void deleteCalendarWidget(); void deleteCalendarWidget();
@ -436,7 +438,7 @@ void tst_QDateTimeEdit::cleanup()
{ {
testWidget->clearMinimumDateTime(); testWidget->clearMinimumDateTime();
testWidget->clearMaximumDateTime(); testWidget->clearMaximumDateTime();
testWidget->setTimeSpec(Qt::LocalTime); testWidget->setTimeZone(QTimeZone::LocalTime);
testWidget->setSpecialValueText(QString()); testWidget->setSpecialValueText(QString());
testWidget->setWrapping(false); testWidget->setWrapping(false);
// Restore the default. // Restore the default.
@ -3491,6 +3493,7 @@ void tst_QDateTimeEdit::dateEditTimeEditFormats()
QCOMPARE(d.displayedSections(), QDateTimeEdit::YearSection); QCOMPARE(d.displayedSections(), QDateTimeEdit::YearSection);
} }
#if QT_DEPRECATED_SINCE(6, 10)
void tst_QDateTimeEdit::timeSpec_data() void tst_QDateTimeEdit::timeSpec_data()
{ {
QTest::addColumn<bool>("useSetProperty"); QTest::addColumn<bool>("useSetProperty");
@ -3538,10 +3541,11 @@ void tst_QDateTimeEdit::timeSpec()
QSKIP("Not tested in the GMT timezone"); QSKIP("Not tested in the GMT timezone");
} }
} }
#endif // test deprecated timeSpec property
void tst_QDateTimeEdit::timeSpecBug() void tst_QDateTimeEdit::timeZoneBug()
{ {
testWidget->setTimeSpec(Qt::UTC); testWidget->setTimeZone(QTimeZone::UTC);
testWidget->setDisplayFormat("hh:mm"); testWidget->setDisplayFormat("hh:mm");
testWidget->setTime(QTime(2, 2)); testWidget->setTime(QTime(2, 2));
const QString oldText = testWidget->text(); const QString oldText = testWidget->text();
@ -3551,7 +3555,7 @@ void tst_QDateTimeEdit::timeSpecBug()
QCOMPARE(oldText, testWidget->text()); QCOMPARE(oldText, testWidget->text());
} }
void tst_QDateTimeEdit::timeSpecInit() void tst_QDateTimeEdit::timeZoneInit()
{ {
QDateTime utc(QDate(2000, 1, 1), QTime(12, 0), QTimeZone::UTC); QDateTime utc(QDate(2000, 1, 1), QTime(12, 0), QTimeZone::UTC);
QDateTimeEdit widget(utc); QDateTimeEdit widget(utc);
@ -3560,28 +3564,24 @@ void tst_QDateTimeEdit::timeSpecInit()
void tst_QDateTimeEdit::setDateTime_data() void tst_QDateTimeEdit::setDateTime_data()
{ {
QDateTime localNoon(QDate(2019, 12, 24), QTime(12, 0)); const QDateTime localNoon(QDate(2019, 12, 24), QTime(12, 0));
// TODO QTBUG-80417: port away from spec, to use QTimeZone instead. const QTimeZone UTC(QTimeZone::UTC), local(QTimeZone::LocalTime);
QTest::addColumn<Qt::TimeSpec>("spec"); QTest::addColumn<QTimeZone>("zone");
QTest::addColumn<QDateTime>("store"); QTest::addColumn<QDateTime>("store");
QTest::addColumn<QDateTime>("expect"); QTest::addColumn<QDateTime>("expect");
QTest::newRow("LocalTime/LocalTime") QTest::newRow("LocalTime/LocalTime") << local << localNoon << localNoon;
<< Qt::LocalTime << localNoon << localNoon; QTest::newRow("LocalTime/UTC") << local << localNoon.toUTC() << localNoon;
QTest::newRow("LocalTime/UTC") QTest::newRow("UTC/LocalTime") << UTC << localNoon << localNoon.toUTC();
<< Qt::LocalTime << localNoon.toUTC() << localNoon; QTest::newRow("UTC/UTC") << UTC << localNoon.toUTC() << localNoon.toUTC();
QTest::newRow("UTC/LocalTime")
<< Qt::UTC << localNoon << localNoon.toUTC();
QTest::newRow("UTC/UTC")
<< Qt::UTC << localNoon.toUTC() << localNoon.toUTC();
} }
void tst_QDateTimeEdit::setDateTime() void tst_QDateTimeEdit::setDateTime()
{ {
QFETCH(const Qt::TimeSpec, spec); QFETCH(const QTimeZone, zone);
QFETCH(const QDateTime, store); QFETCH(const QDateTime, store);
QFETCH(const QDateTime, expect); QFETCH(const QDateTime, expect);
QDateTimeEdit editor; QDateTimeEdit editor;
editor.setTimeSpec(spec); editor.setTimeZone(zone);
editor.setDateTime(store); editor.setDateTime(store);
QCOMPARE(editor.dateTime(), expect); QCOMPARE(editor.dateTime(), expect);
} }
@ -3775,14 +3775,14 @@ void tst_QDateTimeEdit::focusNextPrevChild()
QCOMPARE(edit.currentSection(), QDateTimeEdit::MonthSection); QCOMPARE(edit.currentSection(), QDateTimeEdit::MonthSection);
} }
void tst_QDateTimeEdit::taskQTBUG_12384_timeSpecShowTimeOnly() void tst_QDateTimeEdit::taskQTBUG_12384_timeZoneShowTimeOnly()
{ {
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.setTimeZone(QTimeZone::UTC); time.setTimeZone(QTimeZone::UTC);
EditorDateEdit edit; EditorDateEdit edit;
edit.setDisplayFormat("hh:mm:ss"); edit.setDisplayFormat("hh:mm:ss");
edit.setTimeSpec(Qt::UTC); edit.setTimeZone(QTimeZone::UTC);
edit.setDateTime(time); edit.setDateTime(time);
QCOMPARE(edit.minimumTime(), QTime(0, 0, 0, 0)); QCOMPARE(edit.minimumTime(), QTime(0, 0, 0, 0));