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. Fixes: QTBUG-102199 Pick-to: 6.3 6.2 5.15 Change-Id: I658308614505ef25f4c97d0de6148acb54a65a0f Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
d82301a900
commit
9fee35a2ed
@ -823,6 +823,11 @@ QDateTimeParser::parseSection(const QDateTime ¤tValue, int sectionIndex, i
|
||||
&& m_text.at(offset) == u'-');
|
||||
const int negativeYearOffset = negate ? 1 : 0;
|
||||
|
||||
// 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());
|
||||
|
||||
QStringView sectionTextRef =
|
||||
QStringView { m_text }.mid(offset + negativeYearOffset, sectionmaxsize);
|
||||
|
||||
@ -858,7 +863,7 @@ QDateTimeParser::parseSection(const QDateTime ¤tValue, int sectionIndex, i
|
||||
m_text.replace(offset, used, sectiontext.constData(), used);
|
||||
break; }
|
||||
case TimeZoneSection:
|
||||
result = findTimeZone(sectionTextRef, currentValue,
|
||||
result = findTimeZone(sectionTextRef, defaultValue,
|
||||
absoluteMax(sectionIndex),
|
||||
absoluteMin(sectionIndex));
|
||||
break;
|
||||
@ -870,7 +875,7 @@ QDateTimeParser::parseSection(const QDateTime ¤tValue, int sectionIndex, i
|
||||
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, §iontext, &used);
|
||||
} else {
|
||||
@ -964,7 +969,7 @@ QDateTimeParser::parseSection(const QDateTime ¤tValue, int sectionIndex, i
|
||||
}
|
||||
|
||||
} 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);
|
||||
m_text.insert(offset, QString(missingZeroes, u'0'));
|
||||
|
@ -1967,7 +1967,8 @@ void tst_QLocale::toDateTime_data()
|
||||
QTest::addColumn<QDateTime>("result");
|
||||
QTest::addColumn<QString>("format");
|
||||
QTest::addColumn<QString>("string");
|
||||
QTest::addColumn<bool>("clean"); // No non-format letters in format string
|
||||
// No non-format letters in format string, no time-zone (t format):
|
||||
QTest::addColumn<bool>("clean");
|
||||
|
||||
QTest::newRow("1C") << "C" << QDateTime(QDate(1974, 12, 1), QTime(5, 14, 0))
|
||||
<< "d/M/yyyy hh:h:mm" << "1/12/1974 05:5:14" << true;
|
||||
@ -2021,6 +2022,18 @@ void tst_QLocale::toDateTime_data()
|
||||
QTest::newRow("12no_NO") << "no_NO" << QDateTime(QDate(1974, 12, 1), QTime(15, 0, 0))
|
||||
<< "d'd'dd/M/yyh" << "1d01/12/7415" << false;
|
||||
|
||||
QTest::newRow("short-ss") // QTBUG-102199: trips over an assert in CET
|
||||
<< "C" << QDateTime() // Single-digit seconds does not match ss format.
|
||||
<< u"ddd, d MMM yyyy HH:mm:ss"_qs << u"Sun, 29 Mar 2020 02:26:3"_qs << true;
|
||||
|
||||
QTest::newRow("short-ss-Z") // Same, but with a valid date-time:
|
||||
<< "C" << QDateTime()
|
||||
<< u"ddd, d MMM yyyy HH:mm:ss t"_qs << u"Sun, 29 Mar 2020 02:26:3 Z"_qs << false;
|
||||
|
||||
QTest::newRow("s-Z") // Same, but with a format that accepts the single digit:
|
||||
<< "C" << QDateTime(QDate(2020, 3, 29), QTime(2, 26, 3), Qt::UTC)
|
||||
<< u"ddd, d MMM yyyy HH:mm:s t"_qs << u"Sun, 29 Mar 2020 02:26:3 Z"_qs << false;
|
||||
|
||||
QTest::newRow("RFC-1123")
|
||||
<< "C" << QDateTime(QDate(2007, 11, 1), QTime(18, 8, 30))
|
||||
<< "ddd, dd MMM yyyy hh:mm:ss 'GMT'" << "Thu, 01 Nov 2007 18:08:30 GMT" << false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user