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. Change-Id: Ided9adf62a56d98f144bdf91b40f918e22bd82cd Reviewed-by: Israel Lins Albuquerque <israelins85@yahoo.com.br> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
b6c3f55b93
commit
a9c111ed8c
@ -4763,25 +4763,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('+');
|
||||
@ -4789,8 +4799,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) {
|
||||
|
@ -2283,6 +2283,9 @@ 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();
|
||||
|
||||
// Test Qt::RFC2822Date format (RFC 2822).
|
||||
QTest::newRow("RFC 2822 +0100") << QString::fromLatin1("13 Feb 1987 13:24:51 +0100")
|
||||
|
Loading…
x
Reference in New Issue
Block a user