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 <thiago.macieira@intel.com>
This commit is contained in:
Tor Arne Vestbø 2016-10-10 13:44:52 +02:00
parent 6a9e039d19
commit 837781db52
6 changed files with 44 additions and 16 deletions

View File

@ -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 {

View File

@ -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}.

View File

@ -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<QDate, QTime> 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)

View File

@ -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()

View File

@ -732,46 +732,56 @@ void tst_QDateTime::fromMSecsSinceEpoch()
void tst_QDateTime::toString_isoDate_data()
{
QTest::addColumn<QDateTime>("datetime");
QTest::addColumn<Qt::DateFormat>("format");
QTest::addColumn<QString>("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());

View File

@ -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()