summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2018-01-30 21:02:10 +0100
committerEdward Welbourne <edward.welbourne@qt.io>2018-02-01 15:57:23 +0000
commitb44df9937e4b15596b994f8e20822b83ac4bed29 (patch)
treeb5e35a8874ee19517bf830a001e2719478bb9e93
parent9b2913377807b3dae107befeec0bc488f4a2cbad (diff)
Clean-up in QDateTime's parsing of ISODate{,WithMs}
Actually check that there's a T where ISO 8601 wants it (instead of just skipping over whatever's there), with something after it; move some declarations later; add some comments; and use the QStringRef API more cleanly (so that it's easier to see what's going on). Simplify a loop condition to avoid the need for a post-loop fix-up. This incidentally prevents an assertion failure (which brought the mess to my attention) parsing a short string as an ISO date-time; if there's a T with nothing after it, we won't try to read at index -1 in the following text. (The actual fail seen had a Z where the T should have been, with nothing after it.) Add tests for invalid ISOdate cases that triggered the assertion. Task-number: QTBUG-66076 Change-Id: Ided9adf62a56d98f144bdf91b40f918e22bd82cd Reviewed-by: Israel Lins Albuquerque <israelins85@yahoo.com.br> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> (cherry picked from commit a9c111ed8c30a5a8fec3f02244f0d5a4bd08e931)
-rw-r--r--src/corelib/tools/qdatetime.cpp23
-rw-r--r--tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp4
2 files changed, 20 insertions, 7 deletions
diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp
index 9d26207a0f..045ad10755 100644
--- a/src/corelib/tools/qdatetime.cpp
+++ b/src/corelib/tools/qdatetime.cpp
@@ -4720,25 +4720,35 @@ QDateTime QDateTime::fromString(const QString& string, Qt::DateFormat format)
if (size < 10)
return QDateTime();
- QStringRef isoString(&string);
- Qt::TimeSpec spec = Qt::LocalTime;
-
QDate date = QDate::fromString(string.left(10), Qt::ISODate);
if (!date.isValid())
return QDateTime();
if (size == 10)
return QDateTime(date);
- isoString = isoString.right(isoString.length() - 11);
+ Qt::TimeSpec spec = Qt::LocalTime;
+ QStringRef isoString(&string);
+ isoString = isoString.mid(10); // trim "yyyy-MM-dd"
+
+ // Must be left with T and at least one digit for the hour:
+ if (isoString.size() < 2
+ || !(isoString.startsWith(QLatin1Char('T'))
+ // FIXME: QSql relies on QVariant::toDateTime() accepting a space here:
+ || isoString.startsWith(QLatin1Char(' ')))) {
+ return QDateTime();
+ }
+ isoString = isoString.mid(1); // trim 'T' (or space)
+
int offset = 0;
// Check end of string for Time Zone definition, either Z for UTC or [+-]HH:mm for Offset
if (isoString.endsWith(QLatin1Char('Z'))) {
spec = Qt::UTC;
- isoString = isoString.left(isoString.size() - 1);
+ isoString.chop(1); // trim 'Z'
} else {
// the loop below is faster but functionally equal to:
// const int signIndex = isoString.indexOf(QRegExp(QStringLiteral("[+-]")));
int signIndex = isoString.size() - 1;
+ Q_ASSERT(signIndex >= 0);
bool found = false;
{
const QChar plus = QLatin1Char('+');
@@ -4746,8 +4756,7 @@ QDateTime QDateTime::fromString(const QString& string, Qt::DateFormat format)
do {
QChar character(isoString.at(signIndex));
found = character == plus || character == minus;
- } while (--signIndex >= 0 && !found);
- ++signIndex;
+ } while (!found && --signIndex >= 0);
}
if (found) {
diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp
index 28ad2d193c..91b5966fa8 100644
--- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp
+++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp
@@ -2277,6 +2277,10 @@ void tst_QDateTime::fromStringDateFormat_data()
QTest::newRow("ISO .99999 of a minute (comma)") << QString::fromLatin1("2012-01-01T08:00,99999")
<< Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 59, 999), Qt::LocalTime);
QTest::newRow("ISO empty") << QString::fromLatin1("") << Qt::ISODate << invalidDateTime();
+ QTest::newRow("ISO short") << QString::fromLatin1("2017-07-01T") << Qt::ISODate << invalidDateTime();
+ QTest::newRow("ISO zoned date") << QString::fromLatin1("2017-07-01Z") << Qt::ISODate << invalidDateTime();
+ QTest::newRow("ISO zoned empty time") << QString::fromLatin1("2017-07-01TZ") << Qt::ISODate << invalidDateTime();
+ QTest::newRow("ISO mis-punctuated") << QString::fromLatin1("2018/01/30 ") << Qt::ISODate << invalidDateTime();
// Test Qt::RFC2822Date format (RFC 2822).
QTest::newRow("RFC 2822 +0100") << QString::fromLatin1("13 Feb 1987 13:24:51 +0100")