summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp')
-rw-r--r--tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp926
1 files changed, 606 insertions, 320 deletions
diff --git a/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp b/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp
index 479c2771d7..a350ffeb04 100644
--- a/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp
+++ b/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp
@@ -1,34 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
#include <qtimezone.h>
#include <private/qtimezoneprivate_p.h>
+#include <private/qcomparisontesthelper_p.h>
+
#include <qlocale.h>
#if defined(Q_OS_WIN)
@@ -43,15 +20,20 @@ class tst_QTimeZone : public QObject
{
Q_OBJECT
-public:
- tst_QTimeZone();
-
private Q_SLOTS:
// Public class default system tests
void createTest();
void nullTest();
- void systemZone();
+ void assign();
+ void compareCompiles();
+ void compare_data();
+ void compare();
+ void timespec();
+ void offset();
void dataStreamTest();
+#if QT_CONFIG(timezone)
+ void asBackendZone();
+ void systemZone();
void isTimeZoneIdAvailable();
void availableTimeZoneIds();
void utcOffsetId_data();
@@ -75,28 +57,28 @@ private Q_SLOTS:
void macTest();
void darwinTypes();
void winTest();
+ void localeSpecificDisplayName_data();
+ void localeSpecificDisplayName();
+ void stdCompatibility_data();
+ void stdCompatibility();
+#endif // timezone backends
private:
void printTimeZone(const QTimeZone &tz);
-#ifdef QT_BUILD_INTERNAL
+#if defined(QT_BUILD_INTERNAL) && QT_CONFIG(timezone)
// Generic tests of privates, called by implementation-specific private tests:
void testCetPrivate(const QTimeZonePrivate &tzp);
void testEpochTranPrivate(const QTimeZonePrivate &tzp);
-#endif // QT_BUILD_INTERNAL
- const bool debug;
-};
-
-tst_QTimeZone::tst_QTimeZone()
+#endif // QT_BUILD_INTERNAL && timezone backends
// Set to true to print debug output, test Display Names and run long stress tests
- : debug(false)
-{
-}
+ static constexpr bool debug = false;
+};
void tst_QTimeZone::printTimeZone(const QTimeZone &tz)
{
QDateTime now = QDateTime::currentDateTime();
- QDateTime jan = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC);
- QDateTime jun = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC);
+ QDateTime jan = QDateTime(QDate(2012, 1, 1), QTime(0, 0), QTimeZone::UTC);
+ QDateTime jun = QDateTime(QDate(2012, 6, 1), QTime(0, 0), QTimeZone::UTC);
qDebug() << "";
qDebug() << "Time Zone = " << tz;
qDebug() << "";
@@ -180,9 +162,9 @@ void tst_QTimeZone::createTest()
QCOMPARE(tz.territory(), QLocale::NewZealand);
- QDateTime jan = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC);
- QDateTime jun = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC);
- QDateTime janPrev = QDateTime(QDate(2011, 1, 1), QTime(0, 0, 0), Qt::UTC);
+ QDateTime jan = QDateTime(QDate(2012, 1, 1), QTime(0, 0), QTimeZone::UTC);
+ QDateTime jun = QDateTime(QDate(2012, 6, 1), QTime(0, 0), QTimeZone::UTC);
+ QDateTime janPrev = QDateTime(QDate(2011, 1, 1), QTime(0, 0), QTimeZone::UTC);
QCOMPARE(tz.offsetFromUtc(jan), 13 * 3600);
QCOMPARE(tz.offsetFromUtc(jun), 12 * 3600);
@@ -202,7 +184,8 @@ void tst_QTimeZone::createTest()
QTimeZone::OffsetData tran = tz.nextTransition(jan);
// 2012-04-01 03:00 NZDT, +13 -> +12
QCOMPARE(tran.atUtc,
- QDateTime(QDate(2012, 4, 1), QTime(3, 0), Qt::OffsetFromUTC, 13 * 3600));
+ QDateTime(QDate(2012, 4, 1), QTime(3, 0),
+ QTimeZone::fromSecondsAheadOfUtc(13 * 3600)));
QCOMPARE(tran.offsetFromUtc, 12 * 3600);
QCOMPARE(tran.standardTimeOffset, 12 * 3600);
QCOMPARE(tran.daylightTimeOffset, 0);
@@ -210,7 +193,8 @@ void tst_QTimeZone::createTest()
tran = tz.nextTransition(jun);
// 2012-09-30 02:00 NZST, +12 -> +13
QCOMPARE(tran.atUtc,
- QDateTime(QDate(2012, 9, 30), QTime(2, 0), Qt::OffsetFromUTC, 12 * 3600));
+ QDateTime(QDate(2012, 9, 30), QTime(2, 0),
+ QTimeZone::fromSecondsAheadOfUtc(12 * 3600)));
QCOMPARE(tran.offsetFromUtc, 13 * 3600);
QCOMPARE(tran.standardTimeOffset, 12 * 3600);
QCOMPARE(tran.daylightTimeOffset, 3600);
@@ -218,7 +202,8 @@ void tst_QTimeZone::createTest()
tran = tz.previousTransition(jan);
// 2011-09-25 02:00 NZST, +12 -> +13
QCOMPARE(tran.atUtc,
- QDateTime(QDate(2011, 9, 25), QTime(2, 0), Qt::OffsetFromUTC, 12 * 3600));
+ QDateTime(QDate(2011, 9, 25), QTime(2, 0),
+ QTimeZone::fromSecondsAheadOfUtc(12 * 3600)));
QCOMPARE(tran.offsetFromUtc, 13 * 3600);
QCOMPARE(tran.standardTimeOffset, 12 * 3600);
QCOMPARE(tran.daylightTimeOffset, 3600);
@@ -226,23 +211,26 @@ void tst_QTimeZone::createTest()
tran = tz.previousTransition(jun);
// 2012-04-01 03:00 NZDT, +13 -> +12 (again)
QCOMPARE(tran.atUtc,
- QDateTime(QDate(2012, 4, 1), QTime(3, 0), Qt::OffsetFromUTC, 13 * 3600));
+ QDateTime(QDate(2012, 4, 1), QTime(3, 0),
+ QTimeZone::fromSecondsAheadOfUtc(13 * 3600)));
QCOMPARE(tran.offsetFromUtc, 12 * 3600);
QCOMPARE(tran.standardTimeOffset, 12 * 3600);
QCOMPARE(tran.daylightTimeOffset, 0);
QTimeZone::OffsetDataList expected;
// Reuse 2012's fall-back data for 2011-04-03:
- tran.atUtc = QDateTime(QDate(2011, 4, 3), QTime(3, 0), Qt::OffsetFromUTC, 13 * 3600);
+ tran.atUtc = QDateTime(QDate(2011, 4, 3), QTime(3, 0),
+ QTimeZone::fromSecondsAheadOfUtc(13 * 3600));
expected << tran;
// 2011's spring-forward:
- tran.atUtc = QDateTime(QDate(2011, 9, 25), QTime(2, 0), Qt::OffsetFromUTC, 12 * 3600);
+ tran.atUtc = QDateTime(QDate(2011, 9, 25), QTime(2, 0),
+ QTimeZone::fromSecondsAheadOfUtc(12 * 3600));
tran.offsetFromUtc = 13 * 3600;
tran.daylightTimeOffset = 3600;
expected << tran;
QTimeZone::OffsetDataList result = tz.transitions(janPrev, jan);
- QCOMPARE(result.count(), expected.count());
- for (int i = 0; i < expected.count(); ++i) {
+ QCOMPARE(result.size(), expected.size());
+ for (int i = 0; i < expected.size(); ++i) {
QCOMPARE(result.at(i).atUtc, expected.at(i).atUtc);
QCOMPARE(result.at(i).offsetFromUtc, expected.at(i).offsetFromUtc);
QCOMPARE(result.at(i).standardTimeOffset, expected.at(i).standardTimeOffset);
@@ -278,9 +266,9 @@ void tst_QTimeZone::nullTest()
QCOMPARE(nullTz1.territory(), QLocale::AnyTerritory);
QCOMPARE(nullTz1.comment(), QString());
- QDateTime jan = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC);
- QDateTime jun = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC);
- QDateTime janPrev = QDateTime(QDate(2011, 1, 1), QTime(0, 0, 0), Qt::UTC);
+ QDateTime jan = QDateTime(QDate(2012, 1, 1), QTime(0, 0), QTimeZone::UTC);
+ QDateTime jun = QDateTime(QDate(2012, 6, 1), QTime(0, 0), QTimeZone::UTC);
+ QDateTime janPrev = QDateTime(QDate(2011, 1, 1), QTime(0, 0), QTimeZone::UTC);
QCOMPARE(nullTz1.abbreviation(jan), QString());
QCOMPARE(nullTz1.displayName(jan), QString());
@@ -300,48 +288,178 @@ void tst_QTimeZone::nullTest()
QCOMPARE(nullTz1.isDaylightTime(jun), false);
QTimeZone::OffsetData data = nullTz1.offsetData(jan);
+ constexpr auto invalidOffset = std::numeric_limits<int>::min();
QCOMPARE(data.atUtc, QDateTime());
- QCOMPARE(data.offsetFromUtc, std::numeric_limits<int>::min());
- QCOMPARE(data.standardTimeOffset, std::numeric_limits<int>::min());
- QCOMPARE(data.daylightTimeOffset, std::numeric_limits<int>::min());
+ QCOMPARE(data.offsetFromUtc, invalidOffset);
+ QCOMPARE(data.standardTimeOffset, invalidOffset);
+ QCOMPARE(data.daylightTimeOffset, invalidOffset);
QCOMPARE(nullTz1.hasTransitions(), false);
data = nullTz1.nextTransition(jan);
QCOMPARE(data.atUtc, QDateTime());
- QCOMPARE(data.offsetFromUtc, std::numeric_limits<int>::min());
- QCOMPARE(data.standardTimeOffset, std::numeric_limits<int>::min());
- QCOMPARE(data.daylightTimeOffset, std::numeric_limits<int>::min());
+ QCOMPARE(data.offsetFromUtc, invalidOffset);
+ QCOMPARE(data.standardTimeOffset, invalidOffset);
+ QCOMPARE(data.daylightTimeOffset, invalidOffset);
data = nullTz1.previousTransition(jan);
QCOMPARE(data.atUtc, QDateTime());
- QCOMPARE(data.offsetFromUtc, std::numeric_limits<int>::min());
- QCOMPARE(data.standardTimeOffset, std::numeric_limits<int>::min());
- QCOMPARE(data.daylightTimeOffset, std::numeric_limits<int>::min());
+ QCOMPARE(data.offsetFromUtc, invalidOffset);
+ QCOMPARE(data.standardTimeOffset, invalidOffset);
+ QCOMPARE(data.daylightTimeOffset, invalidOffset);
}
-void tst_QTimeZone::systemZone()
+void tst_QTimeZone::assign()
{
- const QTimeZone zone = QTimeZone::systemTimeZone();
- QVERIFY(zone.isValid());
- QCOMPARE(zone.id(), QTimeZone::systemTimeZoneId());
- QCOMPARE(zone, QTimeZone(QTimeZone::systemTimeZoneId()));
- // Check it behaves the same as local-time:
- const QDate dates[] = {
- QDate::fromJulianDay(0), // far in the distant past (LMT)
- QDate(1625, 6, 8), // Before time-zones (date of Cassini's birth)
- QDate(1901, 12, 13), // Last day before 32-bit time_t's range
- QDate(1969, 12, 31), // Last day before the epoch
- QDate(1970, 0, 0), // Start of epoch
- QDate(2000, 2, 29), // An anomalous leap day
- QDate(2038, 1, 20) // First day after 32-bit time_t's range
- };
- for (const auto &date : dates)
- QCOMPARE(date.startOfDay(Qt::LocalTime), date.startOfDay(zone));
+ QTimeZone assignee;
+ QCOMPARE(assignee.timeSpec(), Qt::TimeZone);
+ assignee = QTimeZone();
+ QCOMPARE(assignee.timeSpec(), Qt::TimeZone);
+ assignee = QTimeZone::UTC;
+ QCOMPARE(assignee.timeSpec(), Qt::UTC);
+ assignee = QTimeZone::LocalTime;
+ QCOMPARE(assignee.timeSpec(), Qt::LocalTime);
+ assignee = QTimeZone();
+ QCOMPARE(assignee.timeSpec(), Qt::TimeZone);
+ assignee = QTimeZone::fromSecondsAheadOfUtc(1);
+ QCOMPARE(assignee.timeSpec(), Qt::OffsetFromUTC);
+ assignee = QTimeZone::fromSecondsAheadOfUtc(0);
+ QCOMPARE(assignee.timeSpec(), Qt::UTC);
+#if QT_CONFIG(timezone)
+ {
+ const QTimeZone cet("Europe/Oslo");
+ assignee = cet;
+ QCOMPARE(assignee.timeSpec(), Qt::TimeZone);
+ }
+#endif
+}
+
+void tst_QTimeZone::compareCompiles()
+{
+ QTestPrivate::testEqualityOperatorsCompile<QTimeZone>();
+}
+
+void tst_QTimeZone::compare_data()
+{
+ QTest::addColumn<QTimeZone>("left");
+ QTest::addColumn<QTimeZone>("right");
+ QTest::addColumn<bool>("expectedEqual");
+
+ const QTimeZone local;
+ const QTimeZone utc(QTimeZone::UTC);
+ const auto secondEast = QTimeZone::fromSecondsAheadOfUtc(1);
+ const auto zeroOffset = QTimeZone::fromSecondsAheadOfUtc(0);
+ const auto durationEast = QTimeZone::fromDurationAheadOfUtc(std::chrono::seconds{1});
+
+ QTest::newRow("local vs default-constructed") << local << QTimeZone() << true;
+ QTest::newRow("local vs UTC") << local << utc << false;
+ QTest::newRow("local vs secondEast") << local << secondEast << false;
+ QTest::newRow("secondEast vs UTC") << secondEast << utc << false;
+ QTest::newRow("UTC vs zeroOffset") << utc << zeroOffset << true;
+ QTest::newRow("secondEast vs durationEast") << secondEast << durationEast << true;
+}
+
+void tst_QTimeZone::compare()
+{
+ QFETCH(QTimeZone, left);
+ QFETCH(QTimeZone, right);
+ QFETCH(bool, expectedEqual);
+
+ QT_TEST_EQUALITY_OPS(left, right, expectedEqual);
+}
+
+void tst_QTimeZone::timespec()
+{
+ using namespace std::chrono_literals;
+ QCOMPARE(QTimeZone().timeSpec(), Qt::TimeZone);
+ QCOMPARE(QTimeZone(QTimeZone::UTC).timeSpec(), Qt::UTC);
+ QCOMPARE(QTimeZone(QTimeZone::LocalTime).timeSpec(), Qt::LocalTime);
+ QCOMPARE(QTimeZone::fromSecondsAheadOfUtc(0).timeSpec(), Qt::UTC);
+ QCOMPARE(QTimeZone::fromDurationAheadOfUtc(0s).timeSpec(), Qt::UTC);
+ QCOMPARE(QTimeZone::fromDurationAheadOfUtc(0min).timeSpec(), Qt::UTC);
+ QCOMPARE(QTimeZone::fromDurationAheadOfUtc(0h).timeSpec(), Qt::UTC);
+ QCOMPARE(QTimeZone::fromSecondsAheadOfUtc(1).timeSpec(), Qt::OffsetFromUTC);
+ QCOMPARE(QTimeZone::fromSecondsAheadOfUtc(-1).timeSpec(), Qt::OffsetFromUTC);
+ QCOMPARE(QTimeZone::fromSecondsAheadOfUtc(36000).timeSpec(), Qt::OffsetFromUTC);
+ QCOMPARE(QTimeZone::fromSecondsAheadOfUtc(-36000).timeSpec(), Qt::OffsetFromUTC);
+ QCOMPARE(QTimeZone::fromDurationAheadOfUtc(3h - 20min +17s).timeSpec(), Qt::OffsetFromUTC);
+ {
+ const QTimeZone zone;
+ QCOMPARE(zone.timeSpec(), Qt::TimeZone);
+ }
+ {
+ const QTimeZone zone = { QTimeZone::UTC };
+ QCOMPARE(zone.timeSpec(), Qt::UTC);
+ }
+ {
+ const QTimeZone zone = { QTimeZone::LocalTime };
+ QCOMPARE(zone.timeSpec(), Qt::LocalTime);
+ }
+ {
+ const auto zone = QTimeZone::fromSecondsAheadOfUtc(0);
+ QCOMPARE(zone.timeSpec(), Qt::UTC);
+ }
+ {
+ const auto zone = QTimeZone::fromDurationAheadOfUtc(0s);
+ QCOMPARE(zone.timeSpec(), Qt::UTC);
+ }
+ {
+ const auto zone = QTimeZone::fromSecondsAheadOfUtc(1);
+ QCOMPARE(zone.timeSpec(), Qt::OffsetFromUTC);
+ }
+ {
+ const auto zone = QTimeZone::fromDurationAheadOfUtc(1s);
+ QCOMPARE(zone.timeSpec(), Qt::OffsetFromUTC);
+ }
+#if QT_CONFIG(timezone)
+ QCOMPARE(QTimeZone("Europe/Oslo").timeSpec(), Qt::TimeZone);
+#endif
+}
+
+void tst_QTimeZone::offset()
+{
+ QCOMPARE(QTimeZone().fixedSecondsAheadOfUtc(), 0);
+ QCOMPARE(QTimeZone(QTimeZone::UTC).fixedSecondsAheadOfUtc(), 0);
+ QCOMPARE(QTimeZone::fromSecondsAheadOfUtc(0).fixedSecondsAheadOfUtc(), 0);
+ QCOMPARE(QTimeZone::fromDurationAheadOfUtc(std::chrono::seconds{}).fixedSecondsAheadOfUtc(), 0);
+ QCOMPARE(QTimeZone::fromDurationAheadOfUtc(std::chrono::minutes{}).fixedSecondsAheadOfUtc(), 0);
+ QCOMPARE(QTimeZone::fromDurationAheadOfUtc(std::chrono::hours{}).fixedSecondsAheadOfUtc(), 0);
+ QCOMPARE(QTimeZone::fromSecondsAheadOfUtc(1).fixedSecondsAheadOfUtc(), 1);
+ QCOMPARE(QTimeZone::fromSecondsAheadOfUtc(-1).fixedSecondsAheadOfUtc(), -1);
+ QCOMPARE(QTimeZone::fromSecondsAheadOfUtc(36000).fixedSecondsAheadOfUtc(), 36000);
+ QCOMPARE(QTimeZone::fromSecondsAheadOfUtc(-36000).fixedSecondsAheadOfUtc(), -36000);
+ {
+ const QTimeZone zone;
+ QCOMPARE(zone.fixedSecondsAheadOfUtc(), 0);
+ }
+ {
+ const QTimeZone zone = { QTimeZone::UTC };
+ QCOMPARE(zone.fixedSecondsAheadOfUtc(), 0);
+ }
+ {
+ const auto zone = QTimeZone::fromSecondsAheadOfUtc(0);
+ QCOMPARE(zone.fixedSecondsAheadOfUtc(), 0);
+ }
+ {
+ const auto zone = QTimeZone::fromDurationAheadOfUtc(std::chrono::seconds{});
+ QCOMPARE(zone.fixedSecondsAheadOfUtc(), 0);
+ }
+ {
+ const auto zone = QTimeZone::fromSecondsAheadOfUtc(1);
+ QCOMPARE(zone.fixedSecondsAheadOfUtc(), 1);
+ }
+ {
+ const auto zone = QTimeZone::fromDurationAheadOfUtc(std::chrono::seconds{1});
+ QCOMPARE(zone.fixedSecondsAheadOfUtc(), 1);
+ }
+#if QT_CONFIG(timezone)
+ QCOMPARE(QTimeZone("Europe/Oslo").fixedSecondsAheadOfUtc(), 0);
+#endif
}
void tst_QTimeZone::dataStreamTest()
{
+#ifndef QT_NO_DATASTREAM
// Test the OffsetFromUtc backend serialization. First with a custom timezone:
QTimeZone tz1("QST", 123456, "Qt Standard Time", "QST", QLocale::Norway, "Qt Testing");
QByteArray tmp;
@@ -395,14 +513,60 @@ void tst_QTimeZone::dataStreamTest()
ds >> tz2;
}
QCOMPARE(tz2.id(), tz1.id());
+#endif
+}
+
+#if QT_CONFIG(timezone)
+void tst_QTimeZone::asBackendZone()
+{
+ QCOMPARE(QTimeZone(QTimeZone::LocalTime).asBackendZone(), QTimeZone::systemTimeZone());
+ QCOMPARE(QTimeZone(QTimeZone::UTC).asBackendZone(), QTimeZone::utc());
+ QCOMPARE(QTimeZone::fromSecondsAheadOfUtc(-300).asBackendZone(), QTimeZone(-300));
+ QTimeZone cet("Europe/Oslo");
+ QCOMPARE(cet.asBackendZone(), cet);
+}
+
+void tst_QTimeZone::systemZone()
+{
+ const QTimeZone zone = QTimeZone::systemTimeZone();
+ 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:
+ const QDate dates[] = {
+ QDate::fromJulianDay(0), // far in the distant past (LMT)
+ QDate(1625, 6, 8), // Before time-zones (date of Cassini's birth)
+ QDate(1901, 12, 13), // Last day before 32-bit time_t's range
+ QDate(1969, 12, 31), // Last day before the epoch
+ QDate(1970, 0, 0), // Start of epoch
+ QDate(2000, 2, 29), // An anomalous leap day
+ QDate(2038, 1, 20) // First day after 32-bit time_t's range
+ };
+ for (const auto &date : dates)
+ QCOMPARE(date.startOfDay(QTimeZone::LocalTime), date.startOfDay(zone));
+
+#if __cpp_lib_chrono >= 201907L
+ const std::chrono::time_zone *currentTimeZone = std::chrono::current_zone();
+ QCOMPARE(QByteArrayView(currentTimeZone->name()), QByteArrayView(zone.id()));
+#endif
}
void tst_QTimeZone::isTimeZoneIdAvailable()
{
const QList<QByteArray> available = QTimeZone::availableTimeZoneIds();
for (const QByteArray &id : available) {
- QVERIFY(QTimeZone::isTimeZoneIdAvailable(id));
+ QVERIFY2(QTimeZone::isTimeZoneIdAvailable(id), id);
QVERIFY2(QTimeZone(id).isValid(), id);
+ QCOMPARE(QTimeZone(id).id(), id);
+ }
+ for (qint32 offset = QTimeZone::MinUtcOffsetSecs;
+ offset <= QTimeZone::MinUtcOffsetSecs; ++offset) {
+ const QByteArray id = QTimeZone(offset).id();
+ QVERIFY2(QTimeZone::isTimeZoneIdAvailable(id), id);
+ QVERIFY2(QTimeZone(id).isValid(), id);
+ QCOMPARE(QTimeZone(id).id(), id);
}
}
@@ -467,7 +631,11 @@ void tst_QTimeZone::utcOffsetId_data()
ROW("UTC-11", true, -39600);
ROW("UTC-09", true, -32400);
ROW("UTC-08", true, -28800);
+ ROW("UTC-8", true, -28800);
+ ROW("UTC-2:5", true, -7500);
ROW("UTC-02", true, -7200);
+ ROW("UTC+2", true, 7200);
+ ROW("UTC+2:5", true, 7500);
ROW("UTC+12", true, 43200);
ROW("UTC+13", true, 46800);
// Encountered in bug reports:
@@ -511,10 +679,23 @@ void tst_QTimeZone::utcOffsetId()
QTimeZone zone(id);
QCOMPARE(zone.isValid(), valid);
if (valid) {
- QDateTime epoch(QDate(1970, 1, 1), QTime(0, 0, 0), Qt::UTC);
+ QDateTime epoch(QDate(1970, 1, 1), QTime(0, 0), QTimeZone::UTC);
QFETCH(int, offset);
QCOMPARE(zone.offsetFromUtc(epoch), offset);
QVERIFY(!zone.hasDaylightTime());
+
+ // zone.id() will be an IANA ID with zero minutes field if original was
+ // a UTC offset by a whole number of hours. It will also zero-pad a
+ // single-digit hour or minute to two digits.
+ if (const qsizetype cut = id.indexOf(':'); cut >= 0) {
+ if (id.size() == cut + 2) // "...:m" -> "...:0m"
+ id.insert(cut + 1, '0');
+ } else if (zone.id().contains(':')) {
+ id += ":00";
+ }
+ if (id.indexOf(':') == 5) // UTC±h:mm -> UTC±0h:mm
+ id.insert(4, '0');
+
QCOMPARE(zone.id(), id);
}
}
@@ -526,7 +707,7 @@ void tst_QTimeZone::specificTransition_data()
QTest::addColumn<QDate>("stop");
QTest::addColumn<int>("count");
QTest::addColumn<QDateTime>("atUtc");
- // In minutes:
+ // In seconds:
QTest::addColumn<int>("offset");
QTest::addColumn<int>("stdoff");
QTest::addColumn<int>("dstoff");
@@ -543,16 +724,16 @@ void tst_QTimeZone::specificTransition_data()
{
QTest::newRow("Moscow/2014") // From original bug-report
<< QByteArray("Europe/Moscow")
- << QDate(2011, 4, 1) << QDate(2017, 12,31) << 1
- << QDateTime(QDate(2014, 10, 26), QTime(2, 0, 0),
- Qt::OffsetFromUTC, 4 * 3600).toUTC()
+ << QDate(2011, 4, 1) << QDate(2021, 12, 31) << 1
+ << QDateTime(QDate(2014, 10, 26), QTime(2, 0),
+ QTimeZone::fromSecondsAheadOfUtc(4 * 3600)).toUTC()
<< 3 * 3600 << 3 * 3600 << 0;
}
QTest::newRow("Moscow/2011") // Transition on 2011-03-27
<< QByteArray("Europe/Moscow")
<< QDate(2010, 11, 1) << QDate(2014, 10, 25) << 1
- << QDateTime(QDate(2011, 3, 27), QTime(2, 0, 0),
- Qt::OffsetFromUTC, 3 * 3600).toUTC()
+ << QDateTime(QDate(2011, 3, 27), QTime(2, 0),
+ QTimeZone::fromSecondsAheadOfUtc(3 * 3600)).toUTC()
<< 4 * 3600 << 4 * 3600 << 0;
}
@@ -573,14 +754,15 @@ void tst_QTimeZone::specificTransition()
if (!timeZone.isValid())
QSKIP("Missing time-zone data");
QTimeZone::OffsetDataList transits =
- timeZone.transitions(QDateTime(start, QTime(0, 0), timeZone),
- QDateTime(stop, QTime(23, 59), timeZone));
- QCOMPARE(transits.length(), count);
- const QTimeZone::OffsetData &transition = transits.at(0);
- QCOMPARE(transition.offsetFromUtc, offset);
- QCOMPARE(transition.standardTimeOffset, stdoff);
- QCOMPARE(transition.daylightTimeOffset, dstoff);
- QCOMPARE(transition.atUtc, atUtc);
+ timeZone.transitions(start.startOfDay(timeZone), stop.endOfDay(timeZone));
+ QCOMPARE(transits.size(), count);
+ if (count) {
+ const QTimeZone::OffsetData &transition = transits.at(0);
+ QCOMPARE(transition.offsetFromUtc, offset);
+ QCOMPARE(transition.standardTimeOffset, stdoff);
+ QCOMPARE(transition.daylightTimeOffset, dstoff);
+ QCOMPARE(transition.atUtc, atUtc);
+ }
}
void tst_QTimeZone::transitionEachZone_data()
@@ -595,19 +777,15 @@ void tst_QTimeZone::transitionEachZone_data()
int start, stop;
int year;
} table[] = {
- { 25666200, 3, 12, 1970 }, // 1970-10-25 01:30 UTC; North America
- { 1288488600, -4, 8, 2010 } // 2010-10-31 01:30 UTC; Europe, Russia
+ { 1288488600, -4, 8, 2010 }, // 2010-10-31 01:30 UTC; Europe, Russia
+ { 25666200, 3, 12, 1970 }, // 1970-10-25 01:30 UTC; North America
};
const auto zones = QTimeZone::availableTimeZoneIds();
- for (int k = std::size(table); k-- > 0; ) {
+ for (const auto &entry : table) {
for (const QByteArray &zone : zones) {
- const QString name = QString::asprintf("%s@%d", zone.constData(), table[k].year);
- QTest::newRow(name.toUtf8().constData())
- << zone
- << table[k].baseSecs
- << table[k].start
- << table[k].stop;
+ QTest::addRow("%s@%d", zone.constData(), entry.year)
+ << zone << entry.baseSecs << entry.start << entry.stop;
}
}
}
@@ -648,17 +826,29 @@ void tst_QTimeZone::transitionEachZone()
void tst_QTimeZone::checkOffset_data()
{
- QTest::addColumn<QByteArray>("zoneName");
+ QTest::addColumn<QTimeZone>("zone");
QTest::addColumn<QDateTime>("when");
QTest::addColumn<int>("netOffset");
QTest::addColumn<int>("stdOffset");
QTest::addColumn<int>("dstOffset");
+ const QTimeZone UTC = QTimeZone::UTC;
+ QTest::addRow("UTC")
+ << UTC << QDate(1970, 1, 1).startOfDay(UTC) << 0 << 0 << 0;
+ const auto east = QTimeZone::fromSecondsAheadOfUtc(28'800); // 8 hours
+ QTest::addRow("UTC+8")
+ << east << QDate(2000, 2, 29).startOfDay(east) << 28'800 << 28'800 << 0;
+ const auto west = QTimeZone::fromDurationAheadOfUtc(std::chrono::hours{-8});
+ QTest::addRow("UTC-8")
+ << west << QDate(2100, 2, 28).startOfDay(west) << -28'800 << -28'800 << 0;
+
struct {
const char *zone, *nick;
int year, month, day, hour, min, sec;
int std, dst;
} table[] = {
+ // Exercise the UTC-backend:
+ { "UTC", "epoch", 1970, 1, 1, 0, 0, 0, 0, 0 },
// Zone with no transitions (QTBUG-74614, QTBUG-74666, when TZ backend uses minimal data)
{ "Etc/UTC", "epoch", 1970, 1, 1, 0, 0, 0, 0, 0 },
{ "Etc/UTC", "pre_int32", 1901, 12, 13, 20, 45, 51, 0, 0 },
@@ -666,15 +856,15 @@ void tst_QTimeZone::checkOffset_data()
{ "Etc/UTC", "post_uint32", 2106, 2, 7, 6, 28, 17, 0, 0 },
{ "Etc/UTC", "initial", -292275056, 5, 16, 16, 47, 5, 0, 0 },
{ "Etc/UTC", "final", 292278994, 8, 17, 7, 12, 55, 0, 0 },
- // Kiev: regression test for QTBUG-64122 (on MS):
- { "Europe/Kiev", "summer", 2017, 10, 27, 12, 0, 0, 2 * 3600, 3600 },
- { "Europe/Kiev", "winter", 2017, 10, 29, 12, 0, 0, 2 * 3600, 0 }
+ // Kyiv: regression test for QTBUG-64122 (on MS):
+ { "Europe/Kyiv", "summer", 2017, 10, 27, 12, 0, 0, 2 * 3600, 3600 },
+ { "Europe/Kyiv", "winter", 2017, 10, 29, 12, 0, 0, 2 * 3600, 0 }
};
for (const auto &entry : table) {
QTimeZone zone(entry.zone);
if (zone.isValid()) {
QTest::addRow("%s@%s", entry.zone, entry.nick)
- << QByteArray(entry.zone)
+ << zone
<< QDateTime(QDate(entry.year, entry.month, entry.day),
QTime(entry.hour, entry.min, entry.sec), zone)
<< entry.dst + entry.std << entry.std << entry.dst;
@@ -686,18 +876,24 @@ void tst_QTimeZone::checkOffset_data()
void tst_QTimeZone::checkOffset()
{
- QFETCH(QByteArray, zoneName);
+ QFETCH(QTimeZone, zone);
QFETCH(QDateTime, when);
QFETCH(int, netOffset);
QFETCH(int, stdOffset);
QFETCH(int, dstOffset);
- QTimeZone zone(zoneName);
QVERIFY(zone.isValid()); // It was when _data() added the row !
QCOMPARE(zone.offsetFromUtc(when), netOffset);
QCOMPARE(zone.standardTimeOffset(when), stdOffset);
QCOMPARE(zone.daylightTimeOffset(when), dstOffset);
QCOMPARE(zone.isDaylightTime(when), dstOffset != 0);
+
+ // Also test offsetData(), which gets all this data in one go:
+ const auto data = zone.offsetData(when);
+ QCOMPARE(data.atUtc, when);
+ QCOMPARE(data.offsetFromUtc, netOffset);
+ QCOMPARE(data.standardTimeOffset, stdOffset);
+ QCOMPARE(data.daylightTimeOffset, dstOffset);
}
void tst_QTimeZone::availableTimeZoneIds()
@@ -723,12 +919,13 @@ void tst_QTimeZone::availableTimeZoneIds()
void tst_QTimeZone::stressTest()
{
+ const auto UTC = QTimeZone::UTC;
const QList<QByteArray> idList = QTimeZone::availableTimeZoneIds();
for (const QByteArray &id : idList) {
QTimeZone testZone = QTimeZone(id);
QCOMPARE(testZone.isValid(), true);
QCOMPARE(testZone.id(), id);
- QDateTime testDate = QDateTime(QDate(2015, 1, 1), QTime(0, 0, 0), Qt::UTC);
+ QDateTime testDate = QDateTime(QDate(2015, 1, 1), QTime(0, 0), UTC);
testZone.territory();
testZone.comment();
testZone.displayName(testDate);
@@ -745,10 +942,10 @@ void tst_QTimeZone::stressTest()
testZone.nextTransition(testDate);
testZone.previousTransition(testDate);
// Dates known to be outside possible tz file pre-calculated rules range
- QDateTime lowDate1 = QDateTime(QDate(1800, 1, 1), QTime(0, 0, 0), Qt::UTC);
- QDateTime lowDate2 = QDateTime(QDate(1800, 6, 1), QTime(0, 0, 0), Qt::UTC);
- QDateTime highDate1 = QDateTime(QDate(2200, 1, 1), QTime(0, 0, 0), Qt::UTC);
- QDateTime highDate2 = QDateTime(QDate(2200, 6, 1), QTime(0, 0, 0), Qt::UTC);
+ QDateTime lowDate1 = QDateTime(QDate(1800, 1, 1), QTime(0, 0), UTC);
+ QDateTime lowDate2 = QDateTime(QDate(1800, 6, 1), QTime(0, 0), UTC);
+ QDateTime highDate1 = QDateTime(QDate(2200, 1, 1), QTime(0, 0), UTC);
+ QDateTime highDate2 = QDateTime(QDate(2200, 6, 1), QTime(0, 0), UTC);
testZone.nextTransition(lowDate1);
testZone.nextTransition(lowDate2);
testZone.previousTransition(lowDate2);
@@ -801,46 +998,54 @@ void tst_QTimeZone::windowsId()
QByteArray("CST6CDT"));
QCOMPARE(QTimeZone::windowsIdToDefaultIanaId(QByteArray()), QByteArray());
- // No country is sorted list of all zones
- QList<QByteArray> list;
- list << "America/Chicago" << "America/Indiana/Knox" << "America/Indiana/Tell_City"
- << "America/Matamoros" << "America/Menominee" << "America/North_Dakota/Beulah"
- << "America/North_Dakota/Center" << "America/North_Dakota/New_Salem"
- << "America/Rainy_River" << "America/Rankin_Inlet" << "America/Resolute"
- << "America/Winnipeg" << "CST6CDT";
- QCOMPARE(QTimeZone::windowsIdToIanaIds("Central Standard Time"), list);
-
- // Check country with no match returns empty list
- list.clear();
- QCOMPARE(QTimeZone::windowsIdToIanaIds("Central Standard Time", QLocale::NewZealand),
- list);
-
- // Check valid country returns list in preference order
- list.clear();
- list << "America/Winnipeg" << "America/Rainy_River" << "America/Rankin_Inlet"
- << "America/Resolute";
- QCOMPARE(QTimeZone::windowsIdToIanaIds("Central Standard Time", QLocale::Canada), list);
-
- list.clear();
- list << "America/Matamoros";
- QCOMPARE(QTimeZone::windowsIdToIanaIds("Central Standard Time", QLocale::Mexico), list);
-
- list.clear();
- list << "America/Chicago" << "America/Indiana/Knox" << "America/Indiana/Tell_City"
- << "America/Menominee" << "America/North_Dakota/Beulah" << "America/North_Dakota/Center"
- << "America/North_Dakota/New_Salem";
- QCOMPARE(QTimeZone::windowsIdToIanaIds("Central Standard Time", QLocale::UnitedStates),
- list);
-
- list.clear();
- list << "CST6CDT";
- QCOMPARE(QTimeZone::windowsIdToIanaIds("Central Standard Time", QLocale::AnyTerritory),
- list);
-
- // Check no windowsId return empty
- list.clear();
- QCOMPARE(QTimeZone::windowsIdToIanaIds(QByteArray()), list);
- QCOMPARE(QTimeZone::windowsIdToIanaIds(QByteArray(), QLocale::AnyTerritory), list);
+ {
+ // With no country, expect sorted list of all zones for ID
+ const QList<QByteArray> list = {
+ "America/Chicago", "America/Indiana/Knox", "America/Indiana/Tell_City",
+ "America/Matamoros", "America/Menominee", "America/North_Dakota/Beulah",
+ "America/North_Dakota/Center", "America/North_Dakota/New_Salem",
+ "America/Ojinaga", "America/Rainy_River", "America/Rankin_Inlet",
+ "America/Resolute", "America/Winnipeg", "CST6CDT"
+ };
+ QCOMPARE(QTimeZone::windowsIdToIanaIds("Central Standard Time"), list);
+ }
+ {
+ // Check country with no match returns empty list
+ const QList<QByteArray> empty;
+ QCOMPARE(QTimeZone::windowsIdToIanaIds("Central Standard Time", QLocale::NewZealand),
+ empty);
+ }
+ {
+ // Check valid country returns list in preference order
+ const QList<QByteArray> list = {
+ "America/Winnipeg", "America/Rainy_River", "America/Rankin_Inlet", "America/Resolute"
+ };
+ QCOMPARE(QTimeZone::windowsIdToIanaIds("Central Standard Time", QLocale::Canada), list);
+ }
+ {
+ const QList<QByteArray> list = { "America/Matamoros", "America/Ojinaga" };
+ QCOMPARE(QTimeZone::windowsIdToIanaIds("Central Standard Time", QLocale::Mexico), list);
+ }
+ {
+ const QList<QByteArray> list = {
+ "America/Chicago", "America/Indiana/Knox", "America/Indiana/Tell_City",
+ "America/Menominee", "America/North_Dakota/Beulah", "America/North_Dakota/Center",
+ "America/North_Dakota/New_Salem"
+ };
+ QCOMPARE(QTimeZone::windowsIdToIanaIds("Central Standard Time", QLocale::UnitedStates),
+ list);
+ }
+ {
+ const QList<QByteArray> list = { "CST6CDT" };
+ QCOMPARE(QTimeZone::windowsIdToIanaIds("Central Standard Time", QLocale::AnyTerritory),
+ list);
+ }
+ {
+ // Check empty if given no windowsId:
+ const QList<QByteArray> empty;
+ QCOMPARE(QTimeZone::windowsIdToIanaIds(QByteArray()), empty);
+ QCOMPARE(QTimeZone::windowsIdToIanaIds(QByteArray(), QLocale::AnyTerritory), empty);
+ }
}
void tst_QTimeZone::isValidId_data()
@@ -863,7 +1068,7 @@ void tst_QTimeZone::isValidId_data()
// Parts separated by '/', each part min 1 and max of 14 chars
TESTSET("empty", "", false);
TESTSET("minimal", "m", true);
-#ifdef Q_OS_ANDROID
+#if defined(Q_OS_ANDROID) || QT_CONFIG(icu)
TESTSET("maximal", "East-Saskatchewan", true); // Android actually uses this
TESTSET("too long", "North-Saskatchewan", false); // ... but thankfully not this.
#else
@@ -934,7 +1139,7 @@ void tst_QTimeZone::isValidId_data()
QTest::newRow("a,z alone") << QByteArray("a,z") << false;
QTest::newRow("/z alone") << QByteArray("/z") << false;
QTest::newRow("-z alone") << QByteArray("-z") << false;
-#ifdef Q_OS_ANDROID
+#if defined(Q_OS_ANDROID) || QT_CONFIG(icu)
QTest::newRow("long alone") << QByteArray("12345678901234567") << true;
QTest::newRow("over-long alone") << QByteArray("123456789012345678") << false;
#else
@@ -961,6 +1166,7 @@ void tst_QTimeZone::serialize()
{
int parts = 0;
#ifndef QT_NO_DEBUG_STREAM
+ QTest::ignoreMessage(QtDebugMsg, "QTimeZone(\"\")");
qDebug() << QTimeZone(); // to verify no crash
parts++;
#endif
@@ -1018,18 +1224,25 @@ void tst_QTimeZone::utcTest()
QCOMPARE(tzp.hasDaylightTime(), false);
QCOMPARE(tzp.hasTransitions(), false);
- // Test create from UTC Offset (uses minimal id, skipping minutes if 0)
+ // Test create from UTC Offset:
QDateTime now = QDateTime::currentDateTime();
QTimeZone tz(36000);
QVERIFY(tz.isValid());
- QCOMPARE(tz.id(), QByteArray("UTC+10"));
+ QCOMPARE(tz.id(), QByteArray("UTC+10:00"));
QCOMPARE(tz.offsetFromUtc(now), 36000);
QCOMPARE(tz.standardTimeOffset(now), 36000);
QCOMPARE(tz.daylightTimeOffset(now), 0);
- // Test invalid UTC offset, must be in range -14 to +14 hours
- int min = -14*60*60;
- int max = 14*60*60;
+ tz = QTimeZone(15 * 3600); // no IANA ID, so uses minimal id, skipping :00 minutes
+ QVERIFY(tz.isValid());
+ QCOMPARE(tz.id(), QByteArray("UTC+15"));
+ QCOMPARE(tz.offsetFromUtc(now), 15 * 3600);
+ QCOMPARE(tz.standardTimeOffset(now), 15 * 3600);
+ QCOMPARE(tz.daylightTimeOffset(now), 0);
+
+ // Test validity range of UTC offsets:
+ int min = QTimeZone::MinUtcOffsetSecs;
+ int max = QTimeZone::MaxUtcOffsetSecs;
QCOMPARE(QTimeZone(min - 1).isValid(), false);
QCOMPARE(QTimeZone(min).isValid(), true);
QCOMPARE(QTimeZone(min + 1).isValid(), true);
@@ -1060,18 +1273,25 @@ void tst_QTimeZone::utcTest()
#endif // QT_BUILD_INTERNAL
}
+// Relies on local variable names: zone tzp and locale enUS.
+#define ZONE_DNAME_CHECK(type, name, val) \
+ QCOMPARE(tzp.displayName(QTimeZone::type, QTimeZone::name, enUS), \
+ QStringLiteral(val));
+
void tst_QTimeZone::icuTest()
{
#if defined(QT_BUILD_INTERNAL) && QT_CONFIG(icu)
// Known datetimes
- qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch();
- qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch();
+ qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0), QTimeZone::UTC).toMSecsSinceEpoch();
+ qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0), QTimeZone::UTC).toMSecsSinceEpoch();
// Test default constructor
QIcuTimeZonePrivate tzpd;
QVERIFY(tzpd.isValid());
- // Test invalid constructor
+ // Test invalid is not available:
+ QVERIFY(!tzpd.isTimeZoneIdAvailable("Gondwana/Erewhon"));
+ // and construction gives an invalid result:
QIcuTimeZonePrivate tzpi("Gondwana/Erewhon");
QCOMPARE(tzpi.isValid(), false);
@@ -1083,25 +1303,16 @@ void tst_QTimeZone::icuTest()
if (debug) {
// Test display names by type
QLocale enUS("en_US");
- QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::LongName, enUS),
- QString("Central European Standard Time"));
- QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::ShortName, enUS),
- QString("GMT+01:00"));
- QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::OffsetName, enUS),
- QString("UTC+01:00"));
- QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::LongName, enUS),
- QString("Central European Summer Time"));
- QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::ShortName, enUS),
- QString("GMT+02:00"));
- QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::OffsetName, enUS),
- QString("UTC+02:00"));
+ ZONE_DNAME_CHECK(StandardTime, LongName, "Central European Standard Time");
+ ZONE_DNAME_CHECK(StandardTime, ShortName, "GMT+01:00");
+ ZONE_DNAME_CHECK(StandardTime, OffsetName, "UTC+01:00");
+ ZONE_DNAME_CHECK(DaylightTime, LongName, "Central European Summer Time");
+ ZONE_DNAME_CHECK(DaylightTime, ShortName, "GMT+02:00");
+ ZONE_DNAME_CHECK(DaylightTime, OffsetName, "UTC+02:00");
// ICU C api does not support Generic Time yet, C++ api does
- QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::LongName, enUS),
- QString("Central European Standard Time"));
- QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::ShortName, enUS),
- QString("GMT+01:00"));
- QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::OffsetName, enUS),
- QString("UTC+01:00"));
+ ZONE_DNAME_CHECK(GenericTime, LongName, "Central European Standard Time");
+ ZONE_DNAME_CHECK(GenericTime, ShortName, "GMT+01:00");
+ ZONE_DNAME_CHECK(GenericTime, OffsetName, "UTC+01:00");
// Test Abbreviations
QCOMPARE(tzp.abbreviation(std), QString("CET"));
@@ -1118,9 +1329,10 @@ void tst_QTimeZone::icuTest()
void tst_QTimeZone::tzTest()
{
#if defined QT_BUILD_INTERNAL && defined Q_OS_UNIX && !defined Q_OS_DARWIN && !defined Q_OS_ANDROID
+ const auto UTC = QTimeZone::UTC;
// Known datetimes
- qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch();
- qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch();
+ qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0), UTC).toMSecsSinceEpoch();
+ qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0), UTC).toMSecsSinceEpoch();
// Test default constructor
QTzTimeZonePrivate tzpd;
@@ -1128,7 +1340,7 @@ void tst_QTimeZone::tzTest()
// Test invalid constructor
QTzTimeZonePrivate tzpi("Gondwana/Erewhon");
- QCOMPARE(tzpi.isValid(), false);
+ QVERIFY(!tzpi.isValid());
// Test named constructor
QTzTimeZonePrivate tzp("Europe/Berlin");
@@ -1153,8 +1365,8 @@ void tst_QTimeZone::tzTest()
// It shouldn't have any transitions. QTimeZone::hasTransitions() only says
// whether the backend supports them, so ask for transitions in a wide
// enough interval that one would show up, if there are any:
- QVERIFY(permaDst.transitions(QDate(2015, 1, 1).startOfDay(Qt::UTC).toMSecsSinceEpoch(),
- QDate(2020, 1, 1).startOfDay(Qt::UTC).toMSecsSinceEpoch()
+ QVERIFY(permaDst.transitions(QDate(2015, 1, 1).startOfDay(UTC).toMSecsSinceEpoch(),
+ QDate(2020, 1, 1).startOfDay(UTC).toMSecsSinceEpoch()
).isEmpty());
QTimeZone tzBrazil("BRT+3"); // parts of Northern Brazil, as a POSIX rule
@@ -1166,44 +1378,26 @@ void tst_QTimeZone::tzTest()
// Only test names in debug mode, names used can vary by ICU version installed
if (debug) {
#if QT_CONFIG(icu)
- QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::LongName, enUS),
- QString("Central European Standard Time"));
- QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::ShortName, enUS),
- QString("GMT+01:00"));
- QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::OffsetName, enUS),
- QString("UTC+01:00"));
- QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::LongName, enUS),
- QString("Central European Summer Time"));
- QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::ShortName, enUS),
- QString("GMT+02:00"));
- QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::OffsetName, enUS),
- QString("UTC+02:00"));
+ ZONE_DNAME_CHECK(StandardTime, LongName, "Central European Standard Time");
+ ZONE_DNAME_CHECK(StandardTime, ShortName, "GMT+01:00");
+ ZONE_DNAME_CHECK(StandardTime, OffsetName, "UTC+01:00");
+ ZONE_DNAME_CHECK(DaylightTime, LongName, "Central European Summer Time");
+ ZONE_DNAME_CHECK(DaylightTime, ShortName, "GMT+02:00");
+ ZONE_DNAME_CHECK(DaylightTime, OffsetName, "UTC+02:00");
// ICU C api does not support Generic Time yet, C++ api does
- QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::LongName, enUS),
- QString("Central European Standard Time"));
- QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::ShortName, enUS),
- QString("GMT+01:00"));
- QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::OffsetName, enUS),
- QString("UTC+01:00"));
+ ZONE_DNAME_CHECK(GenericTime, LongName, "Central European Standard Time");
+ ZONE_DNAME_CHECK(GenericTime, ShortName, "GMT+01:00");
+ ZONE_DNAME_CHECK(GenericTime, OffsetName, "UTC+01:00");
#else
- QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::LongName, enUS),
- QString("CET"));
- QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::ShortName, enUS),
- QString("CET"));
- QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::OffsetName, enUS),
- QString("CET"));
- QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::LongName, enUS),
- QString("CEST"));
- QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::ShortName, enUS),
- QString("CEST"));
- QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::OffsetName, enUS),
- QString("CEST"));
- QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::LongName, enUS),
- QString("CET"));
- QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::ShortName, enUS),
- QString("CET"));
- QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::OffsetName, enUS),
- QString("CET"));
+ ZONE_DNAME_CHECK(StandardTime, LongName, "CET");
+ ZONE_DNAME_CHECK(StandardTime, ShortName, "CET");
+ ZONE_DNAME_CHECK(StandardTime, OffsetName, "CET");
+ ZONE_DNAME_CHECK(DaylightTime, LongName, "CEST");
+ ZONE_DNAME_CHECK(DaylightTime, ShortName, "CEST");
+ ZONE_DNAME_CHECK(DaylightTime, OffsetName, "CEST");
+ ZONE_DNAME_CHECK(GenericTime, LongName, "CET");
+ ZONE_DNAME_CHECK(GenericTime, ShortName, "CET");
+ ZONE_DNAME_CHECK(GenericTime, OffsetName, "CET");
#endif // icu
// Test Abbreviations
@@ -1222,82 +1416,88 @@ void tst_QTimeZone::tzTest()
// Warning: This could vary depending on age of TZ file!
// Test low date uses first rule found
+ constexpr qint64 ancient = -Q_INT64_C(9999999999999);
// Note: Depending on the OS in question, the database may be carrying the
// Local Mean Time. which for Berlin is 0:53:28
- QTimeZonePrivate::Data dat = tzp.data(-9999999999999);
- QCOMPARE(dat.atMSecsSinceEpoch, (qint64)-9999999999999);
+ QTimeZonePrivate::Data dat = tzp.data(ancient);
+ QCOMPARE(dat.atMSecsSinceEpoch, ancient);
QCOMPARE(dat.daylightTimeOffset, 0);
if (dat.abbreviation == "LMT") {
QCOMPARE(dat.standardTimeOffset, 3208);
} else {
QCOMPARE(dat.standardTimeOffset, 3600);
+ constexpr qint64 invalidTime = std::numeric_limits<qint64>::min();
+ constexpr int invalidOffset = std::numeric_limits<int>::min();
// Test previous to low value is invalid
- dat = tzp.previousTransition(-9999999999999);
- QCOMPARE(dat.atMSecsSinceEpoch, std::numeric_limits<qint64>::min());
- QCOMPARE(dat.standardTimeOffset, std::numeric_limits<int>::min());
- QCOMPARE(dat.daylightTimeOffset, std::numeric_limits<int>::min());
+ dat = tzp.previousTransition(ancient);
+ QCOMPARE(dat.atMSecsSinceEpoch, invalidTime);
+ QCOMPARE(dat.standardTimeOffset, invalidOffset);
+ QCOMPARE(dat.daylightTimeOffset, invalidOffset);
}
- dat = tzp.nextTransition(-9999999999999);
- QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, Qt::OffsetFromUTC, 3600),
- QDateTime(QDate(1893, 4, 1), QTime(0, 6, 32), Qt::OffsetFromUTC, 3600));
+ dat = tzp.nextTransition(ancient);
+ QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch,
+ QTimeZone::fromSecondsAheadOfUtc(3600)),
+ QDateTime(QDate(1893, 4, 1), QTime(0, 6, 32),
+ QTimeZone::fromSecondsAheadOfUtc(3600)));
QCOMPARE(dat.standardTimeOffset, 3600);
QCOMPARE(dat.daylightTimeOffset, 0);
// Date-times late enough to exercise POSIX rules:
- qint64 stdHi = QDate(2100, 1, 1).startOfDay(Qt::UTC).toMSecsSinceEpoch();
- qint64 dstHi = QDate(2100, 6, 1).startOfDay(Qt::UTC).toMSecsSinceEpoch();
+ qint64 stdHi = QDate(2100, 1, 1).startOfDay(UTC).toMSecsSinceEpoch();
+ qint64 dstHi = QDate(2100, 6, 1).startOfDay(UTC).toMSecsSinceEpoch();
// Relevant last Sundays in October and March:
QCOMPARE(Qt::DayOfWeek(QDate(2099, 10, 25).dayOfWeek()), Qt::Sunday);
QCOMPARE(Qt::DayOfWeek(QDate(2100, 3, 28).dayOfWeek()), Qt::Sunday);
QCOMPARE(Qt::DayOfWeek(QDate(2100, 10, 31).dayOfWeek()), Qt::Sunday);
dat = tzp.data(stdHi);
- QCOMPARE(dat.atMSecsSinceEpoch - stdHi, (qint64)0);
+ QCOMPARE(dat.atMSecsSinceEpoch - stdHi, qint64(0));
QCOMPARE(dat.offsetFromUtc, 3600);
QCOMPARE(dat.standardTimeOffset, 3600);
QCOMPARE(dat.daylightTimeOffset, 0);
dat = tzp.data(dstHi);
- QCOMPARE(dat.atMSecsSinceEpoch - dstHi, (qint64)0);
+ QCOMPARE(dat.atMSecsSinceEpoch - dstHi, qint64(0));
QCOMPARE(dat.offsetFromUtc, 7200);
QCOMPARE(dat.standardTimeOffset, 3600);
QCOMPARE(dat.daylightTimeOffset, 3600);
dat = tzp.previousTransition(stdHi);
QCOMPARE(dat.abbreviation, QStringLiteral("CET"));
- QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, Qt::UTC),
- QDateTime(QDate(2099, 10, 25), QTime(3, 0), Qt::OffsetFromUTC, 7200));
+ QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, UTC),
+ QDateTime(QDate(2099, 10, 25), QTime(3, 0), QTimeZone::fromSecondsAheadOfUtc(7200)));
QCOMPARE(dat.offsetFromUtc, 3600);
QCOMPARE(dat.standardTimeOffset, 3600);
QCOMPARE(dat.daylightTimeOffset, 0);
dat = tzp.previousTransition(dstHi);
QCOMPARE(dat.abbreviation, QStringLiteral("CEST"));
- QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, Qt::UTC),
- QDateTime(QDate(2100, 3, 28), QTime(2, 0), Qt::OffsetFromUTC, 3600));
+ QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, UTC),
+ QDateTime(QDate(2100, 3, 28), QTime(2, 0), QTimeZone::fromSecondsAheadOfUtc(3600)));
QCOMPARE(dat.offsetFromUtc, 7200);
QCOMPARE(dat.standardTimeOffset, 3600);
QCOMPARE(dat.daylightTimeOffset, 3600);
dat = tzp.nextTransition(stdHi);
QCOMPARE(dat.abbreviation, QStringLiteral("CEST"));
- QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, Qt::UTC),
- QDateTime(QDate(2100, 3, 28), QTime(2, 0), Qt::OffsetFromUTC, 3600));
+ QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, UTC),
+ QDateTime(QDate(2100, 3, 28), QTime(2, 0), QTimeZone::fromSecondsAheadOfUtc(3600)));
QCOMPARE(dat.offsetFromUtc, 7200);
QCOMPARE(dat.standardTimeOffset, 3600);
QCOMPARE(dat.daylightTimeOffset, 3600);
dat = tzp.nextTransition(dstHi);
QCOMPARE(dat.abbreviation, QStringLiteral("CET"));
- QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, Qt::OffsetFromUTC, 3600),
- QDateTime(QDate(2100, 10, 31), QTime(3, 0), Qt::OffsetFromUTC, 7200));
+ QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch,
+ QTimeZone::fromSecondsAheadOfUtc(3600)),
+ QDateTime(QDate(2100, 10, 31), QTime(3, 0), QTimeZone::fromSecondsAheadOfUtc(7200)));
QCOMPARE(dat.offsetFromUtc, 3600);
QCOMPARE(dat.standardTimeOffset, 3600);
QCOMPARE(dat.daylightTimeOffset, 0);
- // Test TZ timezone vs UTC timezone for fractionary negative offset
+ // Test TZ timezone vs UTC timezone for non-whole-hour negative offset:
QTzTimeZonePrivate tztz1("America/Caracas");
QUtcTimeZonePrivate tzutc1("UTC-04:30");
QVERIFY(tztz1.isValid());
@@ -1306,22 +1506,25 @@ void tst_QTimeZone::tzTest()
QTzTimeZonePrivate::Data datautc1 = tzutc1.data(std);
QCOMPARE(datatz1.offsetFromUtc, datautc1.offsetFromUtc);
- // Test TZ timezone vs UTC timezone for fractionary positive offset
- QTzTimeZonePrivate tztz2("Asia/Calcutta");
+ // Test TZ timezone vs UTC timezone for non-whole-hour positive offset:
+ QTzTimeZonePrivate tztz2k("Asia/Kolkata"); // New name
+ QTzTimeZonePrivate tztz2c("Asia/Calcutta"); // Legacy name
+ // Can't assign QtzTZP, so use a reference; prefer new name.
+ QTzTimeZonePrivate &tztz2 = tztz2k.isValid() ? tztz2k : tztz2c;
QUtcTimeZonePrivate tzutc2("UTC+05:30");
- QVERIFY(tztz2.isValid());
+ QVERIFY2(tztz2.isValid(), tztz2.id().constData());
QVERIFY(tzutc2.isValid());
QTzTimeZonePrivate::Data datatz2 = tztz2.data(std);
QTzTimeZonePrivate::Data datautc2 = tzutc2.data(std);
QCOMPARE(datatz2.offsetFromUtc, datautc2.offsetFromUtc);
- // Test a timezone with a name that isn't all letters
+ // Test a timezone with an abbreviation that isn't all letters:
QTzTimeZonePrivate tzBarnaul("Asia/Barnaul");
if (tzBarnaul.isValid()) {
QCOMPARE(tzBarnaul.data(std).abbreviation, QString("+07"));
// first full day of the new rule (tzdata2016b)
- QDateTime dt(QDate(2016, 3, 28), QTime(0, 0, 0), Qt::UTC);
+ QDateTime dt(QDate(2016, 3, 28), QTime(0, 0), UTC);
QCOMPARE(tzBarnaul.data(dt.toMSecsSinceEpoch()).abbreviation, QString("+07"));
}
#endif // QT_BUILD_INTERNAL && Q_OS_UNIX && !Q_OS_DARWIN
@@ -1331,8 +1534,8 @@ void tst_QTimeZone::macTest()
{
#if defined(QT_BUILD_INTERNAL) && defined(Q_OS_DARWIN)
// Known datetimes
- qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch();
- qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch();
+ qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0), QTimeZone::UTC).toMSecsSinceEpoch();
+ qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0), QTimeZone::UTC).toMSecsSinceEpoch();
// Test default constructor
QMacTimeZonePrivate tzpd;
@@ -1350,25 +1553,16 @@ void tst_QTimeZone::macTest()
if (debug) {
// Test display names by type
QLocale enUS("en_US");
- QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::LongName, enUS),
- QString("Central European Standard Time"));
- QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::ShortName, enUS),
- QString("GMT+01:00"));
- QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::OffsetName, enUS),
- QString("UTC+01:00"));
- QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::LongName, enUS),
- QString("Central European Summer Time"));
- QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::ShortName, enUS),
- QString("GMT+02:00"));
- QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::OffsetName, enUS),
- QString("UTC+02:00"));
+ ZONE_DNAME_CHECK(StandardTime, LongName, "Central European Standard Time");
+ ZONE_DNAME_CHECK(StandardTime, ShortName, "GMT+01:00");
+ ZONE_DNAME_CHECK(StandardTime, OffsetName, "UTC+01:00");
+ ZONE_DNAME_CHECK(DaylightTime, LongName, "Central European Summer Time");
+ ZONE_DNAME_CHECK(DaylightTime, ShortName, "GMT+02:00");
+ ZONE_DNAME_CHECK(DaylightTime, OffsetName, "UTC+02:00");
// ICU C api does not support Generic Time yet, C++ api does
- QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::LongName, enUS),
- QString("Central European Time"));
- QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::ShortName, enUS),
- QString("Germany Time"));
- QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::OffsetName, enUS),
- QString("UTC+01:00"));
+ ZONE_DNAME_CHECK(GenericTime, LongName, "Central European Time");
+ ZONE_DNAME_CHECK(GenericTime, ShortName, "Germany Time");
+ ZONE_DNAME_CHECK(GenericTime, OffsetName, "UTC+01:00");
// Test Abbreviations
QCOMPARE(tzp.abbreviation(std), QString("CET"));
@@ -1396,8 +1590,8 @@ void tst_QTimeZone::winTest()
{
#if defined(QT_BUILD_INTERNAL) && defined(USING_WIN_TZ)
// Known datetimes
- qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch();
- qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch();
+ qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0), QTimeZone::UTC).toMSecsSinceEpoch();
+ qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0), QTimeZone::UTC).toMSecsSinceEpoch();
// Test default constructor
QWinTimeZonePrivate tzpd;
@@ -1419,24 +1613,17 @@ void tst_QTimeZone::winTest()
if (debug) {
// Test display names by type
QLocale enUS("en_US");
- QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::LongName, enUS),
- QString("W. Europe Standard Time"));
- QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::ShortName, enUS),
- QString("W. Europe Standard Time"));
- QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::OffsetName, enUS),
- QString("UTC+01:00"));
- QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::LongName, enUS),
- QString("W. Europe Daylight Time"));
- QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::ShortName, enUS),
- QString("W. Europe Daylight Time"));
- QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::OffsetName, enUS),
- QString("UTC+02:00"));
- QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::LongName, enUS),
- QString("(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"));
- QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::ShortName, enUS),
- QString("(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"));
- QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::OffsetName, enUS),
- QString("UTC+01:00"));
+ ZONE_DNAME_CHECK(StandardTime, LongName, "W. Europe Standard Time");
+ ZONE_DNAME_CHECK(StandardTime, ShortName, "W. Europe Standard Time");
+ ZONE_DNAME_CHECK(StandardTime, OffsetName, "UTC+01:00");
+ ZONE_DNAME_CHECK(DaylightTime, LongName, "W. Europe Daylight Time");
+ ZONE_DNAME_CHECK(DaylightTime, ShortName, "W. Europe Daylight Time");
+ ZONE_DNAME_CHECK(DaylightTime, OffsetName, "UTC+02:00");
+ ZONE_DNAME_CHECK(GenericTime, LongName,
+ "(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna");
+ ZONE_DNAME_CHECK(GenericTime, ShortName,
+ "(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna");
+ ZONE_DNAME_CHECK(GenericTime, OffsetName, "UTC+01:00");
// Test Abbreviations
QCOMPARE(tzp.abbreviation(std), QString("W. Europe Standard Time"));
@@ -1450,14 +1637,67 @@ void tst_QTimeZone::winTest()
#endif // QT_BUILD_INTERNAL && USING_WIN_TZ
}
+#undef ZONE_DNAME_CHECK
+
+void tst_QTimeZone::localeSpecificDisplayName_data()
+{
+#ifdef USING_WIN_TZ
+ QSKIP("MS backend does not use locale parameter");
+#endif
+ QTest::addColumn<QByteArray>("zoneName");
+ QTest::addColumn<QLocale>("locale");
+ QTest::addColumn<QTimeZone::TimeType>("timeType");
+ QTest::addColumn<QString>("expectedName");
+
+ QStringList names;
+ QLocale locale;
+ // Pick a non-system locale; German or French
+ if (QLocale::system().language() != QLocale::German) {
+ locale = QLocale(QLocale::German);
+ names << QString("Mitteleurop\u00e4ische Normalzeit")
+ << QString("Mitteleurop\u00e4ische Sommerzeit");
+ } else {
+ locale = QLocale(QLocale::French);
+ names << QString("heure normale d\u2019Europe centrale")
+ << QString("heure d\u2019\u00E9t\u00E9 d\u2019Europe centrale");
+ }
+
+ qsizetype index = 0;
+ QTest::newRow("Berlin, standard time")
+ << QByteArray("Europe/Berlin") << locale << QTimeZone::StandardTime
+ << names.at(index++);
+
+ QTest::newRow("Berlin, summer time")
+ << QByteArray("Europe/Berlin") << locale << QTimeZone::DaylightTime
+ << names.at(index++);
+}
+
+void tst_QTimeZone::localeSpecificDisplayName()
+{
+ // This test checks that QTimeZone::displayName() correctly uses the
+ // specified locale, NOT the system locale (see QTBUG-101460).
+ QFETCH(QByteArray, zoneName);
+ QFETCH(QLocale, locale);
+ QFETCH(QTimeZone::TimeType, timeType);
+ QFETCH(QString, expectedName);
+
+ QTimeZone zone(zoneName);
+ QVERIFY(zone.isValid());
+
+ const QString localeName = zone.displayName(timeType, QTimeZone::LongName, locale);
+ QCOMPARE(localeName, expectedName);
+}
+
#ifdef QT_BUILD_INTERNAL
// Test each private produces the same basic results for CET
void tst_QTimeZone::testCetPrivate(const QTimeZonePrivate &tzp)
{
// Known datetimes
- qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch();
- qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch();
- qint64 prev = QDateTime(QDate(2011, 1, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch();
+ const auto UTC = QTimeZone::UTC;
+ const auto eastOneHour = QTimeZone::fromSecondsAheadOfUtc(3600);
+ qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0), UTC).toMSecsSinceEpoch();
+ qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0), UTC).toMSecsSinceEpoch();
+ qint64 prev = QDateTime(QDate(2011, 1, 1), QTime(0, 0), UTC).toMSecsSinceEpoch();
QCOMPARE(tzp.offsetFromUtc(std), 3600);
QCOMPARE(tzp.offsetFromUtc(dst), 7200);
@@ -1490,32 +1730,34 @@ void tst_QTimeZone::testCetPrivate(const QTimeZonePrivate &tzp)
if (tzp.hasTransitions()) {
QTimeZonePrivate::Data tran = tzp.nextTransition(std);
// 2012-03-25 02:00 CET, +1 -> +2
- QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, Qt::UTC),
- QDateTime(QDate(2012, 3, 25), QTime(2, 0), Qt::OffsetFromUTC, 3600));
+ QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, UTC),
+ QDateTime(QDate(2012, 3, 25), QTime(2, 0), eastOneHour));
QCOMPARE(tran.offsetFromUtc, 7200);
QCOMPARE(tran.standardTimeOffset, 3600);
QCOMPARE(tran.daylightTimeOffset, 3600);
tran = tzp.nextTransition(dst);
// 2012-10-28 03:00 CEST, +2 -> +1
- QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, Qt::UTC),
- QDateTime(QDate(2012, 10, 28), QTime(3, 0), Qt::OffsetFromUTC, 2 * 3600));
+ QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, UTC),
+ QDateTime(QDate(2012, 10, 28), QTime(3, 0),
+ QTimeZone::fromSecondsAheadOfUtc(2 * 3600)));
QCOMPARE(tran.offsetFromUtc, 3600);
QCOMPARE(tran.standardTimeOffset, 3600);
QCOMPARE(tran.daylightTimeOffset, 0);
tran = tzp.previousTransition(std);
// 2011-10-30 03:00 CEST, +2 -> +1
- QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, Qt::UTC),
- QDateTime(QDate(2011, 10, 30), QTime(3, 0), Qt::OffsetFromUTC, 2 * 3600));
+ QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, UTC),
+ QDateTime(QDate(2011, 10, 30), QTime(3, 0),
+ QTimeZone::fromSecondsAheadOfUtc(2 * 3600)));
QCOMPARE(tran.offsetFromUtc, 3600);
QCOMPARE(tran.standardTimeOffset, 3600);
QCOMPARE(tran.daylightTimeOffset, 0);
tran = tzp.previousTransition(dst);
// 2012-03-25 02:00 CET, +1 -> +2 (again)
- QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, Qt::UTC),
- QDateTime(QDate(2012, 3, 25), QTime(2, 0), Qt::OffsetFromUTC, 3600));
+ QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, UTC),
+ QDateTime(QDate(2012, 3, 25), QTime(2, 0), eastOneHour));
QCOMPARE(tran.offsetFromUtc, 7200);
QCOMPARE(tran.standardTimeOffset, 3600);
QCOMPARE(tran.daylightTimeOffset, 3600);
@@ -1523,25 +1765,24 @@ void tst_QTimeZone::testCetPrivate(const QTimeZonePrivate &tzp)
QTimeZonePrivate::DataList expected;
// 2011-03-27 02:00 CET, +1 -> +2
tran.atMSecsSinceEpoch = QDateTime(QDate(2011, 3, 27), QTime(2, 0),
- Qt::OffsetFromUTC, 3600).toMSecsSinceEpoch();
+ eastOneHour).toMSecsSinceEpoch();
tran.offsetFromUtc = 7200;
tran.standardTimeOffset = 3600;
tran.daylightTimeOffset = 3600;
expected << tran;
// 2011-10-30 03:00 CEST, +2 -> +1
tran.atMSecsSinceEpoch = QDateTime(QDate(2011, 10, 30), QTime(3, 0),
- Qt::OffsetFromUTC, 2 * 3600).toMSecsSinceEpoch();
+ QTimeZone::fromSecondsAheadOfUtc(2 * 3600)
+ ).toMSecsSinceEpoch();
tran.offsetFromUtc = 3600;
tran.standardTimeOffset = 3600;
tran.daylightTimeOffset = 0;
expected << tran;
QTimeZonePrivate::DataList result = tzp.transitions(prev, std);
- QCOMPARE(result.count(), expected.count());
- for (int i = 0; i < expected.count(); ++i) {
- QCOMPARE(QDateTime::fromMSecsSinceEpoch(result.at(i).atMSecsSinceEpoch,
- Qt::OffsetFromUTC, 3600),
- QDateTime::fromMSecsSinceEpoch(expected.at(i).atMSecsSinceEpoch,
- Qt::OffsetFromUTC, 3600));
+ QCOMPARE(result.size(), expected.size());
+ for (int i = 0; i < expected.size(); ++i) {
+ QCOMPARE(QDateTime::fromMSecsSinceEpoch(result.at(i).atMSecsSinceEpoch, eastOneHour),
+ QDateTime::fromMSecsSinceEpoch(expected.at(i).atMSecsSinceEpoch, eastOneHour));
QCOMPARE(result.at(i).offsetFromUtc, expected.at(i).offsetFromUtc);
QCOMPARE(result.at(i).standardTimeOffset, expected.at(i).standardTimeOffset);
QCOMPARE(result.at(i).daylightTimeOffset, expected.at(i).daylightTimeOffset);
@@ -1555,10 +1796,13 @@ void tst_QTimeZone::testEpochTranPrivate(const QTimeZonePrivate &tzp)
if (!tzp.hasTransitions())
return; // test only viable for transitions
+ const auto UTC = QTimeZone::UTC;
+ const auto hour = std::chrono::hours{1};
QTimeZonePrivate::Data tran = tzp.nextTransition(0); // i.e. first after epoch
// 1970-04-26 02:00 EST, -5 -> -4
- const QDateTime after = QDateTime(QDate(1970, 4, 26), QTime(2, 0), Qt::OffsetFromUTC, -5 * 3600);
- const QDateTime found = QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, Qt::UTC);
+ const QDateTime after = QDateTime(QDate(1970, 4, 26), QTime(2, 0),
+ QTimeZone::fromDurationAheadOfUtc(-5 * hour));
+ const QDateTime found = QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, UTC);
#ifdef USING_WIN_TZ // MS gets the date wrong: 5th April instead of 26th.
QCOMPARE(found.toOffsetFromUtc(-5 * 3600).time(), after.time());
#else
@@ -1569,16 +1813,16 @@ void tst_QTimeZone::testEpochTranPrivate(const QTimeZonePrivate &tzp)
QCOMPARE(tran.daylightTimeOffset, 3600);
// Pre-epoch time-zones might not be supported at all:
- tran = tzp.nextTransition(QDateTime(QDate(1601, 1, 1), QTime(0, 0),
- Qt::UTC).toMSecsSinceEpoch());
+ tran = tzp.nextTransition(QDateTime(QDate(1601, 1, 1), QTime(0, 0), UTC).toMSecsSinceEpoch());
if (tran.atMSecsSinceEpoch != QTimeZonePrivate::invalidMSecs()
// Toronto *did* have a transition before 1970 (DST since 1918):
&& tran.atMSecsSinceEpoch < 0) {
// ... but, if they are, we should be able to search back to them:
tran = tzp.previousTransition(0); // i.e. last before epoch
// 1969-10-26 02:00 EDT, -4 -> -5
- QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, Qt::UTC),
- QDateTime(QDate(1969, 10, 26), QTime(2, 0), Qt::OffsetFromUTC, -4 * 3600));
+ QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, UTC),
+ QDateTime(QDate(1969, 10, 26), QTime(2, 0),
+ QTimeZone::fromDurationAheadOfUtc(-4 * hour)));
QCOMPARE(tran.offsetFromUtc, -5 * 3600);
QCOMPARE(tran.standardTimeOffset, -5 * 3600);
QCOMPARE(tran.daylightTimeOffset, 0);
@@ -1589,5 +1833,47 @@ void tst_QTimeZone::testEpochTranPrivate(const QTimeZonePrivate &tzp)
}
#endif // QT_BUILD_INTERNAL
+#if __cpp_lib_chrono >= 201907L
+Q_DECLARE_METATYPE(const std::chrono::time_zone *);
+#endif
+
+void tst_QTimeZone::stdCompatibility_data()
+{
+#if __cpp_lib_chrono >= 201907L
+ QTest::addColumn<const std::chrono::time_zone *>("timeZone");
+ const std::chrono::tzdb &tzdb = std::chrono::get_tzdb();
+ qDebug() << "Using tzdb version:" << QByteArrayView(tzdb.version);
+
+ for (const std::chrono::time_zone &zone : tzdb.zones)
+ QTest::addRow(zone.name().data()) << &zone;
+#else
+ QSKIP("This test requires C++20's <chrono>.");
+#endif
+}
+
+void tst_QTimeZone::stdCompatibility()
+{
+#if __cpp_lib_chrono >= 201907L
+ QFETCH(const std::chrono::time_zone *, timeZone);
+ QByteArrayView zoneName = QByteArrayView(timeZone->name());
+ QTimeZone tz = QTimeZone::fromStdTimeZonePtr(timeZone);
+ if (tz.isValid()) {
+ QCOMPARE(tz.id(), zoneName);
+ } else {
+ // QTBUG-102187: a few timezones reported by tzdb might not be
+ // recognized by QTimeZone. This happens for instance on Windows, where
+ // tzdb is using ICU, whose database does not match QTimeZone's.
+ const bool isKnownUnknown =
+ !zoneName.contains('/')
+ || zoneName == "Antarctica/Troll"
+ || zoneName.startsWith("SystemV/");
+ QVERIFY(isKnownUnknown);
+ }
+#else
+ QSKIP("This test requires C++20's <chrono>.");
+#endif
+}
+#endif // timezone backends
+
QTEST_APPLESS_MAIN(tst_QTimeZone)
#include "tst_qtimezone.moc"