summaryrefslogtreecommitdiffstats
path: root/src/corelib/time/qdatetimeparser.cpp
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2022-04-01 12:07:10 +0200
committerEdward Welbourne <edward.welbourne@qt.io>2022-04-25 22:54:07 +0200
commit27e0ca05a022cf0e7406e8d4ea7ba7256be2c4a5 (patch)
tree3cd0d56a341d12801c707c6573acac322969823f /src/corelib/time/qdatetimeparser.cpp
parenta2e5dcfbde7b3bf6db5da58cd578debf246dc3af (diff)
Fix assertion failure when parsing a doubly-invalid date-time text
When the date-time string falls in a spring-forward (so is invalid) and one of the fields of the parsed string doesn't match the format it's meant to (e.g. a single-digit seconds field when format ss was specified), a check that the current fall-back date-time is between the minimum and maximum for the parser object failed, triggering an assertion. In any case, an invalid default-value wasn't useful to the code that parsed a single section of the date-time string, so brute-force the current value to a valid date-time (when possible) using the usual round-trip via milliseconds since the epoch. Added the test-case which first revealed the problem, plus a couple more informed by it, to exercise the same code-paths with fewer things failing. (For 5.15: converted u"..."_qs to QStringLiteral("...").) Fixes: QTBUG-102199 Change-Id: I658308614505ef25f4c97d0de6148acb54a65a0f Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> (cherry picked from commit 9fee35a2eda68b5968d911d5e14d298b91418d2c) Reviewed-by: Ievgenii Meshcheriakov <ievgenii.meshcheriakov@qt.io>
Diffstat (limited to 'src/corelib/time/qdatetimeparser.cpp')
-rw-r--r--src/corelib/time/qdatetimeparser.cpp13
1 files changed, 9 insertions, 4 deletions
diff --git a/src/corelib/time/qdatetimeparser.cpp b/src/corelib/time/qdatetimeparser.cpp
index 5df4b373c4..5f8267c2b9 100644
--- a/src/corelib/time/qdatetimeparser.cpp
+++ b/src/corelib/time/qdatetimeparser.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -761,6 +761,11 @@ QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionIndex,
const int sectionmaxsize = sectionMaxSize(sectionIndex);
QStringRef sectionTextRef = text->midRef(offset, sectionmaxsize);
+ // If the fields we've read thus far imply a time in a spring-forward,
+ // coerce to a nearby valid time:
+ const QDateTime defaultValue = currentValue.isValid() ? currentValue
+ : QDateTime::fromMSecsSinceEpoch(currentValue.toMSecsSinceEpoch());
+
QDTPDEBUG << "sectionValue for" << sn.name()
<< "with text" << *text << "and (at" << offset
<< ") st:" << sectionTextRef;
@@ -793,7 +798,7 @@ QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionIndex,
text->replace(offset, used, sectiontext.constData(), used);
break; }
case TimeZoneSection:
- result = findTimeZone(sectionTextRef, currentValue,
+ result = findTimeZone(sectionTextRef, defaultValue,
absoluteMax(sectionIndex),
absoluteMin(sectionIndex));
break;
@@ -805,7 +810,7 @@ QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionIndex,
int num = 0, used = 0;
if (sn.type == MonthSection) {
const QDate minDate = getMinimum().date();
- const int year = currentValue.date().year(calendar);
+ const int year = defaultValue.date().year(calendar);
const int min = (year == minDate.year(calendar)) ? minDate.month(calendar) : 1;
num = findMonth(sectiontext.toLower(), min, sectionIndex, year, &sectiontext, &used);
} else {
@@ -887,7 +892,7 @@ QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionIndex,
else
QDTPDEBUG << "invalid because" << last << "is less than absoluteMin" << absMin;
} else if (unfilled && (fi & (FixedWidth|Numeric)) == (FixedWidth|Numeric)) {
- if (skipToNextSection(sectionIndex, currentValue, digitsStr)) {
+ if (skipToNextSection(sectionIndex, defaultValue, digitsStr)) {
const int missingZeroes = sectionmaxsize - digitsStr.size();
result = ParsedSection(Acceptable, last, sectionmaxsize, missingZeroes);
text->insert(offset, QString(missingZeroes, QLatin1Char('0')));