From 18439a449fdf7e60878329a42fdc55beca14b4c0 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Fri, 15 Jul 2022 15:50:33 +0200 Subject: [PATCH] Support serializing time-zone fields in date-times more flexibly [ChangeLog][QtCore][QDateTime] The 't' format character in a toString() template can now be repeated to get alternatives to the (unparseable) zone abbreviation. Thus 'tt' now gets the zone offset without colon, [+-]hhmm; 'ttt' gets the same with colon, [+-]hh:mm, and 'tttt' gets the zone name. Previously, each 't' was replaced by another copy of the abbreviation. Task-number: QTBUG-95966 Change-Id: Iccccd11f06fa732ed27c0e5d4e40a3d4b5f79f8d Reviewed-by: Thiago Macieira --- src/corelib/text/qlocale.cpp | 36 ++++++++++++++++--- src/corelib/time/qdatetime.cpp | 19 +++++++++- .../corelib/time/qdatetime/tst_qdatetime.cpp | 5 +-- 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp index e8ef690186..ba97d8cbb4 100644 --- a/src/corelib/text/qlocale.cpp +++ b/src/corelib/text/qlocale.cpp @@ -31,6 +31,9 @@ QT_WARNING_DISABLE_GCC("-Wfree-nonheap-object") // false positive tracking #include "qvariant.h" #include "qvarlengtharray.h" #include "qstringbuilder.h" +#if QT_CONFIG(timezone) +# include "qtimezone.h" +#endif #include "private/qnumeric_p.h" #include "private/qtools_p.h" #include @@ -3520,13 +3523,36 @@ QString QCalendarBackend::dateTimeToString(QStringView format, const QDateTime & } break; - case 't': + case 't': { used = true; - repeat = 1; - // If we have a QDateTime use the time spec otherwise use the current system tzname - result.append(formatDate ? datetime.timeZoneAbbreviation() - : QDateTime::currentDateTime().timeZoneAbbreviation()); + repeat = qMin(repeat, 4); + // If we don't have a date-time, use the current system time: + const QDateTime when = formatDate ? datetime : QDateTime::currentDateTime(); + QString text; + switch (repeat) { +#if QT_CONFIG(timezone) + case 4: + text = when.timeZone().displayName(when, QTimeZone::LongName); + break; +#endif // timezone + case 3: + case 2: + text = when.toOffsetFromUtc(when.offsetFromUtc()).timeZoneAbbreviation(); + // If the offset is UTC that'll be a Qt::UTC, otherwise Qt::OffsetFromUTC. + Q_ASSERT(text.startsWith("UTC"_L1)); + // The Qt::UTC case omits the zero offset, which we want: + text = text.size() == 3 ? u"+00:00"_s : text.sliced(3); + if (repeat == 2) // +hhmm format, rather than +hh:mm format + text = text.remove(u':'); + break; + default: + text = when.timeZoneAbbreviation(); + break; + } + if (!text.isEmpty()) + result.append(text); break; + } default: break; diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp index eca8f7c18a..689bc88c24 100644 --- a/src/corelib/time/qdatetime.cpp +++ b/src/corelib/time/qdatetime.cpp @@ -1952,7 +1952,24 @@ QString QTime::toString(Qt::DateFormat format) const \l{QLocale::toString()}), the locale-appropriate text (returned by \l{QLocale::amText()} or \l{QLocale::pmText()}) is used without change of case. - \row \li t \li The timezone (for example "CEST") + \row \li t + \li The timezone abbreviation (for example "CEST"). Note that time zone + abbreviations are not unique. In particular, \l toString() cannot + parse this. + \row \li tt + \li The timezone's offset from UTC with no colon between the hours and + minutes (for example "+0200"). + \row \li ttt + \li The timezone's offset from UTC with a colon between the hours and + minutes (for example "+02:00"). + \row \li tttt + \li The timezone name (for example "Europe/Berlin"). Note that this + gives no indication of whether the date-time was in daylight-saving + time or standard time, which may lead to ambiguity if the date-time + falls in an hour repeated by a transition between the two. The name + used is the one provided by \l QTimeZone::displayName() with the \l + QTimeZone::LongName type. This may depend on the operating system + in use. \endtable Any non-empty sequence of characters enclosed in single quotes will be diff --git a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp index d00ddb254d..4f3fc881b4 100644 --- a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp @@ -1104,8 +1104,9 @@ void tst_QDateTime::toString_strformat() 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")); + QCOMPARE(testDateTime.toString("yyyy-MM-dd hh:mm:ss tt"), QString("2013-01-01 01:02:03 +0000")); + QCOMPARE(testDateTime.toString("yyyy-MM-dd hh:mm:ss ttt"), QString("2013-01-01 01:02:03 +00:00")); + QCOMPARE(testDateTime.toString("yyyy-MM-dd hh:mm:ss tttt"), QString("2013-01-01 01:02:03 UTC")); } #endif // datestring