Address problems with date-time parsing near bounds

Document the limited range of datetimes that can be parsed from
strings and the (awkward) consequence of the range bounds being
specified in local time.

Add tests for UTC hitting those bounds and QEXPECT_FAIL() the ones
that (as the new docs say they may) fail. Technically the fact that
the UTC:min one *doesn't* fail is evidence of a bug in the existing
date-time parser. Its replacement should support unbounded parsing.

Pick to 6.8 required removing a QEXPECT_FAIL() specific (on MS) to the
std::chrono::tzdb backend, which isn't present before 6.9.

Fixes: QTBUG-129287
Task-number: QTBUG-77948
Pick-to: 6.5
Change-Id: Ic90558f1a06a62f7d0a947e37802370d1ab4e373
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
(cherry picked from commit 3e25203d4d5ba428309e972367dbdf99c4e70327)
This commit is contained in:
Edward Welbourne 2024-09-30 15:03:20 +02:00
parent 037e14dd07
commit 4408d077ac
2 changed files with 25 additions and 2 deletions

View File

@ -5883,7 +5883,11 @@ QDateTime QDateTime::fromString(QStringView string, Qt::DateFormat format)
two digits.
Incorrectly specified fields of the \a string will cause an invalid
QDateTime to be returned.
QDateTime to be returned. Only datetimes between the local time start of
year 100 and end of year 9999 are supported. Note that datetimes near the
ends of this range in other time-zones, notably including UTC, may fall
outside the range (and thust be treated as invalid) depending on local time
zone.
\note Day and month names as well as AM/PM indicators must be given in
English (C locale). If localized month and day names or localized forms of

View File

@ -3334,6 +3334,17 @@ void tst_QDateTime::fromStringStringFormat_data()
QTest::newRow("ASN.1:UTC-end")
<< u"491231235959Z"_s << u"yyMMddHHmmsst"_s << 1950
<< QDate(2049, 12, 31).endOfDay(QTimeZone::UTC).addMSecs(-999);
// Reproducer for QTBUG-129287
QTest::newRow("ASN.1:max")
<< u"99991231235959Z"_s << u"yyyyMMddHHmmsst"_s << 1950
<< QDate(9999, 12, 31).endOfDay(QTimeZone::UTC).addMSecs(-999);
// Can also be reproduced with more legible formats:
QTest::newRow("UTC:max")
<< u"9999 Dec 31 23:59:59 +00:00"_s << u"yyyy MMM dd HH:mm:ss t"_s << 9900
<< QDate(9999, 12, 31).endOfDay(QTimeZone::UTC).addMSecs(-999);
QTest::newRow("UTC:min")
<< u"0100 Jan 1 00:00:00 +00:00"_s << u"yyyy MMM d HH:mm:ss t"_s << 100
<< QDate(100, 1, 1).startOfDay(QTimeZone::UTC);
// fuzzer test
QTest::newRow("integer overflow found by fuzzer")
@ -3359,9 +3370,17 @@ void tst_QDateTime::fromStringStringFormat()
QFETCH(int, baseYear);
QFETCH(QDateTime, expected);
QDateTime dt = QDateTime::fromString(string, format, baseYear);
if (futureTimeType == LocalTimeAheadOfUtc) {
// The new parser should remove the bounds, removing this limitation.
QEXPECT_FAIL("ASN.1:max", "QTBUG-77948: min/max are local times", Abort);
QEXPECT_FAIL("UTC:max", "QTBUG-77948: min/max are local times", Abort);
}
// For contrast, UTC::min gets away with it, which probably means there are
// genuinely out-of-range cases the old parser gets wrong.
QDateTime dt = QDateTime::fromString(string, format, baseYear);
QCOMPARE(dt, expected);
if (expected.isValid()) {
QCOMPARE(dt.timeSpec(), expected.timeSpec());
QCOMPARE(dt.timeRepresentation(), dt.timeRepresentation());