From 86f953a6d40666a3355e76b3ab2c8a2cf5452ec6 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 18 Jun 2012 15:53:30 +0200 Subject: Make QDateTime::fromString()/Time::fromString() adhere to ISO 8601. Currently QDateTime::fromString and QTime::fromString do not correctly handle fractional minutes and, in some cases, fractional seconds. In the case of reading fractional minutes, it has been decided to ignore invalid characters outside of the 5 character portion that we're interested in (see code comments in fromStringImpl() for info on why we read 5 digits). The motive is that there is a performance penalty for calling mid to get the portion of surplus string and also for converting to it to a float. This is also in line with what QDate does with surplus characters, for example. Task-number: QTBUG-14418 Task-number: QTBUG-25387 Change-Id: Ib742fe80686aff3c3770b995678cf838fb4e3bb4 Reviewed-by: Thiago Macieira --- .../auto/corelib/tools/qdatetime/tst_qdatetime.cpp | 71 +++++++++++++++++++--- tests/auto/corelib/tools/qtime/tst_qtime.cpp | 21 ++++--- 2 files changed, 72 insertions(+), 20 deletions(-) (limited to 'tests') diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp index a738c54d4e..b54bf60908 100644 --- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp @@ -1270,25 +1270,76 @@ void tst_QDateTime::fromStringDateFormat_data() // No time specified - defaults to Qt::LocalTime. QTest::newRow("data16") << QString::fromLatin1("2002-10-01") << Qt::ISODate << QDateTime(QDate(2002, 10, 1), QTime(0, 0, 0, 0)) << Qt::LocalTime; - QTest::newRow("ISO date") << QString::fromLatin1("2005-06-28T07:57:30.0010000000Z") + QTest::newRow("ISO") << QString::fromLatin1("2005-06-28T07:57:30.0010000000Z") << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 1)) << Qt::UTC; - QTest::newRow("ISO date with comma 1") << QString::fromLatin1("2005-06-28T07:57:30,0040000000Z") + QTest::newRow("ISO with comma 1") << QString::fromLatin1("2005-06-28T07:57:30,0040000000Z") << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 4)) << Qt::UTC; - QTest::newRow("ISO date with comma 2") << QString::fromLatin1("2005-06-28T07:57:30,0015Z") + QTest::newRow("ISO with comma 2") << QString::fromLatin1("2005-06-28T07:57:30,0015Z") << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 2)) << Qt::UTC; - QTest::newRow("ISO date with comma 3") << QString::fromLatin1("2005-06-28T07:57:30,0014Z") + QTest::newRow("ISO with comma 3") << QString::fromLatin1("2005-06-28T07:57:30,0014Z") << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 1)) << Qt::UTC; - QTest::newRow("ISO date with comma 4") << QString::fromLatin1("2005-06-28T07:57:30,1Z") + QTest::newRow("ISO with comma 4") << QString::fromLatin1("2005-06-28T07:57:30,1Z") << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 100)) << Qt::UTC; - QTest::newRow("ISO date with comma 5") << QString::fromLatin1("2005-06-28T07:57:30,11") + QTest::newRow("ISO with comma 5") << QString::fromLatin1("2005-06-28T07:57:30,11") << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 110)) << Qt::LocalTime; - // Should be next day according to ISO 8601 section 4.2.3. - QTest::newRow("ISO date 24:00") << QString::fromLatin1("2012-06-04T24:00:00") + // 24:00:00 Should be next day according to ISO 8601 section 4.2.3. + QTest::newRow("ISO 24:00") << QString::fromLatin1("2012-06-04T24:00:00") << Qt::ISODate << QDateTime(QDate(2012, 6, 5), QTime(0, 0, 0, 0)) << Qt::LocalTime; - QTest::newRow("ISO date 24:00 end of month") << QString::fromLatin1("2012-06-30T24:00:00") + QTest::newRow("ISO 24:00 end of month") << QString::fromLatin1("2012-06-30T24:00:00") << Qt::ISODate << QDateTime(QDate(2012, 7, 1), QTime(0, 0, 0, 0)) << Qt::LocalTime; - QTest::newRow("ISO date 24:00 end of month and year") << QString::fromLatin1("2012-12-31T24:00:00") + QTest::newRow("ISO 24:00 end of year") << QString::fromLatin1("2012-12-31T24:00:00") << Qt::ISODate << QDateTime(QDate(2013, 1, 1), QTime(0, 0, 0, 0)) << Qt::LocalTime; + QTest::newRow("ISO 24:00, fract ms") << QString::fromLatin1("2012-01-01T24:00:00.000") + << Qt::ISODate << QDateTime(QDate(2012, 1, 2), QTime(0, 0, 0, 0)) << Qt::LocalTime; + QTest::newRow("ISO 24:00 end of year, fract ms") << QString::fromLatin1("2012-12-31T24:00:00.000") + << Qt::ISODate << QDateTime(QDate(2013, 1, 1), QTime(0, 0, 0, 0)) << Qt::LocalTime; + // Test fractional seconds. + QTest::newRow("ISO .0 of a second (period)") << QString::fromLatin1("2012-01-01T08:00:00.0") + << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 0)) << Qt::LocalTime; + QTest::newRow("ISO .00 of a second (period)") << QString::fromLatin1("2012-01-01T08:00:00.00") + << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 0)) << Qt::LocalTime; + QTest::newRow("ISO .000 of a second (period)") << QString::fromLatin1("2012-01-01T08:00:00.000") + << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 0)) << Qt::LocalTime; + QTest::newRow("ISO .1 of a second (comma)") << QString::fromLatin1("2012-01-01T08:00:00,1") + << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 100)) << Qt::LocalTime; + QTest::newRow("ISO .99 of a second (comma)") << QString::fromLatin1("2012-01-01T08:00:00,99") + << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 990)) << Qt::LocalTime; + QTest::newRow("ISO .998 of a second (comma)") << QString::fromLatin1("2012-01-01T08:00:00,998") + << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 998)) << Qt::LocalTime; + QTest::newRow("ISO .999 of a second (comma)") << QString::fromLatin1("2012-01-01T08:00:00,999") + << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 999)) << Qt::LocalTime; + QTest::newRow("ISO .3335 of a second (comma)") << QString::fromLatin1("2012-01-01T08:00:00,3335") + << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 334)) << Qt::LocalTime; + QTest::newRow("ISO .333333 of a second (comma)") << QString::fromLatin1("2012-01-01T08:00:00,333333") + << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 333)) << Qt::LocalTime; + QTest::newRow("ISO .00009 of a second (period)") << QString::fromLatin1("2012-01-01T08:00:00.00009") + << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 0)) << Qt::LocalTime; + QTest::newRow("ISO no fract specified") << QString::fromLatin1("2012-01-01T08:00:00.") + << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 0)) << Qt::LocalTime; + // Test invalid characters (should ignore invalid characters at end of string). + QTest::newRow("ISO invalid character at end") << QString::fromLatin1("2012-01-01T08:00:00!") + << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 0)) << Qt::LocalTime; + QTest::newRow("ISO invalid character at front") << QString::fromLatin1("!2012-01-01T08:00:00") + << Qt::ISODate << invalidDateTime() << Qt::LocalTime; + QTest::newRow("ISO invalid character both ends") << QString::fromLatin1("!2012-01-01T08:00:00!") + << Qt::ISODate << invalidDateTime() << Qt::LocalTime; + QTest::newRow("ISO invalid character at front, 2 at back") << QString::fromLatin1("!2012-01-01T08:00:00..") + << Qt::ISODate << invalidDateTime() << Qt::LocalTime; + QTest::newRow("ISO invalid character 2 at front") << QString::fromLatin1("!!2012-01-01T08:00:00") + << Qt::ISODate << invalidDateTime() << Qt::LocalTime; + // Test fractional minutes. + QTest::newRow("ISO .0 of a minute (period)") << QString::fromLatin1("2012-01-01T08:00.0") + << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 0)) << Qt::LocalTime; + QTest::newRow("ISO .8 of a minute (period)") << QString::fromLatin1("2012-01-01T08:00.8") + << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 48, 0)) << Qt::LocalTime; + QTest::newRow("ISO .99999 of a minute (period)") << QString::fromLatin1("2012-01-01T08:00.99999") + << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 59, 999)) << Qt::LocalTime; + QTest::newRow("ISO .0 of a minute (comma)") << QString::fromLatin1("2012-01-01T08:00,0") + << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 0)) << Qt::LocalTime; + QTest::newRow("ISO .8 of a minute (comma)") << QString::fromLatin1("2012-01-01T08:00,8") + << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 48, 0)) << Qt::LocalTime; + 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; } void tst_QDateTime::fromStringDateFormat() diff --git a/tests/auto/corelib/tools/qtime/tst_qtime.cpp b/tests/auto/corelib/tools/qtime/tst_qtime.cpp index 1e000a1b40..1d6b0d2a01 100644 --- a/tests/auto/corelib/tools/qtime/tst_qtime.cpp +++ b/tests/auto/corelib/tools/qtime/tst_qtime.cpp @@ -562,21 +562,22 @@ void tst_QTime::fromStringDateFormat_data() QTest::addColumn("format"); QTest::addColumn("expected"); - QTest::newRow("valid, start of day, omit seconds") << QString::fromLatin1("00:00") << Qt::ISODate << QTime(0, 0, 0); - QTest::newRow("valid, omit seconds") << QString::fromLatin1("22:21") << Qt::ISODate << QTime(22, 21, 0); - QTest::newRow("valid, omit seconds (2)") << QString::fromLatin1("23:59") << Qt::ISODate << QTime(23, 59, 0); - QTest::newRow("valid, end of day") << QString::fromLatin1("23:59:59") << Qt::ISODate << QTime(23, 59, 59); - - QTest::newRow("invalid, empty string") << QString::fromLatin1("") << Qt::ISODate << invalidTime(); - QTest::newRow("invalid, too many hours") << QString::fromLatin1("25:00") << Qt::ISODate << invalidTime(); - QTest::newRow("invalid, too many minutes") << QString::fromLatin1("10:70") << Qt::ISODate << invalidTime(); - QTest::newRow("invalid, too many seconds") << QString::fromLatin1("23:59:60") << Qt::ISODate << invalidTime(); - QTest::newRow("TextDate - data0") << QString("00:00:00") << Qt::TextDate << QTime(0,0,0,0); QTest::newRow("TextDate - data1") << QString("10:12:34") << Qt::TextDate << QTime(10,12,34,0); QTest::newRow("TextDate - data2") << QString("19:03:54.998601") << Qt::TextDate << QTime(19, 3, 54, 999); QTest::newRow("TextDate - data3") << QString("19:03:54.999601") << Qt::TextDate << QTime(19, 3, 54, 999); + QTest::newRow("IsoDate - valid, start of day, omit seconds") << QString::fromLatin1("00:00") << Qt::ISODate << QTime(0, 0, 0); + QTest::newRow("IsoDate - valid, omit seconds") << QString::fromLatin1("22:21") << Qt::ISODate << QTime(22, 21, 0); + QTest::newRow("IsoDate - valid, omit seconds (2)") << QString::fromLatin1("23:59") << Qt::ISODate << QTime(23, 59, 0); + QTest::newRow("IsoDate - valid, end of day") << QString::fromLatin1("23:59:59") << Qt::ISODate << QTime(23, 59, 59); + + QTest::newRow("IsoDate - invalid, empty string") << QString::fromLatin1("") << Qt::ISODate << invalidTime(); + QTest::newRow("IsoDate - invalid, too many hours") << QString::fromLatin1("25:00") << Qt::ISODate << invalidTime(); + QTest::newRow("IsoDate - invalid, too many minutes") << QString::fromLatin1("10:70") << Qt::ISODate << invalidTime(); + // This is a valid time if it happens on June 30 or December 31 (leap seconds). + QTest::newRow("IsoDate - invalid, too many seconds") << QString::fromLatin1("23:59:60") << Qt::ISODate << invalidTime(); + QTest::newRow("IsoDate - data0") << QString("00:00:00") << Qt::ISODate << QTime(0,0,0,0); QTest::newRow("IsoDate - data1") << QString("10:12:34") << Qt::ISODate << QTime(10,12,34,0); QTest::newRow("IsoDate - data2") << QString("19:03:54.998601") << Qt::ISODate << QTime(19, 3, 54, 999); -- cgit v1.2.3