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 <thiago.macieira@intel.com>
This commit is contained in:
Edward Welbourne 2022-07-15 15:50:33 +02:00
parent 0bc92c01e3
commit 18439a449f
3 changed files with 52 additions and 8 deletions

View File

@ -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 <cmath>
@ -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;

View File

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

View File

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