Support POSIX rules as $TZ values
The TZ environment variable can validly contain a POSIX rule, rather than an IANA ID, as described here: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03 However, if TZ were set to such a value, leading to it being used as systemTimeZoneId(), it would be passed to QTzTimeZonePrivate::init(), which is a no-op unless it manages to open a zoneinfo/ file with the given ianaId as name. When the environment variable doesn't name a zoneinfo/ file, we would thus get an invalid time-zone. We can, instead, check whether the ianaId looks like a valid POSIX rule and, if it does, use it as m_posixRule, enabling us to correctly handle this case. Tweak parsing of POSIX rules so that a zone using name "UTC" or "GMT" with an offset other than 0 will be rejected as invalid. This avoids parsing a zone name such as "GMT+17" or "UTC+00:01" as a POSIX rule, where it should be understood as an offset from UTC (and only certain well-established offsets are supported). Added two test-cases to tst_QTimeZone::tzTest() for validity of a POSIX zone value - a simple one constructed during discussion of the bug, the other taken from an example in: http://leaf.sourceforge.net/doc/buci-tz3.html Task-number: QTBUG-75565 Change-Id: Ia5cb1cc56b13b0f6b56258e48be98d04d909e32a Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
parent
b29cc512f8
commit
ab2655c559
|
|
@ -516,6 +516,10 @@ PosixZone PosixZone::parse(const char *&pos, const char *end)
|
|||
QString name = QString::fromUtf8(nameBegin, nameEnd - nameBegin);
|
||||
const int offset = zoneEnd > zoneBegin ? parsePosixOffset(zoneBegin, zoneEnd) : InvalidOffset;
|
||||
pos = zoneEnd;
|
||||
// UTC+hh:mm:ss or GMT+hh:mm:ss should be read as offsets from UTC, not as a
|
||||
// POSIX rule naming a zone as UTC or GMT and specifying a non-zero offset.
|
||||
if (offset != 0 && (name == QLatin1String("UTC") || name == QLatin1String("GMT")))
|
||||
return invalid();
|
||||
return {std::move(name), offset};
|
||||
}
|
||||
|
||||
|
|
@ -654,8 +658,17 @@ void QTzTimeZonePrivate::init(const QByteArray &ianaId)
|
|||
tzif.setFileName(QLatin1String("/usr/share/zoneinfo/") + QString::fromLocal8Bit(ianaId));
|
||||
if (!tzif.open(QIODevice::ReadOnly)) {
|
||||
tzif.setFileName(QLatin1String("/usr/lib/zoneinfo/") + QString::fromLocal8Bit(ianaId));
|
||||
if (!tzif.open(QIODevice::ReadOnly))
|
||||
if (!tzif.open(QIODevice::ReadOnly)) {
|
||||
// ianaId may be a POSIX rule, taken from $TZ
|
||||
const QByteArray zoneInfo = ianaId.split(',').at(0);
|
||||
const char *begin = zoneInfo.constBegin();
|
||||
if (PosixZone::parse(begin, zoneInfo.constEnd()).hasValidOffset()
|
||||
&& (begin == zoneInfo.constEnd()
|
||||
|| PosixZone::parse(begin, zoneInfo.constEnd()).hasValidOffset())) {
|
||||
m_id = m_posixRule = ianaId;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -915,6 +915,14 @@ void tst_QTimeZone::tzTest()
|
|||
QTzTimeZonePrivate tzp("Europe/Berlin");
|
||||
QVERIFY(tzp.isValid());
|
||||
|
||||
// Test POSIX-format value for $TZ:
|
||||
QTzTimeZonePrivate tzposix("MET-1METDST-2,M3.5.0/02:00:00,M10.5.0/03:00:00");
|
||||
QVERIFY(tzposix.isValid());
|
||||
|
||||
QTimeZone tzBrazil("BRT+3"); // parts of Northern Brazil, as a POSIX rule
|
||||
QVERIFY(tzBrazil.isValid());
|
||||
QCOMPARE(tzBrazil.offsetFromUtc(QDateTime(QDate(1111, 11, 11).startOfDay())), -10800);
|
||||
|
||||
// Test display names by type, either ICU or abbreviation only
|
||||
QLocale enUS("en_US");
|
||||
// Only test names in debug mode, names used can vary by ICU version installed
|
||||
|
|
|
|||
Loading…
Reference in New Issue