diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp index b19e4498d3..d3670c119a 100644 --- a/src/corelib/text/qlocale.cpp +++ b/src/corelib/text/qlocale.cpp @@ -3484,13 +3484,13 @@ QString QCalendarBackend::dateTimeToString(QStringView format, const QDateTime & case 'z': used = true; - repeat = (repeat >= 3) ? 3 : 1; + repeat = qMin(repeat, 3); // note: the millisecond component is treated like the decimal part of the seconds // so ms == 2 is always printed as "002", but ms == 200 can be either "2" or "200" result.append(locale.d->m_data->longLongToString(time.msec(), -1, 10, 3, QLocaleData::ZeroPadded)); - if (repeat == 1) { + if (repeat != 3) { if (result.endsWith(locale.zeroDigit())) result.chop(1); if (result.endsWith(locale.zeroDigit())) diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp index 2bb925c60b..c3b72073ec 100644 --- a/src/corelib/time/qdatetime.cpp +++ b/src/corelib/time/qdatetime.cpp @@ -1147,6 +1147,13 @@ QString QDate::toString(Qt::DateFormat format) const \note Day and month names are given in English (C locale). To get localized month and day names, use QLocale::system().toString(). + \note If a format character is repeated more times than the longest + expression in the table above using it, this part of the format will be read + as several expressions with no separator between them; the longest above, + possibly repeated as many times as there are copies of it, ending with a + residue that may be a shorter expression. Thus \c{'MMMMMMMMMM'} for a date + in May will contribute \c{"MayMay05"} to the output. + \sa fromString(), QDateTime::toString(), QTime::toString(), QLocale::toString() */ @@ -1611,6 +1618,14 @@ QDate QDate::fromString(QStringView string, Qt::DateFormat format) \snippet code/src_corelib_time_qdatetime.cpp 3 + \note If a format character is repeated more times than the longest + expression in the table above using it, this part of the format will be read + as several expressions with no separator between them; the longest above, + possibly repeated as many times as there are copies of it, ending with a + residue that may be a shorter expression. Thus \c{'MMMMMMMMMM'} would match + \c{"MayMay05"} and set the month to May. Likewise, \c{'MMMMMM'} would match + \c{"May08"} and find it inconsistent, leading to an invalid date. + \sa toString(), QDateTime::fromString(), QTime::fromString(), QLocale::toDate() */ @@ -1912,12 +1927,14 @@ QString QTime::toString(Qt::DateFormat format) const \row \li mm \li The minute with a leading zero (00 to 59) \row \li s \li The whole second, without any leading zero (0 to 59) \row \li ss \li The whole second, with a leading zero where applicable (00 to 59) - \row \li z \li The fractional part of the second, to go after a decimal - point, without trailing zeroes (0 to 999). Thus "\c{s.z}" - reports the seconds to full available (millisecond) precision - without trailing zeroes. - \row \li zzz \li The fractional part of the second, to millisecond - precision, including trailing zeroes where applicable (000 to 999). + \row \li z or zz + \li The fractional part of the second, to go after a decimal point, + without trailing zeroes. Thus "\c{s.z}" reports the seconds to + full available (millisecond) precision without trailing zeroes (0 + to 999). + \row \li zzz + \li The fractional part of the second, to millisecond precision, + including trailing zeroes where applicable (000 to 999). \row \li AP or A \li Use AM/PM display. \c A/AP will be replaced by 'AM' or 'PM'. In localized forms (only relevant to \l{QLocale::toString()}), the @@ -1960,8 +1977,16 @@ QString QTime::toString(Qt::DateFormat format) const \note To get localized forms of AM or PM (the AP, ap, A, a, aP or Ap formats), use QLocale::system().toString(). + \note If a format character is repeated more times than the longest + expression in the table above using it, this part of the format will be read + as several expressions with no separator between them; the longest above, + possibly repeated as many times as there are copies of it, ending with a + residue that may be a shorter expression. Thus \c{'HHHHH'} for the time + 08:00 will contribute \c{"08088"} to the output. + \sa fromString(), QDate::toString(), QDateTime::toString(), QLocale::toString() */ +// ### Qt 7 The 't' format specifiers should be specific to QDateTime (compare fromString). QString QTime::toString(QStringView format) const { return QLocale::c().toString(*this, format); @@ -2342,6 +2367,15 @@ QTime QTime::fromString(QStringView string, Qt::DateFormat format) \note If localized forms of am or pm (the AP, ap, Ap, aP, A or a formats) are to be recognized, use QLocale::system().toTime(). + \note If a format character is repeated more times than the longest + expression in the table above using it, this part of the format will be read + as several expressions with no separator between them; the longest above, + possibly repeated as many times as there are copies of it, ending with a + residue that may be a shorter expression. Thus \c{'HHHHH'} would match + \c{"08088"} or \c{"080808"} and set the hour to 8; if the time string + contained "070809" it would "match" but produce an inconsistent result, + leading to an invalid time. + \sa toString(), QDateTime::fromString(), QDate::fromString(), QLocale::toTime(), QLocale::toDateTime() */ @@ -5061,6 +5095,15 @@ QDateTime QDateTime::fromString(QStringView string, Qt::DateFormat format) English (C locale). If localized month and day names or localized forms of AM/PM are to be recognized, use QLocale::system().toDateTime(). + \note If a format character is repeated more times than the longest + expression in the table above using it, this part of the format will be read + as several expressions with no separator between them; the longest above, + possibly repeated as many times as there are copies of it, ending with a + residue that may be a shorter expression. Thus \c{'tttttt'} would match + \c{"Europe/BerlinEurope/Berlin"} and set the zone to Berlin time; if the + date-time string contained "Europe/BerlinZ" it would "match" but produce an + inconsistent result, leading to an invalid date-time. + \sa toString(), QDate::fromString(), QTime::fromString(), QLocale::toDateTime() */ diff --git a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp index 4dd2cf6aff..df2721cfc3 100644 --- a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp +++ b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp @@ -1664,7 +1664,7 @@ void tst_QLocale::formatTime_data() QTest::newRow("C-quote-dquote-H") << QTime(1, 2, 3) << "C" << "'\"H\"'" << "\"H\""; QTest::newRow("C-H:m:s.z") << QTime(1, 2, 3, 456) << "C" << "H:m:s.z" << "1:2:3.456"; - QTest::newRow("C-H:m:s.zz") << QTime(1, 2, 3, 456) << "C" << "H:m:s.zz" << "1:2:3.456456"; + QTest::newRow("C-H:m:s.zz") << QTime(1, 2, 3, 456) << "C" << "H:m:s.zz" << "1:2:3.456"; QTest::newRow("C-H:m:s.zzz") << QTime(1, 2, 3, 456) << "C" << "H:m:s.zzz" << "1:2:3.456"; QTest::newRow("C-H:m:s.z=400") << QTime(1, 2, 3, 400) << "C" << "H:m:s.z" << "1:2:3.4"; QTest::newRow("C-H:m:s.zzz=400") << QTime(1, 2, 3, 400) << "C" << "H:m:s.zzz" << "1:2:3.400"; diff --git a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp index c12ae8b632..090a19d4cc 100644 --- a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp @@ -1098,10 +1098,11 @@ void tst_QDateTime::toString_strformat() { // Most tests are in QLocale, just test that the api works. QDate testDate(2013, 1, 1); - QTime testTime(1, 2, 3); + QTime testTime(1, 2, 3, 456); QDateTime testDateTime(testDate, testTime, Qt::UTC); QCOMPARE(testDate.toString("yyyy-MM-dd"), QString("2013-01-01")); QCOMPARE(testTime.toString("hh:mm:ss"), QString("01:02:03")); + QCOMPARE(testTime.toString("hh:mm:ss.zz"), QString("01:02:03.456")); QCOMPARE(testDateTime.toString("yyyy-MM-dd hh:mm:ss t"), QString("2013-01-01 01:02:03 UTC")); // TODO QTBUG-95966: find better ways to use repeated 't' QCOMPARE(testDateTime.toString("yyyy-MM-dd hh:mm:ss tt"), QString("2013-01-01 01:02:03 UTCUTC"));