Warn on failure to construct valid system time zone object

Also move some docs from asBackendZone() to systemTimeZone(), making
clear that the system zone object is current at the time of creation
and won't be updated if the system is reconfigured. Adapt some tests
to fail and make clear that the system is misconfigured if no valid
system zone is found.

[ChangeLog][QtCore][QTimeZone] If systemTimeZone() is unable to
identify a valid system time zone, it now produces a warning the first
time it encounters the problem.

Task-number: QTBUG-116017
Change-Id: Ia437d8a03ff3cbf2b2cd98e8a8c3aebe50c1ee32
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Edward Welbourne 2023-09-14 11:15:24 +02:00
parent 59bf9160cc
commit 9c0def81e4
3 changed files with 27 additions and 8 deletions

View File

@ -556,16 +556,12 @@ QTimeZone::QTimeZone(QTimeZonePrivate &dd)
In all cases, the result's \l timeSpec() is Qt::TimeZone. When this
QTimeZone's timeSpec() is Qt::TimeZone, this QTimeZone itself is returned.
If timeSpec() is Qt::LocalTime then systemTimeZone() is returned.
If timeSpec() is Qt::UTC, QTimeZone::utc() is returned. If it is
Qt::OffsetFromUTC then QTimeZone(int) is passed its offset and the result is
returned.
If timeSpec() is Qt::LocalTime then an instance of the current system time
zone will be returned. This will not change to reflect any subsequent change
to the system time zone. It represents the local time that was in effect
when asBackendZone() was called.
When using a lightweight time representation - local time, UTC time or time
at a fixed offset from UTC - using methods only supported when feature \c
timezone is enabled may be more expensive than using a corresponding time
@ -1353,11 +1349,29 @@ QByteArray QTimeZone::systemTimeZoneId()
representation \c {QTimeZone(QTimeZone::LocalTime)}, albeit implemented as a
time zone.
The returned object will not change to reflect any subsequent change to the
system time zone. It represents the local time that was in effect when
asBackendZone() was called. On misconfigured systems, such as those that
lack the timezone data relied on by the backend for which Qt was compiled,
it may be invalid. In such a case, a warning is output.
\sa utc(), Initialization, asBackendZone()
*/
QTimeZone QTimeZone::systemTimeZone()
{
return QTimeZone(global_tz->backend->systemTimeZoneId());
// Use ID even if empty, as default constructor is invalid but empty-ID
// constructor goes to backend's default constructor, which may succeed.
const auto sys = QTimeZone(global_tz->backend->systemTimeZoneId());
if (!sys.isValid()) {
static bool neverWarned = true;
if (neverWarned) {
// Racey but, at worst, merely repeats the warning.
neverWarned = false;
qWarning("Unable to determine system time zone: "
"please check your system configuration.");
}
}
return sys;
}
/*!

View File

@ -573,6 +573,7 @@ void tst_QDate::startOfDay_endOfDay_data()
#if QT_CONFIG(timezone)
const QTimeZone sys = QTimeZone::systemTimeZone();
QVERIFY2(sys.isValid(), "Test depends on properly configured system");
for (const auto &tran : transitions) {
if (QTimeZone zone(tran.zone); zone.isValid()) {
QTest::newRow(tran.test)
@ -728,7 +729,9 @@ void tst_QDate::startOfDay_endOfDay_bounds()
QCOMPARE(qdteMin.startOfDay(UTC).date(), qdteMin);
QCOMPARE(qdteMin.startOfDay().date(), qdteMin);
#if QT_CONFIG(timezone)
QCOMPARE(qdteMin.startOfDay(QTimeZone::systemTimeZone()).date(), qdteMin);
const QTimeZone sys = QTimeZone::systemTimeZone();
QVERIFY2(sys.isValid(), "Test depends on properly configured system");
QCOMPARE(qdteMin.startOfDay(sys).date(), qdteMin);
QTimeZone berlin("Europe/Berlin");
if (berlin.isValid())
QCOMPARE(qdteMin.startOfDay(berlin).date(), qdteMin);

View File

@ -507,7 +507,9 @@ void tst_QTimeZone::asBackendZone()
void tst_QTimeZone::systemZone()
{
const QTimeZone zone = QTimeZone::systemTimeZone();
QVERIFY2(zone.isValid(), "Invalid system zone setting, tests are doomed.");
QVERIFY2(zone.isValid(),
"Invalid system zone setting, tests are doomed on misconfigured system.");
// This may fail on Windows if CLDR data doesn't map system MS ID to IANA ID:
QCOMPARE(zone.id(), QTimeZone::systemTimeZoneId());
QCOMPARE(zone, QTimeZone(QTimeZone::systemTimeZoneId()));
// Check it behaves the same as local-time: