From 837781db52b59012fdebb357ccb3abbd2f9bf2f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 10 Oct 2016 13:44:52 +0200 Subject: Add Qt::ISODateWithMs date format, with support in QTime/Date/DateTime The Qt::ISODate format strips milliseconds, so a new format is introduced that keeps the milliseconds. A new format was chosen over fixing the existing format due to the behavioral change of suddenly having ms as part of Qt::ISODate. Change-Id: If8b852daed068cce8eee9b61a7cd4576bc763443 Reviewed-by: Thiago Macieira --- src/corelib/global/qnamespace.h | 3 ++- src/corelib/global/qnamespace.qdoc | 2 ++ src/corelib/tools/qdatetime.cpp | 25 +++++++++++++++------ tests/auto/corelib/tools/qdate/tst_qdate.cpp | 1 + .../auto/corelib/tools/qdatetime/tst_qdatetime.cpp | 26 +++++++++++++++------- tests/auto/corelib/tools/qtime/tst_qtime.cpp | 3 +++ 6 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 5a66319164..e2b0d30db0 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -1197,7 +1197,8 @@ public: SystemLocaleLongDate, DefaultLocaleShortDate, DefaultLocaleLongDate, - RFC2822Date // RFC 2822 (+ 850 and 1036 during parsing) + RFC2822Date, // RFC 2822 (+ 850 and 1036 during parsing) + ISODateWithMs }; enum TimeSpec { diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 7768070e4f..250195a512 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -658,6 +658,8 @@ \c{YYYY-MM-DDTHH:mm:ss}, \c{YYYY-MM-DDTHH:mm:ssTZD} (e.g., 1997-07-16T19:20:30+01:00) for combined dates and times. + \value ISODateWithMs \l{ISO 8601} extended format, including milliseconds if applicable. + \value SystemLocaleShortDate The \l{QLocale::ShortFormat}{short format} used by the \l{QLocale::system()}{operating system}. diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 7819d2e207..3750b37580 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -873,6 +873,7 @@ QString QDate::toString(Qt::DateFormat format) const return toStringTextDate(*this); #endif case Qt::ISODate: + case Qt::ISODateWithMs: return toStringIsoDate(jd); } } @@ -1568,7 +1569,9 @@ int QTime::msec() const If \a format is Qt::ISODate, the string format corresponds to the ISO 8601 extended specification for representations of dates, - which is also HH:mm:ss. + represented by HH:mm:ss. To include milliseconds in the ISO 8601 + date, use the \a format Qt::ISODateWithMs, which corresponds to + HH:mm:ss.zzz. If the \a format is Qt::SystemLocaleShortDate or Qt::SystemLocaleLongDate, the string format depends on the locale @@ -1610,6 +1613,8 @@ QString QTime::toString(Qt::DateFormat format) const return QLocale().toString(*this, QLocale::ShortFormat); case Qt::DefaultLocaleLongDate: return QLocale().toString(*this, QLocale::LongFormat); + case Qt::ISODateWithMs: + return QString::asprintf("%02d:%02d:%02d.%03d", hour(), minute(), second(), msec()); case Qt::RFC2822Date: case Qt::ISODate: case Qt::TextDate: @@ -1916,7 +1921,8 @@ static QTime fromIsoTimeString(const QStringRef &string, Qt::DateFormat format, } } - if (format == Qt::ISODate && hour == 24 && minute == 0 && second == 0 && msec == 0) { + const bool isISODate = format == Qt::ISODate || format == Qt::ISODateWithMs; + if (isISODate && hour == 24 && minute == 0 && second == 0 && msec == 0) { if (isMidnight24) *isMidnight24 = true; hour = 0; @@ -1958,6 +1964,7 @@ QTime QTime::fromString(const QString& string, Qt::DateFormat format) case Qt::RFC2822Date: return rfcDateImpl(string).time; case Qt::ISODate: + case Qt::ISODateWithMs: case Qt::TextDate: default: return fromIsoTimeString(&string, format, 0); @@ -3713,7 +3720,9 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC) depending on the timeSpec() of the QDateTime. If the timeSpec() is Qt::UTC, Z will be appended to the string; if the timeSpec() is Qt::OffsetFromUTC, the offset in hours and minutes from UTC will - be appended to the string. + be appended to the string. To include milliseconds in the ISO 8601 + date, use the \a format Qt::ISODateWithMs, which corresponds to + YYYY-MM-DDTHH:mm:ss.zzz[Z|[+|-]HH:mm]. If the \a format is Qt::SystemLocaleShortDate or Qt::SystemLocaleLongDate, the string format depends on the locale @@ -3784,7 +3793,8 @@ QString QDateTime::toString(Qt::DateFormat format) const return buf; } #endif - case Qt::ISODate: { + case Qt::ISODate: + case Qt::ISODateWithMs: { const QPair p = getDateTime(d); const QDate &dt = p.first; const QTime &tm = p.second; @@ -3792,7 +3802,7 @@ QString QDateTime::toString(Qt::DateFormat format) const if (buf.isEmpty()) return QString(); // failed to convert buf += QLatin1Char('T'); - buf += tm.toString(Qt::ISODate); + buf += tm.toString(format); switch (getSpec(d)) { case Qt::UTC: buf += QLatin1Char('Z'); @@ -4651,7 +4661,8 @@ QDateTime QDateTime::fromString(const QString& string, Qt::DateFormat format) dateTime.setOffsetFromUtc(rfc.utcOffset); return dateTime; } - case Qt::ISODate: { + case Qt::ISODate: + case Qt::ISODateWithMs: { const int size = string.size(); if (size < 10) return QDateTime(); @@ -4699,7 +4710,7 @@ QDateTime QDateTime::fromString(const QString& string, Qt::DateFormat format) // Might be end of day (24:00, including variants), which QTime considers invalid. // ISO 8601 (section 4.2.3) says that 24:00 is equivalent to 00:00 the next day. bool isMidnight24 = false; - QTime time = fromIsoTimeString(isoString, Qt::ISODate, &isMidnight24); + QTime time = fromIsoTimeString(isoString, format, &isMidnight24); if (!time.isValid()) return QDateTime(); if (isMidnight24) diff --git a/tests/auto/corelib/tools/qdate/tst_qdate.cpp b/tests/auto/corelib/tools/qdate/tst_qdate.cpp index f22138b795..0e189ba7aa 100644 --- a/tests/auto/corelib/tools/qdate/tst_qdate.cpp +++ b/tests/auto/corelib/tools/qdate/tst_qdate.cpp @@ -1145,6 +1145,7 @@ void tst_QDate::toStringDateFormat_data() QTest::newRow("year < 0") << QDate(-1,1,1) << Qt::ISODate << QString(); QTest::newRow("year > 9999") << QDate(-1,1,1) << Qt::ISODate << QString(); QTest::newRow("RFC2822Date") << QDate(1974,12,1) << Qt::RFC2822Date << QString("01 Dec 1974"); + QTest::newRow("ISODateWithMs") << QDate(1974,12,1) << Qt::ISODateWithMs << QString("1974-12-01"); } void tst_QDate::toStringDateFormat() diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp index 0404a276ff..4604e664b0 100644 --- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp @@ -732,46 +732,56 @@ void tst_QDateTime::fromMSecsSinceEpoch() void tst_QDateTime::toString_isoDate_data() { QTest::addColumn("datetime"); + QTest::addColumn("format"); QTest::addColumn("expected"); QTest::newRow("localtime") << QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34)) - << QString("1978-11-09T13:28:34"); + << Qt::ISODate << QString("1978-11-09T13:28:34"); QTest::newRow("UTC") << QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34), Qt::UTC) - << QString("1978-11-09T13:28:34Z"); + << Qt::ISODate << QString("1978-11-09T13:28:34Z"); QDateTime dt(QDate(1978, 11, 9), QTime(13, 28, 34)); dt.setOffsetFromUtc(19800); QTest::newRow("positive OffsetFromUTC") - << dt + << dt << Qt::ISODate << QString("1978-11-09T13:28:34+05:30"); dt.setUtcOffset(-7200); QTest::newRow("negative OffsetFromUTC") - << dt + << dt << Qt::ISODate << QString("1978-11-09T13:28:34-02:00"); dt.setUtcOffset(-900); QTest::newRow("negative non-integral OffsetFromUTC") - << dt + << dt << Qt::ISODate << QString("1978-11-09T13:28:34-00:15"); QTest::newRow("invalid") << QDateTime(QDate(-1, 11, 9), QTime(13, 28, 34), Qt::UTC) - << QString(); + << Qt::ISODate << QString(); + QTest::newRow("without-ms") + << QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34, 20)) + << Qt::ISODate << QString("1978-11-09T13:28:34"); + QTest::newRow("with-ms") + << QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34, 20)) + << Qt::ISODateWithMs << QString("1978-11-09T13:28:34.020"); } void tst_QDateTime::toString_isoDate() { QFETCH(QDateTime, datetime); + QFETCH(Qt::DateFormat, format); QFETCH(QString, expected); QLocale oldLocale; QLocale::setDefault(QLocale("en_US")); - QString result = datetime.toString(Qt::ISODate); + QString result = datetime.toString(format); QCOMPARE(result, expected); - QDateTime resultDatetime = QDateTime::fromString(result, Qt::ISODate); + QDateTime resultDatetime = QDateTime::fromString(result, format); // If expecting invalid result the datetime may still be valid, i.e. year < 0 or > 9999 if (!expected.isEmpty()) { + QEXPECT_FAIL("without-ms", "Qt::ISODate truncates milliseconds (QTBUG-56552)", Abort); + QCOMPARE(resultDatetime, datetime); QCOMPARE(resultDatetime.date(), datetime.date()); QCOMPARE(resultDatetime.time(), datetime.time()); diff --git a/tests/auto/corelib/tools/qtime/tst_qtime.cpp b/tests/auto/corelib/tools/qtime/tst_qtime.cpp index 45af10c3ab..059e1e519b 100644 --- a/tests/auto/corelib/tools/qtime/tst_qtime.cpp +++ b/tests/auto/corelib/tools/qtime/tst_qtime.cpp @@ -675,6 +675,9 @@ void tst_QTime::toStringDateFormat_data() QTest::newRow("Text 10:12:34.999") << QTime(10, 12, 34, 999) << Qt::TextDate << QString("10:12:34"); QTest::newRow("ISO 10:12:34.999") << QTime(10, 12, 34, 999) << Qt::ISODate << QString("10:12:34"); QTest::newRow("RFC2822Date") << QTime(10, 12, 34, 999) << Qt::RFC2822Date << QString("10:12:34"); + QTest::newRow("ISOWithMs 10:12:34.000") << QTime(10, 12, 34, 0) << Qt::ISODateWithMs << QString("10:12:34.000"); + QTest::newRow("ISOWithMs 10:12:34.020") << QTime(10, 12, 34, 20) << Qt::ISODateWithMs << QString("10:12:34.020"); + QTest::newRow("ISOWithMs 10:12:34.999") << QTime(10, 12, 34, 999) << Qt::ISODateWithMs << QString("10:12:34.999"); } void tst_QTime::toStringDateFormat() -- cgit v1.2.3