diff options
author | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2020-02-20 17:30:57 +0100 |
---|---|---|
committer | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2020-02-27 19:35:28 +0100 |
commit | 924b97d6abf6f9935c9698984a1596c65324e3fa (patch) | |
tree | a0726e4c0e18bdb133dd0d09734c27f94e2d0bb8 /src/widgets/widgets/qdatetimeedit.cpp | |
parent | 31b06a0437f96935f12eb0db003a5867c83a9228 (diff) |
Fix QDateTimeEdit's handling of invalid time in dst gap
During a spring forward, a time-zone omits an hour. A QDateTime with
such an hour is invalid, but QDateTimeEdit's handling of this invalid
time was not done correctly.
With this fix, up/down changes of any field that would result in an
invalid date-time corrects the time to be valid, while leaving as
much as possible of the user-entered data unchanged. To do that, we
rely on QDateTime::toMSecsSinceEpoch to return a value even for such
an invalid time, which then can be used to construct a valid
QDateTime.
Edits that would result in an invalid hour are reverted to the
previous when pressing return, if correctionMode is
CorrectToPreviousValue. This change also implements support for
CorrectToNearestValue, which uses the same mechanism as when stepping
over an invalid time.
Include a test that verifies that the various interactions result
in a reasonable value. Since QDateTimeEdit does not respect the
timezone or timespec of the QDateTime it is initialized with, we
have to find the first hour of daylight saving time for a year
that we know works for most time zones. Failing that, we have to
skip the tests. Verified in a wide range of time zones.
Change-Id: I05b906ae3b5f6681891d23704f00f9c10cd479ae
Fixes: QTBUG-79803
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src/widgets/widgets/qdatetimeedit.cpp')
-rw-r--r-- | src/widgets/widgets/qdatetimeedit.cpp | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/src/widgets/widgets/qdatetimeedit.cpp b/src/widgets/widgets/qdatetimeedit.cpp index 63d5ae268e..c89cef99b5 100644 --- a/src/widgets/widgets/qdatetimeedit.cpp +++ b/src/widgets/widgets/qdatetimeedit.cpp @@ -1442,7 +1442,16 @@ void QDateTimeEdit::fixup(QString &input) const QValidator::State state; int copy = d->edit->cursorPosition(); - d->validateAndInterpret(input, copy, state, true); + QDateTime value = d->validateAndInterpret(input, copy, state, true); + /* + String was valid, but the datetime still is not; use the time that + has the same distance from epoch. + CorrectToPreviousValue correction is handled by QAbstractSpinBox. + */ + if (!value.isValid() && d->correctionMode == QAbstractSpinBox::CorrectToNearestValue) { + value = QDateTime::fromMSecsSinceEpoch(value.toMSecsSinceEpoch(), value.timeSpec()); + input = textFromDateTime(value); + } } @@ -2060,6 +2069,17 @@ QDateTime QDateTimeEditPrivate::stepBy(int sectionIndex, int steps, bool test) c const int oldDay = v.date().day(calendar); setDigit(v, sectionIndex, val); + /* + Stepping into a daylight saving time that doesn't exist, + so use the time that has the same distance from epoch. + */ + if (!v.isValid()) { + auto msecsSinceEpoch = v.toMSecsSinceEpoch(); + // decreasing from e.g 3am to 2am would get us back to 3am, but we want 1am + if (steps < 0 && sn.type & HourSectionMask) + msecsSinceEpoch -= 3600 * 1000; + v = QDateTime::fromMSecsSinceEpoch(msecsSinceEpoch, v.timeSpec()); + } // if this sets year or month it will make // sure that days are lowered if needed. |