summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/time
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/time')
-rw-r--r--tests/auto/corelib/time/CMakeLists.txt7
-rw-r--r--tests/auto/corelib/time/qcalendar/CMakeLists.txt9
-rw-r--r--tests/auto/corelib/time/qcalendar/tst_qcalendar.cpp104
-rw-r--r--tests/auto/corelib/time/qdate/CMakeLists.txt12
-rw-r--r--tests/auto/corelib/time/qdate/tst_qdate.cpp891
-rw-r--r--tests/auto/corelib/time/qdatetime/CMakeLists.txt18
-rw-r--r--tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp2354
-rw-r--r--tests/auto/corelib/time/qdatetime/tst_qdatetime_mac.mm33
-rw-r--r--tests/auto/corelib/time/qdatetimeparser/CMakeLists.txt11
-rw-r--r--tests/auto/corelib/time/qdatetimeparser/tst_qdatetimeparser.cpp91
-rw-r--r--tests/auto/corelib/time/qtime/CMakeLists.txt12
-rw-r--r--tests/auto/corelib/time/qtime/tst_qtime.cpp227
-rw-r--r--tests/auto/corelib/time/qtimezone/CMakeLists.txt14
-rw-r--r--tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp741
-rw-r--r--tests/auto/corelib/time/qtimezone/tst_qtimezone_darwin.mm33
15 files changed, 2835 insertions, 1722 deletions
diff --git a/tests/auto/corelib/time/CMakeLists.txt b/tests/auto/corelib/time/CMakeLists.txt
index e861a1ac71..f2dfbfa527 100644
--- a/tests/auto/corelib/time/CMakeLists.txt
+++ b/tests/auto/corelib/time/CMakeLists.txt
@@ -1,10 +1,9 @@
-# Generated from time.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(qcalendar)
add_subdirectory(qdate)
add_subdirectory(qdatetime)
add_subdirectory(qdatetimeparser)
add_subdirectory(qtime)
-if(QT_FEATURE_timezone)
- add_subdirectory(qtimezone)
-endif()
+add_subdirectory(qtimezone)
diff --git a/tests/auto/corelib/time/qcalendar/CMakeLists.txt b/tests/auto/corelib/time/qcalendar/CMakeLists.txt
index 685039523d..5b1b2dfc2a 100644
--- a/tests/auto/corelib/time/qcalendar/CMakeLists.txt
+++ b/tests/auto/corelib/time/qcalendar/CMakeLists.txt
@@ -1,9 +1,16 @@
-# Generated from qcalendar.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qcalendar Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qcalendar LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qcalendar
SOURCES
tst_qcalendar.cpp
diff --git a/tests/auto/corelib/time/qcalendar/tst_qcalendar.cpp b/tests/auto/corelib/time/qcalendar/tst_qcalendar.cpp
index 0bb41fd730..61999202d2 100644
--- a/tests/auto/corelib/time/qcalendar/tst_qcalendar.cpp
+++ b/tests/auto/corelib/time/qcalendar/tst_qcalendar.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -56,6 +31,49 @@ private slots:
void gregory();
};
+static void checkCenturyResolution(const QCalendar &cal, const QCalendar::YearMonthDay &base)
+{
+ quint8 weekDayMask = 0;
+ for (int offset = -7; offset < 8; ++offset) {
+ const auto probe = QDate(base.year, base.month, base.day, cal).addYears(100 * offset, cal);
+ const int dow = cal.dayOfWeek(probe);
+ if (probe.isValid() && dow > 0 && dow < 8)
+ weekDayMask |= 1 << quint8(dow - 1);
+ }
+ for (int j = 1; j < 8; ++j) {
+ const bool seen = weekDayMask & (1 << quint8(j - 1));
+ const QDate check = cal.matchCenturyToWeekday(base, j);
+ if (check.isValid()) {
+ const auto parts = cal.partsFromDate(check);
+ const int dow = cal.dayOfWeek(check);
+ QCOMPARE(dow, j);
+ QCOMPARE(parts.day, base.day);
+ QCOMPARE(parts.month, base.month);
+ int gap = parts.year - base.year;
+ if (!cal.hasYearZero() && (parts.year > 0) != (base.year > 0))
+ gap += parts.year > 0 ? -1 : +1;
+ auto report = qScopeGuard([parts, base]() {
+ qDebug("Wrongly matched year: %d replaced %d", parts.year, base.year);
+ });
+ QCOMPARE(gap % 100, 0);
+ // We searched 7 centuries each side of base.
+ if (seen) {
+ QCOMPARE_LT(gap / 100, 8);
+ QCOMPARE_GT(gap / 100, -8);
+ } else {
+ QVERIFY(gap / 100 >= 8 || gap / 100 <= -8);
+ }
+ report.dismiss();
+ } else {
+ auto report = qScopeGuard([j, base]() {
+ qDebug("Missed dow[%d] for %d/%d/%d", j, base.year, base.month, base.day);
+ });
+ QVERIFY(!seen);
+ report.dismiss();
+ }
+ }
+}
+
// Support for basic():
void tst_QCalendar::checkYear(const QCalendar &cal, int year, bool normal)
{
@@ -74,7 +92,7 @@ void tst_QCalendar::checkYear(const QCalendar &cal, int year, bool normal)
int sum = 0;
const int longest = cal.maximumDaysInMonth();
- for (int i = moons; i > 0; i--) {
+ for (int i = moons; i > 0; --i) {
const int last = cal.daysInMonth(i, year);
sum += last;
// Valid month has some days and no more than max:
@@ -87,6 +105,10 @@ void tst_QCalendar::checkYear(const QCalendar &cal, int year, bool normal)
QVERIFY(!cal.isDateValid(year, i, last + 1));
if (normal) // Unspecified year gets same daysInMonth():
QCOMPARE(cal.daysInMonth(i), last);
+
+ checkCenturyResolution(cal, {year, i, (last + 1) / 2});
+ if (QTest::currentTestFailed())
+ return;
}
// Months add up to the whole year:
QCOMPARE(sum, days);
@@ -393,13 +415,12 @@ void tst_QCalendar::gregory()
// dateToJulianDay() and weekDayOfJulian():
if (!year) // No year zero.
continue;
- qint64 first, last;
- QVERIFY2(QGregorianCalendar::julianFromParts(year, 1, 1, &first),
- "Only year zero should lack a first day");
+ const auto first = QGregorianCalendar::julianFromParts(year, 1, 1);
+ QVERIFY2(first, "Only year zero should lack a first day");
QCOMPARE(QGregorianCalendar::yearStartWeekDay(year),
- QGregorianCalendar::weekDayOfJulian(first));
- QVERIFY2(QGregorianCalendar::julianFromParts(year, 12, 31, &last),
- "Only year zero should lack a last day");
+ QGregorianCalendar::weekDayOfJulian(*first));
+ const auto last = QGregorianCalendar::julianFromParts(year, 12, 31);
+ QVERIFY2(last, "Only year zero should lack a last day");
const int lastTwo = (year + (year < 0 ? 1 : 0)) % 100 + (year < -1 ? 100 : 0);
const QDate probe(year, lastTwo && lastTwo <= 12 ? lastTwo : 8,
@@ -417,13 +438,14 @@ void tst_QCalendar::gregory()
if (year > 0 && lastTwo > 31)
QCOMPARE(match % 100, lastTwo);
// Its first and last days of the year match those of year:
- qint64 day;
- QVERIFY(QGregorianCalendar::julianFromParts(match, 1, 1, &day));
- QCOMPARE(QGregorianCalendar::weekDayOfJulian(day),
- QGregorianCalendar::weekDayOfJulian(first));
- QVERIFY(QGregorianCalendar::julianFromParts(match, 12, 31, &day));
- QCOMPARE(QGregorianCalendar::weekDayOfJulian(day),
- QGregorianCalendar::weekDayOfJulian(last));
+ auto day = QGregorianCalendar::julianFromParts(match, 1, 1);
+ QVERIFY(day);
+ QCOMPARE(QGregorianCalendar::weekDayOfJulian(*day),
+ QGregorianCalendar::weekDayOfJulian(*first));
+ day = QGregorianCalendar::julianFromParts(match, 12, 31);
+ QVERIFY(day);
+ QCOMPARE(QGregorianCalendar::weekDayOfJulian(*day),
+ QGregorianCalendar::weekDayOfJulian(*last));
}
}
}
diff --git a/tests/auto/corelib/time/qdate/CMakeLists.txt b/tests/auto/corelib/time/qdate/CMakeLists.txt
index 647be9a6f8..4d0f04a967 100644
--- a/tests/auto/corelib/time/qdate/CMakeLists.txt
+++ b/tests/auto/corelib/time/qdate/CMakeLists.txt
@@ -1,15 +1,23 @@
-# Generated from qdate.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdate Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qdate LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qdate
SOURCES
tst_qdate.cpp
DEFINES
QT_NO_FOREACH
QT_NO_KEYWORDS
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/time/qdate/tst_qdate.cpp b/tests/auto/corelib/time/qdate/tst_qdate.cpp
index 911ad90a7a..cacdad307f 100644
--- a/tests/auto/corelib/time/qdate/tst_qdate.cpp
+++ b/tests/auto/corelib/time/qdate/tst_qdate.cpp
@@ -1,37 +1,27 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-#include <private/qglobal_p.h> // for the icu feature test
+#include <QDateTime>
#include <QTest>
+
+#include <QLocale>
+#include <QMap>
#include <QTimeZone>
-#include <qdatetime.h>
-#include <qlocale.h>
+
+#include <private/qglobal_p.h> // for the icu feature test
+#include <private/qcomparisontesthelper_p.h>
+#include <private/qdatetime_p.h>
+#if !QT_CONFIG(timezone)
+# include <private/qtenvironmentvariables_p.h> // for qTzName()
+#endif
+
+using namespace QtPrivate::DateTimeConstants;
+using namespace Qt::StringLiterals;
+
+#if defined(Q_OS_WIN) && !QT_CONFIG(icu)
+# define USING_WIN_TZ
+#endif
class tst_QDate : public QObject
{
@@ -56,10 +46,8 @@ private Q_SLOTS:
void weekNumber_invalid();
void weekNumber_data();
void weekNumber();
-#if QT_CONFIG(timezone)
void startOfDay_endOfDay_data();
void startOfDay_endOfDay();
-#endif
void startOfDay_endOfDay_fixed_data();
void startOfDay_endOfDay_fixed();
void startOfDay_endOfDay_bounds();
@@ -71,12 +59,12 @@ private Q_SLOTS:
void addYears_data();
void addYears();
void daysTo();
+ void orderingCompiles();
void operator_eq_eq_data();
void operator_eq_eq();
- void operator_lt();
- void operator_gt();
- void operator_lt_eq();
- void operator_gt_eq();
+ void ordering_data();
+ void ordering();
+ void ordering_chrono_types();
void operator_insert_extract_data();
void operator_insert_extract();
#if QT_CONFIG(datestring)
@@ -102,6 +90,15 @@ private Q_SLOTS:
void qdebug() const;
private:
QDate defDate() const { return QDate(1900, 1, 1); }
+
+ QDate epochDate() const {
+ using namespace QtPrivate::DateTimeConstants;
+ Q_ASSERT(JULIAN_DAY_FOR_EPOCH == QDate(1970, 1, 1).toJulianDay());
+ return QDate::fromJulianDay(JULIAN_DAY_FOR_EPOCH);
+ }
+
+ static constexpr qint64 minJd = JulianDayMin;
+ static constexpr qint64 maxJd = JulianDayMax;
QDate invalidDate() const { return QDate(); }
};
@@ -112,9 +109,6 @@ void tst_QDate::isNull_data()
QTest::addColumn<qint64>("jd");
QTest::addColumn<bool>("null");
- qint64 minJd = Q_INT64_C(-784350574879);
- qint64 maxJd = Q_INT64_C( 784354017364);
-
QTest::newRow("qint64 min") << std::numeric_limits<qint64>::min() << true;
QTest::newRow("minJd - 1") << minJd - 1 << true;
QTest::newRow("minJd") << minJd << false;
@@ -198,6 +192,32 @@ void tst_QDate::isValid_data()
QTest::newRow("jd latest formula") << 1400000 << 12 << 31 << qint64(513060925) << true;
}
+#if __cpp_lib_chrono >= 201907L
+// QDate has a bigger range than year_month_date. The tests use this bigger
+// range. However building a year_month_time with "out of range" data has
+// unspecified results, so don't do that. See [time.cal.year],
+// [time.cal.month], [time.cal.day]. Also, std::chrono::year has a year 0, so
+// take that into account.
+static std::optional<std::chrono::year_month_day> convertToStdYearMonthDay(int y, int m, int d)
+{
+ using namespace std::chrono;
+
+ if (y >= int((year::min)())
+ && y <= int((year::max)())
+ && m >= 0
+ && m <= 255
+ && d >= 0
+ && d <= 255)
+ {
+ if (y < 0)
+ ++y;
+ return std::make_optional(year(y) / m / d);
+ }
+
+ return std::nullopt;
+}
+#endif
+
void tst_QDate::isValid()
{
QFETCH(int, year);
@@ -217,6 +237,19 @@ void tst_QDate::isValid()
QCOMPARE(d.year(), year);
QCOMPARE(d.month(), month);
QCOMPARE(d.day(), day);
+#if __cpp_lib_chrono >= 201907L
+ std::optional<std::chrono::year_month_day> ymd = convertToStdYearMonthDay(year, month, day);
+ if (ymd) {
+ QDate d = *ymd;
+ QCOMPARE(d.year(), year);
+ QCOMPARE(d.month(), month);
+ QCOMPARE(d.day(), day);
+
+ const std::chrono::sys_days qdateSysDays = d.toStdSysDays();
+ const std::chrono::sys_days ymdSysDays = *ymd;
+ QCOMPARE(qdateSysDays, ymdSysDays);
+ }
+#endif
} else {
QCOMPARE(d.year(), 0);
QCOMPARE(d.month(), 0);
@@ -463,123 +496,178 @@ void tst_QDate::weekNumber_invalid()
QCOMPARE( dt.weekNumber( &yearNumber ), 0 );
}
-#if QT_CONFIG(timezone)
+/* The MS backend tends to lack data for historical transitions. So some of the
+ transition-based tests will get wrong results, that we can't do anything
+ about, when using that backend. Rather than complicating the #if-ery more,
+ overtly record, in a flags column, which we need to ignore and merely make
+ the testing of these flags subject to #if-ery.
+
+ Android appears to lack at least one other.
+*/
+enum BackendKludge { IgnoreStart = 1, IgnoreEnd = 2, };
+Q_DECLARE_FLAGS(BackendKludges, BackendKludge)
+Q_DECLARE_OPERATORS_FOR_FLAGS(BackendKludges)
+
void tst_QDate::startOfDay_endOfDay_data()
{
QTest::addColumn<QDate>("date"); // Typically a spring-forward.
// A zone in which that date's start and end are worth checking:
- QTest::addColumn<QByteArray>("zoneName");
+ QTest::addColumn<QTimeZone>("zone");
// The start and end times in that zone:
QTest::addColumn<QTime>("start");
QTest::addColumn<QTime>("end");
+ // Ignored for backends that don't need it:
+ QTest::addColumn<BackendKludges>("kludge");
+
+ const QTime early(0, 0), late(23, 59, 59, 999), invalid(QDateTime().time());
+ constexpr BackendKludges Clean = {};
+ constexpr BackendKludges IgnoreBoth = IgnoreStart | IgnoreEnd;
+#ifdef USING_WIN_TZ
+ constexpr BackendKludges MsNoStart = IgnoreStart;
+ constexpr BackendKludges MsNoBoth = IgnoreBoth;
+#else
+ constexpr BackendKludges MsNoStart = Clean;
+ constexpr BackendKludges MsNoBoth = Clean;
+ // And use IgnoreBoth directly for the one transition Android lacks.
+#endif
+ const QTimeZone UTC(QTimeZone::UTC);
- const QTime initial(0, 0), final(23, 59, 59, 999), invalid(QDateTime().time());
+ using Bound = std::numeric_limits<qint64>;
+ const auto dateAtMillis = [UTC](qint64 millis) {
+ return QDateTime::fromMSecsSinceEpoch(millis, UTC).date();
+ };
- // UTC is always a valid zone.
- QTest::newRow("epoch")
- << QDate(1970, 1, 1) << QByteArray("UTC")
- << initial << final;
- if (QTimeZone("America/Sao_Paulo").isValid()) {
- QTest::newRow("Brazil")
- << QDate(2008, 10, 19) << QByteArray("America/Sao_Paulo")
- << QTime(1, 0) << final;
- }
-#if QT_CONFIG(icu) || !defined(Q_OS_WIN) // MS's TZ APIs lack data
- if (QTimeZone("Europe/Sofia").isValid()) {
- QTest::newRow("Sofia")
- << QDate(1994, 3, 27) << QByteArray("Europe/Sofia")
- << QTime(1, 0) << final;
- }
-#endif
- if (QTimeZone("Pacific/Kiritimati").isValid()) {
- QTest::newRow("Kiritimati")
- << QDate(1994, 12, 31) << QByteArray("Pacific/Kiritimati")
- << invalid << invalid;
+ // UTC and fixed offset are always available and predictable:
+ QTest::newRow("epoch") << epochDate() << UTC << early << late << Clean;
+
+ // First and last days in QDateTime's supported range:
+ QTest::newRow("earliest")
+ << dateAtMillis(Bound::min()) << UTC << invalid << late << Clean;
+ QTest::newRow("latest")
+ << dateAtMillis(Bound::max()) << UTC << early << invalid << Clean;
+
+ const struct {
+ const char *test;
+ const char *zone;
+ const QDate day;
+ const QTime start;
+ const QTime end;
+ const BackendKludges msOpt;
+ } transitions[] = {
+ // The western Mexico time-zones skipped the first hour of 1970.
+ { "BajaMexico", "America/Hermosillo", QDate(1970, 1, 1), QTime(1, 0), late, MsNoStart },
+
+ // Compare tst_QDateTime::fromStringDateFormat(ISO 24:00 in DST).
+ { "Brazil", "America/Sao_Paulo", QDate(2008, 10, 19), QTime(1, 0), late, Clean },
+
+ // Several southern zones within EET (but not the northern ones) spent
+ // part of the 1990s using midnight as spring transition.
+ { "Sofia", "Europe/Sofia", QDate(1994, 3, 27), QTime(1, 0), late, MsNoStart },
+
+ // Two Pacific zones skipped days to get on the west of the
+ // International Date Line; those days have neither start nor end.
+ { "Kiritimati", "Pacific/Kiritimati", QDate(1994, 12, 31), invalid, invalid, IgnoreBoth },
+ { "Samoa", "Pacific/Apia", QDate(2011, 12, 30), invalid, invalid, MsNoBoth },
+
+ // TODO: find other zones with transitions at/crossing midnight.
+ };
+ const QTimeZone local = QTimeZone::LocalTime;
+
+#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)
+ << tran.day << zone << tran.start << tran.end << tran.msOpt;
+ if (zone == sys) {
+ QTest::addRow("Local=%s", tran.test)
+ << tran.day << local << tran.start << tran.end << tran.msOpt;
+ }
+ }
}
- if (QTimeZone("Pacific/Apia").isValid()) {
- QTest::newRow("Samoa")
- << QDate(2011, 12, 30) << QByteArray("Pacific/Apia")
- << invalid << invalid;
+#else
+ const auto isLocalZone = [](const char *zone) {
+ const QLatin1StringView name(zone);
+ for (int i = 0; i < 2; ++i) {
+ if (qTzName(i) == name)
+ return true;
+ }
+ return false;
+ };
+ for (const auto &tran : transitions) {
+ if (isLocalZone(tran.zone)) { // Might need a different name to match
+ QTest::addRow("Local=%s", tran.test)
+ << tran.day << local << tran.start << tran.end << tran.msOpt;
+ }
}
- // TODO: find other zones with transitions at/crossing midnight.
+#endif // timezone
}
void tst_QDate::startOfDay_endOfDay()
{
- QFETCH(QDate, date);
- QFETCH(QByteArray, zoneName);
- QFETCH(QTime, start);
- QFETCH(QTime, end);
- const QTimeZone zone(zoneName);
+ QFETCH(const QDate, date);
+ QFETCH(const QTimeZone, zone);
+ QFETCH(const QTime, start);
+ QFETCH(const QTime, end);
+#if defined(USING_WIN_TZ) || defined(Q_OS_ANDROID) // Coping with backend limitations.
+ QFETCH(const BackendKludges, kludge);
+#define UNLESSKLUDGE(flag) if (!kludge.testFlag(flag))
+#else
+#define UNLESSKLUDGE(flag)
+#endif
QVERIFY(zone.isValid());
- const bool isSystem = QTimeZone::systemTimeZone() == zone;
+
QDateTime front(date.startOfDay(zone)), back(date.endOfDay(zone));
if (end.isValid())
QCOMPARE(date.addDays(1).startOfDay(zone).addMSecs(-1), back);
if (start.isValid())
QCOMPARE(date.addDays(-1).endOfDay(zone).addMSecs(1), front);
- do { // Avoids duplicating these tests for local-time when it *is* zone:
- if (start.isValid()) {
- QCOMPARE(front.date(), date);
- QCOMPARE(front.time(), start);
- }
- if (end.isValid()) {
- QCOMPARE(back.date(), date);
- QCOMPARE(back.time(), end);
- }
- if (front.timeSpec() == Qt::LocalTime)
- break;
- front = date.startOfDay(Qt::LocalTime);
- back = date.endOfDay(Qt::LocalTime);
- } while (isSystem);
- if (end.isValid())
- QCOMPARE(date.addDays(1).startOfDay(Qt::LocalTime).addMSecs(-1), back);
- if (start.isValid())
- QCOMPARE(date.addDays(-1).endOfDay(Qt::LocalTime).addMSecs(1), front);
- if (!isSystem) {
- // These might fail if system zone coincides with zone; but only if it
- // did something similarly unusual on the date picked for this test.
- if (start.isValid()) {
- QCOMPARE(front.date(), date);
- QCOMPARE(front.time(), QTime(0, 0));
- }
- if (end.isValid()) {
- QCOMPARE(back.date(), date);
- QCOMPARE(back.time(), QTime(23, 59, 59, 999));
- }
+
+ if (start.isValid()) {
+ QVERIFY(front.isValid());
+ QCOMPARE(front.date(), date);
+ UNLESSKLUDGE(IgnoreStart) QCOMPARE(front.time(), start);
+ } else UNLESSKLUDGE(IgnoreStart) {
+ auto report = qScopeGuard([front]() { qDebug() << "Start of day:" << front; });
+ QVERIFY(!front.isValid());
+ report.dismiss();
}
+ if (end.isValid()) {
+ QVERIFY(back.isValid());
+ QCOMPARE(back.date(), date);
+ UNLESSKLUDGE(IgnoreEnd) QCOMPARE(back.time(), end);
+ } else UNLESSKLUDGE(IgnoreEnd) {
+ auto report = qScopeGuard([back]() { qDebug() << "End of day:" << back; });
+ QVERIFY(!back.isValid());
+ report.dismiss();
+ }
+#undef UNLESSKLUDGE
}
-#endif // timezone
void tst_QDate::startOfDay_endOfDay_fixed_data()
{
+ QTest::addColumn<QDate>("date");
+
const qint64 kilo(1000);
using Bounds = std::numeric_limits<qint64>;
- const QDateTime
- first(QDateTime::fromMSecsSinceEpoch(Bounds::min() + 1, Qt::UTC)),
- start32sign(QDateTime::fromMSecsSinceEpoch(Q_INT64_C(-0x80000000) * kilo, Qt::UTC)),
- end32sign(QDateTime::fromMSecsSinceEpoch(Q_INT64_C(0x80000000) * kilo, Qt::UTC)),
- end32unsign(QDateTime::fromMSecsSinceEpoch(Q_INT64_C(0x100000000) * kilo, Qt::UTC)),
- last(QDateTime::fromMSecsSinceEpoch(Bounds::max(), Qt::UTC));
-
- const struct {
- const char *name;
- QDate date;
- } data[] = {
- { "epoch", QDate(1970, 1, 1) },
- { "y2k-leap-day", QDate(2000, 2, 29) },
- // Just outside the start and end of 32-bit time_t:
- { "pre-sign32", QDate(start32sign.date().year(), 1, 1) },
- { "post-sign32", QDate(end32sign.date().year(), 12, 31) },
- { "post-uint32", QDate(end32unsign.date().year(), 12, 31) },
- // Just inside the start and end of QDateTime's range:
- { "first-full", first.date().addDays(1) },
- { "last-full", last.date().addDays(-1) }
- };
-
- QTest::addColumn<QDate>("date");
- for (const auto &r : data)
- QTest::newRow(r.name) << r.date;
+ const auto UTC = QTimeZone::UTC;
+ const QDateTime first(QDateTime::fromMSecsSinceEpoch(Bounds::min() + 1, UTC));
+ const QDateTime start32sign(QDateTime::fromMSecsSinceEpoch(Q_INT64_C(-0x80000000) * kilo, UTC));
+ const QDateTime end32sign(QDateTime::fromMSecsSinceEpoch(Q_INT64_C(0x80000000) * kilo, UTC));
+ const QDateTime end32unsign(QDateTime::fromMSecsSinceEpoch(Q_INT64_C(0x100000000) * kilo, UTC));
+ const QDateTime last(QDateTime::fromMSecsSinceEpoch(Bounds::max(), UTC));
+
+ QTest::newRow("epoch") << epochDate();
+ QTest::newRow("y2k-leap-day") << QDate(2000, 2, 29);
+ QTest::newRow("start-1900") << QDate(1900, 1, 1); // QTBUG-99747
+ // Just outside the start and end of 32-bit time_t:
+ QTest::newRow("pre-sign32") << QDate(start32sign.date().year(), 1, 1);
+ QTest::newRow("post-sign32") << QDate(end32sign.date().year(), 12, 31);
+ QTest::newRow("post-uint32") << QDate(end32unsign.date().year(), 12, 31);
+ // Just inside the start and end of QDateTime's range:
+ QTest::newRow("first-full") << first.date().addDays(1);
+ QTest::newRow("last-full") << last.date().addDays(-1);
}
void tst_QDate::startOfDay_endOfDay_fixed()
@@ -587,56 +675,79 @@ void tst_QDate::startOfDay_endOfDay_fixed()
const QTime early(0, 0), late(23, 59, 59, 999);
QFETCH(QDate, date);
- QDateTime start(date.startOfDay(Qt::UTC));
- QDateTime end(date.endOfDay(Qt::UTC));
+ QDateTime start(date.startOfDay(QTimeZone::UTC));
+ QDateTime end(date.endOfDay(QTimeZone::UTC));
QCOMPARE(start.date(), date);
QCOMPARE(end.date(), date);
QCOMPARE(start.time(), early);
QCOMPARE(end.time(), late);
- QCOMPARE(date.addDays(1).startOfDay(Qt::UTC).addMSecs(-1), end);
- QCOMPARE(date.addDays(-1).endOfDay(Qt::UTC).addMSecs(1), start);
+ QCOMPARE(date.addDays(1).startOfDay(QTimeZone::UTC).addMSecs(-1), end);
+ QCOMPARE(date.addDays(-1).endOfDay(QTimeZone::UTC).addMSecs(1), start);
for (int offset = -60 * 16; offset <= 60 * 16; offset += 65) {
- start = date.startOfDay(Qt::OffsetFromUTC, offset);
- end = date.endOfDay(Qt::OffsetFromUTC, offset);
+ const auto zone = QTimeZone::fromSecondsAheadOfUtc(offset);
+ start = date.startOfDay(zone);
+ end = date.endOfDay(zone);
QCOMPARE(start.date(), date);
QCOMPARE(end.date(), date);
QCOMPARE(start.time(), early);
QCOMPARE(end.time(), late);
- QCOMPARE(date.addDays(1).startOfDay(Qt::OffsetFromUTC, offset).addMSecs(-1), end);
- QCOMPARE(date.addDays(-1).endOfDay(Qt::OffsetFromUTC, offset).addMSecs(1), start);
+ QCOMPARE(date.addDays(1).startOfDay(zone).addMSecs(-1), end);
+ QCOMPARE(date.addDays(-1).endOfDay(zone).addMSecs(1), start);
+ }
+
+ // Minimal testing for LocalTime and TimeZone
+ QCOMPARE(date.startOfDay().date(), date);
+ QCOMPARE(date.endOfDay().date(), date);
+#if QT_CONFIG(timezone)
+ const QTimeZone cet("Europe/Oslo");
+ if (cet.isValid()) {
+ QCOMPARE(date.startOfDay(cet).date(), date);
+ QCOMPARE(date.endOfDay(cet).date(), date);
}
+#endif
}
void tst_QDate::startOfDay_endOfDay_bounds()
{
// Check the days in which QDateTime's range starts and ends:
using Bounds = std::numeric_limits<qint64>;
+ const auto UTC = QTimeZone::UTC;
const QDateTime
- first(QDateTime::fromMSecsSinceEpoch(Bounds::min(), Qt::UTC)),
- last(QDateTime::fromMSecsSinceEpoch(Bounds::max(), Qt::UTC)),
- epoch(QDateTime::fromMSecsSinceEpoch(0, Qt::UTC));
+ first(QDateTime::fromMSecsSinceEpoch(Bounds::min(), UTC)),
+ last(QDateTime::fromMSecsSinceEpoch(Bounds::max(), UTC)),
+ epoch(QDateTime::fromMSecsSinceEpoch(0, UTC));
// First, check these *are* the start and end of QDateTime's range:
QVERIFY(first.isValid());
QVERIFY(last.isValid());
QVERIFY(first < epoch);
QVERIFY(last > epoch);
- // QDateTime's addMSecs doesn't check against {und,ov}erflow ...
QVERIFY(!first.addMSecs(-1).isValid() || first.addMSecs(-1) > first);
QVERIFY(!last.addMSecs(1).isValid() || last.addMSecs(1) < last);
// Now test start/end methods with them:
- QCOMPARE(first.date().endOfDay(Qt::UTC).time(), QTime(23, 59, 59, 999));
- QCOMPARE(last.date().startOfDay(Qt::UTC).time(), QTime(0, 0));
- QVERIFY(!first.date().startOfDay(Qt::UTC).isValid());
- QVERIFY(!last.date().endOfDay(Qt::UTC).isValid());
+ QCOMPARE(first.date().endOfDay(UTC).time(), QTime(23, 59, 59, 999));
+ QCOMPARE(last.date().startOfDay(UTC).time(), QTime(0, 0));
+ QVERIFY(!first.date().startOfDay(UTC).isValid());
+ QVERIFY(!last.date().endOfDay(UTC).isValid());
+
+ // Test for QTBUG-100873, shouldn't assert:
+ const QDate qdteMin(1752, 9, 14); // Used by QDateTimeEdit
+ QCOMPARE(qdteMin.startOfDay(UTC).date(), qdteMin);
+ QCOMPARE(qdteMin.startOfDay().date(), qdteMin);
+#if QT_CONFIG(timezone)
+ 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);
+#endif
}
void tst_QDate::julianDaysLimits()
{
qint64 min = std::numeric_limits<qint64>::min();
qint64 max = std::numeric_limits<qint64>::max();
- qint64 minJd = Q_INT64_C(-784350574879);
- qint64 maxJd = Q_INT64_C( 784354017364);
QDate maxDate = QDate::fromJulianDay(maxJd);
QDate minDate = QDate::fromJulianDay(minJd);
@@ -704,11 +815,19 @@ void tst_QDate::addDays()
QFETCH( int, expectedDay );
QDate dt( year, month, day );
- dt = dt.addDays( amountToAdd );
+ QDate dt2 = dt.addDays( amountToAdd );
- QCOMPARE( dt.year(), expectedYear );
- QCOMPARE( dt.month(), expectedMonth );
- QCOMPARE( dt.day(), expectedDay );
+ QCOMPARE( dt2.year(), expectedYear );
+ QCOMPARE( dt2.month(), expectedMonth );
+ QCOMPARE( dt2.day(), expectedDay );
+
+#if __cpp_lib_chrono >= 201907L
+ QDate dt3 = dt.addDuration( std::chrono::days( amountToAdd ) );
+
+ QCOMPARE( dt3.year(), expectedYear );
+ QCOMPARE( dt3.month(), expectedMonth );
+ QCOMPARE( dt3.day(), expectedDay );
+#endif
}
void tst_QDate::addDays_data()
@@ -851,9 +970,6 @@ void tst_QDate::addYears_data()
void tst_QDate::daysTo()
{
- qint64 minJd = Q_INT64_C(-784350574879);
- qint64 maxJd = Q_INT64_C( 784354017364);
-
QDate dt1(2000, 1, 1);
QDate dt2(2000, 1, 5);
QCOMPARE(dt1.daysTo(dt2), (qint64) 4);
@@ -878,6 +994,17 @@ void tst_QDate::daysTo()
QCOMPARE(zeroDate.daysTo(minDate), minJd);
}
+void tst_QDate::orderingCompiles()
+{
+ QTestPrivate::testAllComparisonOperatorsCompile<QDate>();
+#if __cpp_lib_chrono >= 201907L
+ QTestPrivate::testAllComparisonOperatorsCompile<QDate, std::chrono::year_month_day>();
+ QTestPrivate::testAllComparisonOperatorsCompile<QDate, std::chrono::year_month_day_last>();
+ QTestPrivate::testAllComparisonOperatorsCompile<QDate, std::chrono::year_month_weekday>();
+ QTestPrivate::testAllComparisonOperatorsCompile<QDate, std::chrono::year_month_weekday_last>();
+#endif
+}
+
void tst_QDate::operator_eq_eq_data()
{
QTest::addColumn<QDate>("d1");
@@ -914,137 +1041,83 @@ void tst_QDate::operator_eq_eq()
QFETCH(QDate, d2);
QFETCH(bool, expectEqual);
- bool equal = d1 == d2;
- QCOMPARE(equal, expectEqual);
- bool notEqual = d1 != d2;
- QCOMPARE(notEqual, !expectEqual);
+ QT_TEST_EQUALITY_OPS(d1, d2, expectEqual);
- if (equal)
+ if (expectEqual)
QVERIFY(qHash(d1) == qHash(d2));
}
-void tst_QDate::operator_lt()
-{
- QDate d1(2000,1,2);
- QDate d2(2000,1,2);
- QVERIFY( !(d1 < d2) );
-
- d1 = QDate(2001,12,4);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 < d2 );
-
- d1 = QDate(2001,11,5);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 < d2 );
-
- d1 = QDate(2000,12,5);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 < d2 );
-
- d1 = QDate(2002,12,5);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 < d2) );
-
- d1 = QDate(2001,12,5);
- d2 = QDate(2001,11,5);
- QVERIFY( !(d1 < d2) );
-
- d1 = QDate(2001,12,6);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 < d2) );
-}
-
-void tst_QDate::operator_gt()
+void tst_QDate::ordering_data()
{
- QDate d1(2000,1,2);
- QDate d2(2000,1,2);
- QVERIFY( !(d1 > d2) );
-
- d1 = QDate(2001,12,4);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 > d2) );
-
- d1 = QDate(2001,11,5);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 > d2) );
-
- d1 = QDate(2000,12,5);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 > d2) );
-
- d1 = QDate(2002,12,5);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 > d2 );
-
- d1 = QDate(2001,12,5);
- d2 = QDate(2001,11,5);
- QVERIFY( d1 > d2 );
-
- d1 = QDate(2001,12,6);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 > d2 );
+ QTest::addColumn<QDate>("left");
+ QTest::addColumn<QDate>("right");
+ QTest::addColumn<Qt::strong_ordering>("expectedOrdering");
+
+ QTest::newRow("2000-1-2_vs_2000-1-2")
+ << QDate(2000, 1, 2) << QDate(2000, 1, 2) << Qt::strong_ordering::equivalent;
+ QTest::newRow("2001-12-4_vs_2001-12-5")
+ << QDate(2001, 12, 4) << QDate(2001, 12, 5) << Qt::strong_ordering::less;
+ QTest::newRow("2001-11-5_vs_2001-12-5")
+ << QDate(2001, 11, 5) << QDate(2001, 12, 5) << Qt::strong_ordering::less;
+ QTest::newRow("2000-12-5_vs_2001-12-5")
+ << QDate(2000, 12, 5) << QDate(2001, 12, 5) << Qt::strong_ordering::less;
+ QTest::newRow("2002-12-5_vs_2001-12-5")
+ << QDate(2002, 12, 5) << QDate(2001, 12, 5) << Qt::strong_ordering::greater;
+ QTest::newRow("2001-12-5_vs_2001-11-5")
+ << QDate(2001, 12, 5) << QDate(2001, 11, 5) << Qt::strong_ordering::greater;
+ QTest::newRow("2001-12-6_vs_2001-12-5")
+ << QDate(2001, 12, 6) << QDate(2001, 12, 5) << Qt::strong_ordering::greater;
}
-void tst_QDate::operator_lt_eq()
+void tst_QDate::ordering()
{
- QDate d1(2000,1,2);
- QDate d2(2000,1,2);
- QVERIFY( d1 <= d2 );
-
- d1 = QDate(2001,12,4);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 <= d2 );
-
- d1 = QDate(2001,11,5);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 <= d2 );
+ QFETCH(QDate, left);
+ QFETCH(QDate, right);
+ QFETCH(Qt::strong_ordering, expectedOrdering);
- d1 = QDate(2000,12,5);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 <= d2 );
-
- d1 = QDate(2002,12,5);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 <= d2) );
-
- d1 = QDate(2001,12,5);
- d2 = QDate(2001,11,5);
- QVERIFY( !(d1 <= d2) );
-
- d1 = QDate(2001,12,6);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 <= d2) );
+ QT_TEST_ALL_COMPARISON_OPS(left, right, expectedOrdering);
}
-void tst_QDate::operator_gt_eq()
+void tst_QDate::ordering_chrono_types()
{
- QDate d1(2000,1,2);
- QDate d2(2000,1,2);
- QVERIFY( d1 >= d2 );
-
- d1 = QDate(2001,12,4);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 >= d2) );
-
- d1 = QDate(2001,11,5);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 >= d2) );
-
- d1 = QDate(2000,12,5);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 >= d2) );
-
- d1 = QDate(2002,12,5);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 >= d2 );
-
- d1 = QDate(2001,12,5);
- d2 = QDate(2001,11,5);
- QVERIFY( d1 >= d2 );
-
- d1 = QDate(2001,12,6);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 >= d2 );
+#if __cpp_lib_chrono >= 201907L
+ using namespace std::chrono;
+ QDate friday(2001, 11, 30); // the 5th Friday of November 2001
+ // std::chrono::year_month_day
+ QT_TEST_ALL_COMPARISON_OPS(friday, year_month_day(2001y, November, 29d),
+ Qt::strong_ordering::greater);
+ QT_TEST_ALL_COMPARISON_OPS(friday, year_month_day(2001y, November, 30d),
+ Qt::strong_ordering::equivalent);
+ QT_TEST_ALL_COMPARISON_OPS(friday, year_month_day(2001y, December, 1d),
+ Qt::strong_ordering::less);
+
+ // std::chrono::year_month_day_last
+ QT_TEST_ALL_COMPARISON_OPS(friday, year_month_day_last(2001y, {October / last}),
+ Qt::strong_ordering::greater);
+ QT_TEST_ALL_COMPARISON_OPS(friday, year_month_day_last(2001y, {November / last}),
+ Qt::strong_ordering::equivalent);
+ QT_TEST_ALL_COMPARISON_OPS(friday, year_month_day_last(2001y, {December / last}),
+ Qt::strong_ordering::less);
+
+ // std::chrono::year_month_weekday
+ QT_TEST_ALL_COMPARISON_OPS(friday, year_month_weekday(2001y, November, Thursday[5]),
+ Qt::strong_ordering::greater);
+ QT_TEST_ALL_COMPARISON_OPS(friday, year_month_weekday(2001y, November, Friday[5]),
+ Qt::strong_ordering::equivalent);
+ QT_TEST_ALL_COMPARISON_OPS(friday, year_month_weekday(2001y, December, Saturday[1]),
+ Qt::strong_ordering::less);
+
+ // std::chrono::year_month_weekday_last
+ QDate thursday(2001, 11, 29); // the last Thursday of November 2001
+ QT_TEST_ALL_COMPARISON_OPS(thursday, year_month_weekday_last(2001y, November, Wednesday[last]),
+ Qt::strong_ordering::greater);
+ QT_TEST_ALL_COMPARISON_OPS(thursday, year_month_weekday_last(2001y, November, Thursday[last]),
+ Qt::strong_ordering::equivalent);
+ QT_TEST_ALL_COMPARISON_OPS(thursday, year_month_weekday_last(2001y, November, Friday[last]),
+ Qt::strong_ordering::less);
+#else
+ QSKIP("This test requires C++20-level <chrono> support enabled in the standard library.");
+#endif // __cpp_lib_chrono >= 201907L
}
Q_DECLARE_METATYPE(QDataStream::Version)
@@ -1148,13 +1221,13 @@ void tst_QDate::fromStringDateFormat_data()
<< QString::fromLatin1(" 13 Feb 1987 13:24:51 +0100")
<< Qt::RFC2822Date << QDate(1987, 2, 13);
QTest::newRow("RFC 2822 with day") << QString::fromLatin1("Thu, 01 Jan 1970 00:12:34 +0000")
- << Qt::RFC2822Date << QDate(1970, 1, 1);
+ << Qt::RFC2822Date << epochDate();
QTest::newRow("RFC 2822 with day after space")
<< QString::fromLatin1(" Thu, 01 Jan 1970 00:12:34 +0000")
- << Qt::RFC2822Date << QDate(1970, 1, 1);
+ << Qt::RFC2822Date << epochDate();
// No timezone
QTest::newRow("RFC 2822 no timezone") << QString::fromLatin1("01 Jan 1970 00:12:34")
- << Qt::RFC2822Date << QDate(1970, 1, 1);
+ << Qt::RFC2822Date << epochDate();
// No time specified
QTest::newRow("RFC 2822 date only") << QString::fromLatin1("01 Nov 2002")
<< Qt::RFC2822Date << QDate(2002, 11, 1);
@@ -1193,7 +1266,7 @@ void tst_QDate::fromStringDateFormat_data()
<< Qt::RFC2822Date << QDate(1987, 2, 13);
// No timezone
QTest::newRow("RFC 850 and 1036 no timezone") << QString::fromLatin1("Thu Jan 01 00:12:34 1970")
- << Qt::RFC2822Date << QDate(1970, 1, 1);
+ << Qt::RFC2822Date << epochDate();
// No time specified
QTest::newRow("RFC 850 and 1036 date only") << QString::fromLatin1("Fri Nov 01 2002")
<< Qt::RFC2822Date << QDate(2002, 11, 1);
@@ -1234,152 +1307,172 @@ void tst_QDate::fromStringFormat_data()
{
QTest::addColumn<QString>("string");
QTest::addColumn<QString>("format");
+ QTest::addColumn<int>("baseYear");
QTest::addColumn<QDate>("expected");
- // Get names:
- const QString january = QStringLiteral("January");
- const QString february = QStringLiteral("February");
- const QString march = QStringLiteral("March");
- const QString august = QStringLiteral("August");
- const QString mon = QStringLiteral("Mon");
- const QString monday = QStringLiteral("Monday");
- const QString tuesday = QStringLiteral("Tuesday");
- const QString wednesday = QStringLiteral("Wednesday");
- const QString thursday = QStringLiteral("Thursday");
- const QString friday = QStringLiteral("Friday");
- const QString saturday = QStringLiteral("Saturday");
- const QString sunday = QStringLiteral("Sunday");
-
- QTest::newRow("data0") << QString("") << QString("") << defDate();
- QTest::newRow("data1") << QString(" ") << QString("") << invalidDate();
- QTest::newRow("data2") << QString(" ") << QString(" ") << defDate();
- QTest::newRow("data3") << QString("-%$%#") << QString("$*(#@") << invalidDate();
- QTest::newRow("data4") << QString("d") << QString("'d'") << defDate();
- QTest::newRow("data5") << QString("101010") << QString("dMyy") << QDate(1910, 10, 10);
- QTest::newRow("data6") << QString("101010b") << QString("dMyy") << invalidDate();
- QTest::newRow("data7") << january << QString("MMMM") << defDate();
- QTest::newRow("data8") << QString("ball") << QString("balle") << invalidDate();
- QTest::newRow("data9") << QString("balleh") << QString("balleh") << defDate();
- QTest::newRow("data10") << QString("10.01.1") << QString("M.dd.d") << QDate(defDate().year(), 10, 1);
- QTest::newRow("data11") << QString("-1.01.1") << QString("M.dd.d") << invalidDate();
- QTest::newRow("data12") << QString("11010") << QString("dMMyy") << invalidDate();
- QTest::newRow("data13") << QString("-2") << QString("d") << invalidDate();
- QTest::newRow("data14") << QString("132") << QString("Md") << invalidDate();
- QTest::newRow("data15") << february << QString("MMMM") << QDate(defDate().year(), 2, 1);
-
- QString date = mon + QLatin1Char(' ') + august + " 8 2005";
- QTest::newRow("data16") << date << QString("ddd MMMM d yyyy") << QDate(2005, 8, 8);
- QTest::newRow("data17") << QString("2000:00") << QString("yyyy:yy") << QDate(2000, 1, 1);
- QTest::newRow("data18") << QString("1999:99") << QString("yyyy:yy") << QDate(1999, 1, 1);
- QTest::newRow("data19") << QString("2099:99") << QString("yyyy:yy") << QDate(2099, 1, 1);
- QTest::newRow("data20") << QString("2001:01") << QString("yyyy:yy") << QDate(2001, 1, 1);
- QTest::newRow("data21") << QString("99") << QString("yy") << QDate(1999, 1, 1);
- QTest::newRow("data22") << QString("01") << QString("yy") << QDate(1901, 1, 1);
-
- QTest::newRow("data23") << monday << QString("dddd") << QDate(1900, 1, 1);
- QTest::newRow("data24") << tuesday << QString("dddd") << QDate(1900, 1, 2);
- QTest::newRow("data25") << wednesday << QString("dddd") << QDate(1900, 1, 3);
- QTest::newRow("data26") << thursday << QString("dddd") << QDate(1900, 1, 4);
- QTest::newRow("data27") << friday << QString("dddd") << QDate(1900, 1, 5);
- QTest::newRow("data28") << saturday << QString("dddd") << QDate(1900, 1, 6);
- QTest::newRow("data29") << sunday << QString("dddd") << QDate(1900, 1, 7);
-
- QTest::newRow("data30") << monday + " 2006" << QString("dddd yyyy") << QDate(2006, 1, 2);
- QTest::newRow("data31") << tuesday + " 2006" << QString("dddd yyyy") << QDate(2006, 1, 3);
- QTest::newRow("data32") << wednesday + " 2006" << QString("dddd yyyy") << QDate(2006, 1, 4);
- QTest::newRow("data33") << thursday + " 2006" << QString("dddd yyyy") << QDate(2006, 1, 5);
- QTest::newRow("data34") << friday + " 2006" << QString("dddd yyyy") << QDate(2006, 1, 6);
- QTest::newRow("data35") << saturday + " 2006" << QString("dddd yyyy") << QDate(2006, 1, 7);
- QTest::newRow("data36") << sunday + " 2006" << QString("dddd yyyy") << QDate(2006, 1, 1);
-
- QTest::newRow("data37") << tuesday + " 2007 " + march << QString("dddd yyyy MMMM") << QDate(2007, 3, 6);
-
- QTest::newRow("data38") << QString("21052006") << QString("ddMMyyyy") << QDate(2006,5,21);
- QTest::newRow("data39") << QString("210506") << QString("ddMMyy") << QDate(1906,5,21);
- QTest::newRow("data40") << QString("21/5/2006") << QString("d/M/yyyy") << QDate(2006,5,21);
- QTest::newRow("data41") << QString("21/5/06") << QString("d/M/yy") << QDate(1906,5,21);
- QTest::newRow("data42") << QString("20060521") << QString("yyyyMMdd") << QDate(2006,5,21);
- QTest::newRow("data43") << QString("060521") << QString("yyMMdd") << QDate(1906,5,21);
- QTest::newRow("lateMarch") << QString("9999-03-06") << QString("yyyy-MM-dd") << QDate(9999, 3, 6);
- QTest::newRow("late") << QString("9999-12-31") << QString("yyyy-MM-dd") << QDate(9999, 12, 31);
+ QTest::newRow("empty") << u""_s << u""_s << 1900 << defDate();
+ QTest::newRow("space-as-empty") << u" "_s << u""_s << 1900 << invalidDate();
+ QTest::newRow("space") << u" "_s << u" "_s << 1900 << defDate();
+ QTest::newRow("mispunc") << u"-%$%#"_s << u"$*(#@"_s << 1900 << invalidDate();
+ QTest::newRow("literal-d") << u"d"_s << u"'d'"_s << 1900 << defDate();
+ QTest::newRow("greedy") << u"101010"_s << u"dMyy"_s << 1900 << QDate(1910, 10, 10);
+ QTest::newRow("greedy-miss") << u"101010b"_s << u"dMyy"_s << 1900 << invalidDate();
+ QTest::newRow("January") << u"January"_s << u"MMMM"_s << 1900 << defDate();
+ QTest::newRow("mistext") << u"ball"_s << u"balle"_s << 1900 << invalidDate();
+ QTest::newRow("text") << u"balleh"_s << u"balleh"_s << 1900 << defDate();
+ QTest::newRow("yearless:19") << u"10.01.1"_s << u"M.dd.d"_s << 1900 << QDate(1900, 10, 1);
+ QTest::newRow("yearless:20") << u"10.01.1"_s << u"M.dd.d"_s << 2000 << QDate(2000, 10, 1);
+ QTest::newRow("neg-month") << u"-1.01.1"_s << u"M.dd.d"_s << 1900 << invalidDate();
+ QTest::newRow("greedy-break") << u"11010"_s << u"dMMyy"_s << 1900 << invalidDate();
+ QTest::newRow("neg-day") << u"-2"_s << u"d"_s << 1900 << invalidDate();
+ QTest::newRow("Md:132") << u"132"_s << u"Md"_s << 1900 << invalidDate();
+ QTest::newRow("February") << u"February"_s << u"MMMM"_s << 1900 << QDate(1900, 2, 1);
+
+ QTest::newRow("mon-aug-8th")
+ << u"Mon August 8 2005"_s << u"ddd MMMM d yyyy"_s << 1900 << QDate(2005, 8, 8);
+ QTest::newRow("year-match-20000") << u"2000:00"_s << u"yyyy:yy"_s << 1900 << QDate(2000, 1, 1);
+ QTest::newRow("year-match-1999") << u"1999:99"_s << u"yyyy:yy"_s << 1900 << QDate(1999, 1, 1);
+ QTest::newRow("year-match-2099") << u"2099:99"_s << u"yyyy:yy"_s << 1900 << QDate(2099, 1, 1);
+ QTest::newRow("year-match-2001") << u"2001:01"_s << u"yyyy:yy"_s << 1900 << QDate(2001, 1, 1);
+ QTest::newRow("just-yy-1999") << u"99"_s << u"yy"_s << 1900 << QDate(1999, 1, 1);
+ QTest::newRow("just-yy-1901") << u"01"_s << u"yy"_s << 1900 << QDate(1901, 1, 1);
+ QTest::newRow("just-yy-2001") << u"01"_s << u"yy"_s << 1970 << QDate(2001, 1, 1);
+
+ QTest::newRow("Monday") << u"Monday"_s << u"dddd"_s << 1900 << QDate(1900, 1, 1);
+ QTest::newRow("Tuesday") << u"Tuesday"_s << u"dddd"_s << 1900 << QDate(1900, 1, 2);
+ QTest::newRow("Wednesday") << u"Wednesday"_s << u"dddd"_s << 1900 << QDate(1900, 1, 3);
+ QTest::newRow("Thursday") << u"Thursday"_s << u"dddd"_s << 1900 << QDate(1900, 1, 4);
+ QTest::newRow("Friday") << u"Friday"_s << u"dddd"_s << 1900 << QDate(1900, 1, 5);
+ QTest::newRow("Saturday") << u"Saturday"_s << u"dddd"_s << 1900 << QDate(1900, 1, 6);
+ QTest::newRow("Sunday") << u"Sunday"_s << u"dddd"_s << 1900 << QDate(1900, 1, 7);
+
+ QTest::newRow("Mon06") << u"Monday 2006"_s << u"dddd yyyy"_s << 1900 << QDate(2006, 1, 2);
+ QTest::newRow("Tues06") << u"Tuesday 2006"_s << u"dddd yyyy"_s << 1900 << QDate(2006, 1, 3);
+ QTest::newRow("Wed06") << u"Wednesday 2006"_s << u"dddd yyyy"_s << 1900 << QDate(2006, 1, 4);
+ QTest::newRow("Thu06") << u"Thursday 2006"_s << u"dddd yyyy"_s << 1900 << QDate(2006, 1, 5);
+ QTest::newRow("Fri06") << u"Friday 2006"_s << u"dddd yyyy"_s << 1900 << QDate(2006, 1, 6);
+ QTest::newRow("Sat06") << u"Saturday 2006"_s << u"dddd yyyy"_s << 1900 << QDate(2006, 1, 7);
+ QTest::newRow("Sun06") << u"Sunday 2006"_s << u"dddd yyyy"_s << 1900 << QDate(2006, 1, 1);
+ QTest::newRow("Tue07Mar")
+ << u"Tuesday 2007 March"_s << u"dddd yyyy MMMM"_s << 1900 << QDate(2007, 3, 6);
+
+ QTest::newRow("21May2006")
+ << u"21052006"_s << u"ddMMyyyy"_s << 1900 << QDate(2006, 5, 21);
+ QTest::newRow("21May06:19")
+ << u"210506"_s << u"ddMMyy"_s << 1900 << QDate(1906, 5, 21);
+ QTest::newRow("21May06:20")
+ << u"210506"_s << u"ddMMyy"_s << 1970 << QDate(2006, 5, 21);
+ QTest::newRow("21/May/2006")
+ << u"21/5/2006"_s << u"d/M/yyyy"_s << 1900 << QDate(2006, 5, 21);
+ QTest::newRow("21/5/06")
+ << u"21/5/06"_s << u"d/M/yy"_s << 1900 << QDate(1906, 5, 21);
+ QTest::newRow("21/5/06:19")
+ << u"21/5/06"_s << u"d/M/yy"_s << 1900 << QDate(1906, 5, 21);
+ QTest::newRow("21/5/06:20")
+ << u"21/5/06"_s << u"d/M/yy"_s << 1910 << QDate(2006, 5, 21);
+ QTest::newRow("2006May21")
+ << u"20060521"_s << u"yyyyMMdd"_s << 1900 << QDate(2006, 5, 21);
+ QTest::newRow("06May21:19")
+ << u"060521"_s << u"yyMMdd"_s << 1900 << QDate(1906, 5, 21);
+ QTest::newRow("06May21:20")
+ << u"060521"_s << u"yyMMdd"_s << 1907 << QDate(2006, 5, 21);
+ QTest::newRow("lateMarch")
+ << u"9999-03-06"_s << u"yyyy-MM-dd"_s << 1900 << QDate(9999, 3, 6);
+ QTest::newRow("late")
+ << u"9999-12-31"_s << u"yyyy-MM-dd"_s << 1900 << QDate(9999, 12, 31);
+
+ QTest::newRow("quoted-dd")
+ << u"21dd-05-2006"_s << u"dd'dd'-MM-yyyy"_s << 1900 << QDate(2006, 5, 21);
+ QTest::newRow("quoted-MM")
+ << u"21-MM05-2006"_s << u"dd-'MM'MM-yyyy"_s << 1900 << QDate(2006, 5, 21);
+ QTest::newRow("quotes-empty")
+ << u"21-'05-2006"_s << u"dd-MM-''yy"_s << 1900 << QDate(2006, 5, 21);
// Test unicode handling.
QTest::newRow("Unicode in format string")
- << QString(u8"2020🤣09🤣21") << QString(u8"yyyy🤣MM🤣dd") << QDate(2020, 9, 21);
- QTest::newRow("Unicode in quoted format string")
- << QString(u8"🤣🤣2020👍09🤣21") << QString(u8"'🤣🤣'yyyy👍MM🤣dd") << QDate(2020, 9, 21);
+ << QString(u8"2020🤣09🤣21") << QString(u8"yyyy🤣MM🤣dd") << 1900 << QDate(2020, 9, 21);
+ QTest::newRow("Unicode-in-format-string-quoted-emoji")
+ << QString(u8"🤣🤣2020👍09🤣21") << QString(u8"'🤣🤣'yyyy👍MM🤣dd") << 1900
+ << QDate(2020, 9, 21);
+ QTest::newRow("Unicode-in-quoted-dd-format-string")
+ << QString(u8"🤣🤣2020👍09🤣21dd") << QString(u8"🤣🤣yyyy👍MM🤣dd'dd'") << 1900
+ << QDate(2020, 9, 21);
+ QTest::newRow("Unicode-in-all-formats-quoted-string")
+ << QString(u8"🤣🤣yyyy2020👍MM09🤣21dd") << QString(u8"🤣🤣'yyyy'yyyy👍'MM'MM🤣dd'dd'")
+ << 1900 << QDate(2020, 9, 21);
// QTBUG-84334
QTest::newRow("-ve year: front, nosep")
- << QString("-20060521") << QString("yyyyMMdd") << QDate(-2006, 5, 21);
+ << u"-20060521"_s << u"yyyyMMdd"_s << 1900 << QDate(-2006, 5, 21);
QTest::newRow("-ve year: mid, nosep")
- << QString("05-200621") << QString("MMyyyydd") << QDate(-2006, 5, 21);
+ << u"05-200621"_s << u"MMyyyydd"_s << 1900 << QDate(-2006, 5, 21);
QTest::newRow("-ve year: back, nosep")
- << QString("0521-2006") << QString("MMddyyyy") << QDate(-2006, 5, 21);
+ << u"0521-2006"_s << u"MMddyyyy"_s << 1900 << QDate(-2006, 5, 21);
// - as separator should not interfere with negative year numbers:
QTest::newRow("-ve year: front, dash")
- << QString("-2006-05-21") << QString("yyyy-MM-dd") << QDate(-2006, 5, 21);
+ << u"-2006-05-21"_s << u"yyyy-MM-dd"_s << 1900 << QDate(-2006, 5, 21);
QTest::newRow("positive year: front, dash")
- << QString("-2006-05-21") << QString("-yyyy-MM-dd") << QDate(2006, 5, 21);
+ << u"-2006-05-21"_s << u"-yyyy-MM-dd"_s << 1900 << QDate(2006, 5, 21);
QTest::newRow("-ve year: mid, dash")
- << QString("05--2006-21") << QString("MM-yyyy-dd") << QDate(-2006, 5, 21);
+ << u"05--2006-21"_s << u"MM-yyyy-dd"_s << 1900 << QDate(-2006, 5, 21);
QTest::newRow("-ve year: back, dash")
- << QString("05-21--2006") << QString("MM-dd-yyyy") << QDate(-2006, 5, 21);
+ << u"05-21--2006"_s << u"MM-dd-yyyy"_s << 1900 << QDate(-2006, 5, 21);
// negative three digit year numbers should be rejected:
QTest::newRow("-ve 3digit year: front")
- << QString("-206-05-21") << QString("yyyy-MM-dd") << QDate();
+ << u"-206-05-21"_s << u"yyyy-MM-dd"_s << 1900 << QDate();
QTest::newRow("-ve 3digit year: mid")
- << QString("05--206-21") << QString("MM-yyyy-dd") << QDate();
+ << u"05--206-21"_s << u"MM-yyyy-dd"_s << 1900 << QDate();
QTest::newRow("-ve 3digit year: back")
- << QString("05-21--206") << QString("MM-dd-yyyy") << QDate();
+ << u"05-21--206"_s << u"MM-dd-yyyy"_s << 1900 << QDate();
// negative month numbers should be rejected:
QTest::newRow("-ve 2digit month: mid")
- << QString("2060--05-21") << QString("yyyy-MM-dd") << QDate();
+ << u"2060--05-21"_s << u"yyyy-MM-dd"_s << 1900 << QDate();
QTest::newRow("-ve 2digit month: front")
- << QString("-05-2060-21") << QString("MM-yyyy-dd") << QDate();
+ << u"-05-2060-21"_s << u"MM-yyyy-dd"_s << 1900 << QDate();
QTest::newRow("-ve 2digit month: back")
- << QString("21-2060--05") << QString("dd-yyyy-MM") << QDate();
+ << u"21-2060--05"_s << u"dd-yyyy-MM"_s << 1900 << QDate();
// negative single digit month numbers should be rejected:
QTest::newRow("-ve 1digit month: mid")
- << QString("2060--5-21") << QString("yyyy-MM-dd") << QDate();
+ << u"2060--5-21"_s << u"yyyy-MM-dd"_s << 1900 << QDate();
QTest::newRow("-ve 1digit month: front")
- << QString("-5-2060-21") << QString("MM-yyyy-dd") << QDate();
+ << u"-5-2060-21"_s << u"MM-yyyy-dd"_s << 1900 << QDate();
QTest::newRow("-ve 1digit month: back")
- << QString("21-2060--5") << QString("dd-yyyy-MM") << QDate();
+ << u"21-2060--5"_s << u"dd-yyyy-MM"_s << 1900 << QDate();
// negative day numbers should be rejected:
QTest::newRow("-ve 2digit day: front")
- << QString("-21-2060-05") << QString("dd-yyyy-MM") << QDate();
+ << u"-21-2060-05"_s << u"dd-yyyy-MM"_s << 1900 << QDate();
QTest::newRow("-ve 2digit day: mid")
- << QString("2060--21-05") << QString("yyyy-dd-MM") << QDate();
+ << u"2060--21-05"_s << u"yyyy-dd-MM"_s << 1900 << QDate();
QTest::newRow("-ve 2digit day: back")
- << QString("05-2060--21") << QString("MM-yyyy-dd") << QDate();
+ << u"05-2060--21"_s << u"MM-yyyy-dd"_s << 1900 << QDate();
// negative single digit day numbers should be rejected:
QTest::newRow("-ve 1digit day: front")
- << QString("-2-2060-05") << QString("dd-yyyy-MM") << QDate();
+ << u"-2-2060-05"_s << u"dd-yyyy-MM"_s << 1900 << QDate();
QTest::newRow("-ve 1digit day: mid")
- << QString("05--2-2060") << QString("MM-dd-yyyy") << QDate();
+ << u"05--2-2060"_s << u"MM-dd-yyyy"_s << 1900 << QDate();
QTest::newRow("-ve 1digit day: back")
- << QString("2060-05--2") << QString("yyyy-MM-dd") << QDate();
+ << u"2060-05--2"_s << u"yyyy-MM-dd"_s << 1900 << QDate();
// positive three digit year numbers should be rejected:
- QTest::newRow("3digit year, front") << QString("206-05-21") << QString("yyyy-MM-dd") << QDate();
- QTest::newRow("3digit year, mid") << QString("05-206-21") << QString("MM-yyyy-dd") << QDate();
- QTest::newRow("3digit year, back") << QString("05-21-206") << QString("MM-dd-yyyy") << QDate();
+ QTest::newRow("3digit year, front") << u"206-05-21"_s << u"yyyy-MM-dd"_s << 1900 << QDate();
+ QTest::newRow("3digit year, mid") << u"05-206-21"_s << u"MM-yyyy-dd"_s << 1900 << QDate();
+ QTest::newRow("3digit year, back") << u"05-21-206"_s << u"MM-dd-yyyy"_s << 1900 << QDate();
// positive five digit year numbers should be rejected:
QTest::newRow("5digit year, front")
- << QString("00206-05-21") << QString("yyyy-MM-dd") << QDate();
- QTest::newRow("5digit year, mid") << QString("05-00206-21") << QString("MM-yyyy-dd") << QDate();
+ << u"00206-05-21"_s << u"yyyy-MM-dd"_s << 1900 << QDate();
+ QTest::newRow("5digit year, mid")
+ << u"05-00206-21"_s << u"MM-yyyy-dd"_s << 1900 << QDate();
QTest::newRow("5digit year, back")
- << QString("05-21-00206") << QString("MM-dd-yyyy") << QDate();
+ << u"05-21-00206"_s << u"MM-dd-yyyy"_s << 1900 << QDate();
QTest::newRow("dash separator, no year at end")
- << QString("05-21-") << QString("dd-MM-yyyy") << QDate();
+ << u"05-21-"_s << u"dd-MM-yyyy"_s << 1900 << QDate();
QTest::newRow("slash separator, no year at end")
- << QString("11/05/") << QString("d/MM/yyyy") << QDate();
+ << u"11/05/"_s << u"d/MM/yyyy"_s << 1900 << QDate();
// QTBUG-84349
- QTest::newRow("+ sign in year field") << QString("+0200322") << QString("yyyyMMdd") << QDate();
- QTest::newRow("+ sign in month field") << QString("2020+322") << QString("yyyyMMdd") << QDate();
- QTest::newRow("+ sign in day field") << QString("202003+1") << QString("yyyyMMdd") << QDate();
+ QTest::newRow("+ sign in year field") << u"+0200322"_s << u"yyyyMMdd"_s << 1900 << QDate();
+ QTest::newRow("+ sign in month field") << u"2020+322"_s << u"yyyyMMdd"_s << 1900 << QDate();
+ QTest::newRow("+ sign in day field") << u"202003+1"_s << u"yyyyMMdd"_s << 1900 << QDate();
}
@@ -1387,9 +1480,12 @@ void tst_QDate::fromStringFormat()
{
QFETCH(QString, string);
QFETCH(QString, format);
+ QFETCH(int, baseYear);
QFETCH(QDate, expected);
- QDate dt = QDate::fromString(string, format);
+ QDate dt = QDate::fromString(string, format, baseYear);
+ QEXPECT_FAIL("quotes-empty", "QTBUG-110669: doubled single-quotes in format mishandled",
+ Continue);
QCOMPARE(dt, expected);
}
#endif // datetimeparser
@@ -1602,9 +1698,6 @@ void tst_QDate::roundtrip() const
loopDate = loopDate.addDays(1);
}
- qint64 minJd = Q_INT64_C(-784350574879);
- qint64 maxJd = Q_INT64_C( 784354017364);
-
// Test Gregorian round trip at top end of conversion range
loopDate = QDate::fromJulianDay(maxJd);
while (loopDate.toJulianDay() >= maxJd - 146397) {
@@ -1620,6 +1713,38 @@ void tst_QDate::roundtrip() const
QCOMPARE(loopDate.toJulianDay(), testDate.toJulianDay());
loopDate = loopDate.addDays(1);
}
+
+#if __cpp_lib_chrono >= 201907L
+ // Test roundtrip for from/to std::chrono conversions.
+ // Compile-time test, to verify it's all constexpr.
+ using namespace std::chrono;
+ {
+ constexpr sys_days expected{days{minJd}};
+ constexpr sys_days actual{QDate::fromStdSysDays(expected).toStdSysDays()};
+ static_assert(actual == expected);
+ }
+ {
+ // constexpr year_month_day expected{sys_days{days{maxJd}}}; // Overflow at least on MSVC
+ constexpr year_month_day expected{1970y, January, 1d};
+ constexpr sys_days actual{QDate(expected).toStdSysDays()};
+ static_assert(actual == sys_days(expected));
+ }
+ {
+ constexpr year_month_day_last expected{2001y, {October / last}};
+ constexpr sys_days actual{QDate(expected).toStdSysDays()};
+ static_assert(actual == sys_days(expected));
+ }
+ {
+ constexpr year_month_weekday expected{2001y, December, Saturday[1]};
+ constexpr sys_days actual{QDate(expected).toStdSysDays()};
+ static_assert(actual == sys_days(expected));
+ }
+ {
+ constexpr year_month_weekday_last expected{2001y, November, Friday[last]};
+ constexpr sys_days actual{QDate(expected).toStdSysDays()};
+ static_assert(actual == sys_days(expected));
+ }
+#endif // __cpp_lib_chrono >= 201907L
}
void tst_QDate::qdebug() const
diff --git a/tests/auto/corelib/time/qdatetime/CMakeLists.txt b/tests/auto/corelib/time/qdatetime/CMakeLists.txt
index c5b8d2bb6e..499369c131 100644
--- a/tests/auto/corelib/time/qdatetime/CMakeLists.txt
+++ b/tests/auto/corelib/time/qdatetime/CMakeLists.txt
@@ -1,29 +1,33 @@
-# Generated from qdatetime.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdatetime Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qdatetime LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qdatetime
SOURCES
tst_qdatetime.cpp
DEFINES
QT_NO_FOREACH
QT_NO_KEYWORDS
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
+ Qt::TestPrivate
)
## Scopes:
#####################################################################
-#### Keys ignored in scope 2:.:.:qdatetime.pro:MSVC:
-# QMAKE_CFLAGS_RELEASE = "--O1"
-# QMAKE_CXXFLAGS_RELEASE = "--O1"
-
qt_internal_extend_target(tst_qdatetime CONDITION APPLE
SOURCES
tst_qdatetime_mac.mm
- PUBLIC_LIBRARIES
+ LIBRARIES
${FWFoundation}
)
diff --git a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp
index 844dead504..f9c6afc795 100644
--- a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp
+++ b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp
@@ -1,41 +1,28 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+#include <QDateTime>
#include <QTest>
-#include <time.h>
-#include <qdatetime.h>
+
+#include <QTimeZone>
#include <private/qdatetime_p.h>
+#include <private/qtenvironmentvariables_p.h> // for qTzSet(), qTzName()
+#include <private/qcomparisontesthelper_p.h>
#ifdef Q_OS_WIN
-# include <qt_windows.h>
+# include <qt_windows.h>
+# if !QT_CONFIG(icu)
+// The native MS back-end for time-zones lacks info about historic transitions:
+# define INADEQUATE_TZ_DATA
+# endif
+#endif
+#ifdef Q_OS_ANDROID // Also seems to lack full-day zone transitions:
+# define INADEQUATE_TZ_DATA
#endif
+using namespace Qt::StringLiterals;
+
class tst_QDateTime : public QObject
{
Q_OBJECT
@@ -48,11 +35,14 @@ public Q_SLOTS:
private Q_SLOTS:
void ctor();
void operator_eq();
+ void moveSemantics();
void isNull();
void isValid();
void date();
void time();
+#if QT_DEPRECATED_SINCE(6, 9)
void timeSpec();
+#endif
void toSecsSinceEpoch_data();
void toSecsSinceEpoch();
void daylightSavingsTimeChange_data();
@@ -62,13 +52,17 @@ private Q_SLOTS:
void setDate();
void setTime_data();
void setTime();
+ void setTimeZone_data();
+ void setTimeZone();
+#if QT_DEPRECATED_SINCE(6, 9)
void setTimeSpec_data();
void setTimeSpec();
+#endif
void setSecsSinceEpoch();
void setMSecsSinceEpoch_data();
void setMSecsSinceEpoch();
void fromSecsSinceEpoch();
- void fromMSecsSinceEpoch_data();
+ void fromMSecsSinceEpoch_data() { setMSecsSinceEpoch_data(); }
void fromMSecsSinceEpoch();
#if QT_CONFIG(datestring)
void toString_isoDate_data();
@@ -92,20 +86,25 @@ private Q_SLOTS:
void addSecs();
void addMSecs_data();
void addMSecs();
+#if QT_DEPRECATED_SINCE(6, 9)
void toTimeSpec_data();
void toTimeSpec();
- void toLocalTime_data();
+ void toLocalTime_data() { toTimeSpec_data(); }
void toLocalTime();
- void toUTC_data();
+ void toUTC_data() { toTimeSpec_data(); }
void toUTC();
void toUTC_extra();
+#endif
void daysTo();
void secsTo_data();
void secsTo();
- void msecsTo_data();
+ void msecsTo_data() { addMSecs_data(); }
void msecsTo();
+ void orderingCompiles();
void operator_eqeq_data();
void operator_eqeq();
+ void ordering_data();
+ void ordering();
void operator_insert_extract_data();
void operator_insert_extract();
void currentDateTime();
@@ -123,8 +122,10 @@ private Q_SLOTS:
#endif
void offsetFromUtc();
+#if QT_DEPRECATED_SINCE(6, 9)
void setOffsetFromUtc();
void toOffsetFromUtc();
+#endif
void zoneAtTime_data();
void zoneAtTime();
@@ -151,11 +152,44 @@ private Q_SLOTS:
void macTypes();
+ void stdCompatibilitySysTime_data();
+ void stdCompatibilitySysTime();
+ void stdCompatibilityLocalTime_data();
+ void stdCompatibilityLocalTime();
+#if QT_CONFIG(timezone)
+ void stdCompatibilityZonedTime_data();
+ void stdCompatibilityZonedTime();
+#endif
+
private:
- enum { LocalTimeIsUtc = 0, LocalTimeAheadOfUtc = 1, LocalTimeBehindUtc = -1} localTimeType;
+ /*
+ Various zones close to UTC (notably Iceland, the WET zones and several in
+ West Africa) or nominally assigned to it historically (north Canada, the
+ Antarctic) and those that have crossed the international date-line (by
+ skipping or repeating a day) don't have a consistent answer to "which side
+ of UTC is it ?" So the various LocalTimeType members may be different.
+ */
+ enum LocalTimeType { LocalTimeIsUtc = 0, LocalTimeAheadOfUtc = 1, LocalTimeBehindUtc = -1};
+ const LocalTimeType solarMeanType, epochTimeType, futureTimeType, distantTimeType;
+ static constexpr auto UTC = QTimeZone::UTC;
+ static constexpr qint64 epochJd = Q_INT64_C(2440588);
int preZoneFix;
bool zoneIsCET;
+ static LocalTimeType timeTypeFor(qint64 jand, qint64 juld)
+ {
+ constexpr uint day = 24 * 3600; // in seconds
+ QDateTime jan = QDateTime::fromSecsSinceEpoch(jand * day);
+ QDateTime jul = QDateTime::fromSecsSinceEpoch(juld * day);
+ if (jan.date().toJulianDay() < jand + epochJd || jul.date().toJulianDay() < juld + epochJd)
+ return LocalTimeBehindUtc;
+ if (jan.date().toJulianDay() > jand + epochJd || jul.date().toJulianDay() > juld + epochJd
+ || jan.time().hour() > 0 || jul.time().hour() > 0) {
+ return LocalTimeAheadOfUtc;
+ }
+ return LocalTimeIsUtc;
+ }
+
class TimeZoneRollback
{
const QByteArray prior;
@@ -166,7 +200,7 @@ private:
{ reset(zone); }
void reset(const QByteArray &zone)
{
- qputenv("TZ", zone.constData());
+ qputenv("TZ", zone);
qTzSet();
}
~TimeZoneRollback()
@@ -174,7 +208,7 @@ private:
if (prior.isNull())
qunsetenv("TZ");
else
- qputenv("TZ", prior.constData());
+ qputenv("TZ", prior);
qTzSet();
}
};
@@ -183,7 +217,18 @@ private:
Q_DECLARE_METATYPE(Qt::TimeSpec)
Q_DECLARE_METATYPE(Qt::DateFormat)
-tst_QDateTime::tst_QDateTime()
+tst_QDateTime::tst_QDateTime() :
+ // UTC starts of January and July in the commented years:
+ solarMeanType(timeTypeFor(-62091, -61910)), // 1800
+ epochTimeType(timeTypeFor(0, 181)), // 1970
+ // Use stable future, to which current rule is extrapolated, as surrogate for variable current:
+ futureTimeType(timeTypeFor(24837, 25018)), // 2038
+ // The glibc functions only handle DST as far as a 32-bit signed day-count
+ // from some date in 1970 reaches; the future extreme of that is in the
+ // second half of 5'881'580 CE. Beyond 5'881'581 CE it treats all zones as
+ // being in their January state, regardless of time of year. So use data for
+ // this later year for tests of QDateTime's upper bound.
+ distantTimeType(timeTypeFor(0x800000adLL, 0x80000162LL))
{
/*
Due to some jurisdictions changing their zones and rules, it's possible
@@ -197,7 +242,6 @@ tst_QDateTime::tst_QDateTime()
might not be properly handled by our work-arounds for the MS backend and
32-bit time_t; so don't probe them here.
*/
- const uint day = 24 * 3600; // in seconds
zoneIsCET = (QDateTime(QDate(2038, 1, 19), QTime(4, 14, 7)).toSecsSinceEpoch() == 0x7fffffff
// Entries a year apart robustly differ by multiples of day.
&& QDate(2015, 7, 1).startOfDay().toSecsSinceEpoch() == 1435701600
@@ -227,31 +271,6 @@ tst_QDateTime::tst_QDateTime()
Q_ASSERT(preZoneFix > -7200 && preZoneFix < 7200);
// So it's OK to add it to a QTime() between 02:00 and 22:00, but otherwise
// we must add it to the QDateTime constructed from it.
-
- /*
- Again, rule changes can cause a TZ to look like UTC at some sample dates
- but deviate at some date relevant to a test using localTimeType. These
- tests mostly use years outside the 1970--2037 range, for which we trust
- our TZ data, so we can't helpfully be exhaustive. Instead, scan a sample
- of years' starts and middles.
- */
- const int sampled = 3;
- // UTC starts of months in 2004, 2038 and 1970:
- qint64 jans[sampled] = { 12418 * day, 24837 * day, 0 };
- qint64 juls[sampled] = { 12600 * day, 25018 * day, 181 * day };
- localTimeType = LocalTimeIsUtc;
- for (int i = sampled; i-- > 0; ) {
- QDateTime jan = QDateTime::fromSecsSinceEpoch(jans[i]);
- QDateTime jul = QDateTime::fromSecsSinceEpoch(juls[i]);
- if (jan.date().year() < 1970 || jul.date().month() < 7) {
- localTimeType = LocalTimeBehindUtc;
- break;
- } else if (jan.time().hour() > 0 || jul.time().hour() > 0
- || jan.date().day() > 1 || jul.date().day() > 1) {
- localTimeType = LocalTimeAheadOfUtc;
- break;
- }
- }
}
void tst_QDateTime::initTestCase()
@@ -259,7 +278,7 @@ void tst_QDateTime::initTestCase()
// Never construct a message like this in an i18n context...
const char *typemsg1 = "exactly";
const char *typemsg2 = "and therefore not";
- switch (localTimeType) {
+ switch (futureTimeType) {
case LocalTimeIsUtc:
break;
case LocalTimeBehindUtc:
@@ -282,9 +301,9 @@ void tst_QDateTime::ctor()
{
QDateTime dt1(QDate(2004, 1, 2), QTime(1, 2, 3));
QCOMPARE(dt1.timeSpec(), Qt::LocalTime);
- QDateTime dt2(QDate(2004, 1, 2), QTime(1, 2, 3), Qt::LocalTime);
+ QDateTime dt2(QDate(2004, 1, 2), QTime(1, 2, 3));
QCOMPARE(dt2.timeSpec(), Qt::LocalTime);
- QDateTime dt3(QDate(2004, 1, 2), QTime(1, 2, 3), Qt::UTC);
+ QDateTime dt3(QDate(2004, 1, 2), QTime(1, 2, 3), UTC);
QCOMPARE(dt3.timeSpec(), Qt::UTC);
QVERIFY(dt1 == dt2);
@@ -298,25 +317,26 @@ void tst_QDateTime::ctor()
QDate offsetDate(2013, 1, 1);
QTime offsetTime(1, 2, 3);
- QDateTime offset1(offsetDate, offsetTime, Qt::OffsetFromUTC);
+ QDateTime offset1(offsetDate, offsetTime, QTimeZone::fromSecondsAheadOfUtc(0));
QCOMPARE(offset1.timeSpec(), Qt::UTC);
QCOMPARE(offset1.offsetFromUtc(), 0);
QCOMPARE(offset1.date(), offsetDate);
QCOMPARE(offset1.time(), offsetTime);
- QDateTime offset2(offsetDate, offsetTime, Qt::OffsetFromUTC, 0);
+ QDateTime offset2(offsetDate, offsetTime,
+ QTimeZone::fromDurationAheadOfUtc(std::chrono::seconds{}));
QCOMPARE(offset2.timeSpec(), Qt::UTC);
QCOMPARE(offset2.offsetFromUtc(), 0);
QCOMPARE(offset2.date(), offsetDate);
QCOMPARE(offset2.time(), offsetTime);
- QDateTime offset3(offsetDate, offsetTime, Qt::OffsetFromUTC, 60 * 60);
+ QDateTime offset3(offsetDate, offsetTime, QTimeZone::fromSecondsAheadOfUtc(60 * 60));
QCOMPARE(offset3.timeSpec(), Qt::OffsetFromUTC);
QCOMPARE(offset3.offsetFromUtc(), 60 * 60);
QCOMPARE(offset3.date(), offsetDate);
QCOMPARE(offset3.time(), offsetTime);
- QDateTime offset4(offsetDate, QTime(0, 0), Qt::OffsetFromUTC, 60 * 60);
+ QDateTime offset4(offsetDate, QTime(0, 0), QTimeZone::fromSecondsAheadOfUtc(60 * 60));
QCOMPARE(offset4.timeSpec(), Qt::OffsetFromUTC);
QCOMPARE(offset4.offsetFromUtc(), 60 * 60);
QCOMPARE(offset4.date(), offsetDate);
@@ -325,13 +345,25 @@ void tst_QDateTime::ctor()
void tst_QDateTime::operator_eq()
{
- QVERIFY(QDateTime() != QDateTime(QDate(1970, 1, 1), QTime(0, 0))); // QTBUG-79006
- QDateTime dt1(QDate(2004, 3, 24), QTime(23, 45, 57), Qt::UTC);
- QDateTime dt2(QDate(2005, 3, 11), QTime(0, 0), Qt::UTC);
+ QVERIFY(QDateTime() != QDate(1970, 1, 1).startOfDay()); // QTBUG-79006
+ QDateTime dt1(QDate(2004, 3, 24), QTime(23, 45, 57), UTC);
+ QDateTime dt2(QDate(2005, 3, 11), QTime(0, 0), UTC);
dt2 = dt1;
QVERIFY(dt1 == dt2);
}
+void tst_QDateTime::moveSemantics()
+{
+ QDateTime dt1{QDate{2004, 3, 24}, QTime{23, 45, 57}, UTC};
+ QDateTime dt2{QDate{2005, 3, 11}, QTime{0, 0}, UTC};
+ QDateTime copy = dt1;
+ QDateTime moved = std::move(dt1);
+ QCOMPARE(copy, moved);
+ copy = dt2;
+ moved = std::move(dt2);
+ QCOMPARE(copy, moved);
+}
+
void tst_QDateTime::isNull()
{
QDateTime dt1;
@@ -340,15 +372,27 @@ void tst_QDateTime::isNull()
QVERIFY(dt1.isNull());
dt1.setTime(QTime());
QVERIFY(dt1.isNull());
- dt1.setTimeSpec(Qt::UTC);
- QVERIFY(dt1.isNull()); // maybe it should return false?
+ dt1.setTimeZone(UTC);
+ QVERIFY(dt1.isNull());
+ dt1.setTime(QTime(12, 34, 56));
+ QVERIFY(!dt1.isNull());
+ dt1.setTime(QTime()); // Date still invalid, so this really clears time.
+ QVERIFY(dt1.isNull());
dt1.setDate(QDate(2004, 1, 2));
QVERIFY(!dt1.isNull());
dt1.setTime(QTime(12, 34, 56));
QVERIFY(!dt1.isNull());
- dt1.setTime(QTime());
+ dt1.setTime(QTime()); // Actually sets time to QTime(0, 0), as date is still valid.
+ QVERIFY(!dt1.isNull());
+ dt1.setDate(QDate()); // Time remains valid
QVERIFY(!dt1.isNull());
+ dt1.setTime(QTime()); // Now really sets time invalid, too
+ QVERIFY(dt1.isNull());
+
+ // Either date or time non-null => date-time isn't null:
+ QVERIFY(!QDateTime(QDate(), QTime(0, 0)).isNull());
+ QVERIFY(!QDateTime(QDate(2022, 2, 16), QTime()).isNull());
}
void tst_QDateTime::isValid()
@@ -359,49 +403,61 @@ void tst_QDateTime::isValid()
QVERIFY(!dt1.isValid());
dt1.setTime(QTime());
QVERIFY(!dt1.isValid());
- dt1.setTimeSpec(Qt::UTC);
+ dt1.setTimeZone(UTC);
QVERIFY(!dt1.isValid());
dt1.setDate(QDate(2004, 1, 2));
QVERIFY(dt1.isValid());
+ dt1.setTime(QTime()); // Effectively QTime(0, 0)
+ QVERIFY(dt1.isValid());
dt1.setDate(QDate());
QVERIFY(!dt1.isValid());
dt1.setTime(QTime(12, 34, 56));
QVERIFY(!dt1.isValid());
- dt1.setTime(QTime());
+ dt1.setTime(QTime()); // Does sets time invalid, as date is invalid
QVERIFY(!dt1.isValid());
+ dt1.setDate(QDate(2004, 1, 2)); // Kicks time back to QTime(0, 0)
+ QVERIFY(dt1.isValid());
+
+ // Invalid date => invalid date-time:
+ QVERIFY(!QDateTime(QDate(), QTime(0, 0)).isValid());
+ // Invalid time gets replaced with QTime(0, 0) when date is valid:
+ QVERIFY(QDateTime(QDate(2022, 2, 16), QTime()).isValid());
}
void tst_QDateTime::date()
{
- QDateTime dt1(QDate(2004, 3, 24), QTime(23, 45, 57), Qt::LocalTime);
+ QDateTime dt1(QDate(2004, 3, 24), QTime(23, 45, 57));
QCOMPARE(dt1.date(), QDate(2004, 3, 24));
- QDateTime dt2(QDate(2004, 3, 25), QTime(0, 45, 57), Qt::LocalTime);
+ QDateTime dt2(QDate(2004, 3, 25), QTime(0, 45, 57));
QCOMPARE(dt2.date(), QDate(2004, 3, 25));
- QDateTime dt3(QDate(2004, 3, 24), QTime(23, 45, 57), Qt::UTC);
+ QDateTime dt3(QDate(2004, 3, 24), QTime(23, 45, 57), UTC);
QCOMPARE(dt3.date(), QDate(2004, 3, 24));
- QDateTime dt4(QDate(2004, 3, 25), QTime(0, 45, 57), Qt::UTC);
+ QDateTime dt4(QDate(2004, 3, 25), QTime(0, 45, 57), UTC);
QCOMPARE(dt4.date(), QDate(2004, 3, 25));
}
void tst_QDateTime::time()
{
- QDateTime dt1(QDate(2004, 3, 24), QTime(23, 45, 57), Qt::LocalTime);
+ QDateTime dt1(QDate(2004, 3, 24), QTime(23, 45, 57));
QCOMPARE(dt1.time(), QTime(23, 45, 57));
- QDateTime dt2(QDate(2004, 3, 25), QTime(0, 45, 57), Qt::LocalTime);
+ QDateTime dt2(QDate(2004, 3, 25), QTime(0, 45, 57));
QCOMPARE(dt2.time(), QTime(0, 45, 57));
- QDateTime dt3(QDate(2004, 3, 24), QTime(23, 45, 57), Qt::UTC);
+ QDateTime dt3(QDate(2004, 3, 24), QTime(23, 45, 57), UTC);
QCOMPARE(dt3.time(), QTime(23, 45, 57));
- QDateTime dt4(QDate(2004, 3, 25), QTime(0, 45, 57), Qt::UTC);
+ QDateTime dt4(QDate(2004, 3, 25), QTime(0, 45, 57), UTC);
QCOMPARE(dt4.time(), QTime(0, 45, 57));
}
+#if QT_DEPRECATED_SINCE(6, 9)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
void tst_QDateTime::timeSpec()
{
QDateTime dt1(QDate(2004, 1, 24), QTime(23, 45, 57));
@@ -415,49 +471,51 @@ void tst_QDateTime::timeSpec()
QCOMPARE(dt1.toTimeSpec(Qt::LocalTime).timeSpec(), Qt::LocalTime);
QCOMPARE(dt1.toTimeSpec(Qt::UTC).timeSpec(), Qt::UTC);
- QDateTime dt2(QDate(2004, 1, 24), QTime(23, 45, 57), Qt::LocalTime);
+ QDateTime dt2(QDate(2004, 1, 24), QTime(23, 45, 57));
QCOMPARE(dt2.timeSpec(), Qt::LocalTime);
- QDateTime dt3(QDate(2004, 1, 25), QTime(0, 45, 57), Qt::UTC);
+ QDateTime dt3(QDate(2004, 1, 25), QTime(0, 45, 57), UTC);
QCOMPARE(dt3.timeSpec(), Qt::UTC);
QDateTime dt4 = QDateTime::currentDateTime();
QCOMPARE(dt4.timeSpec(), Qt::LocalTime);
}
+QT_WARNING_POP
+#endif
void tst_QDateTime::setDate()
{
- QDateTime dt1(QDate(2004, 3, 25), QTime(0, 45, 57), Qt::UTC);
+ QDateTime dt1(QDate(2004, 3, 25), QTime(0, 45, 57), UTC);
dt1.setDate(QDate(2004, 6, 25));
QCOMPARE(dt1.date(), QDate(2004, 6, 25));
QCOMPARE(dt1.time(), QTime(0, 45, 57));
QCOMPARE(dt1.timeSpec(), Qt::UTC);
- QDateTime dt2(QDate(2004, 3, 25), QTime(0, 45, 57), Qt::LocalTime);
+ QDateTime dt2(QDate(2004, 3, 25), QTime(0, 45, 57));
dt2.setDate(QDate(2004, 6, 25));
QCOMPARE(dt2.date(), QDate(2004, 6, 25));
QCOMPARE(dt2.time(), QTime(0, 45, 57));
QCOMPARE(dt2.timeSpec(), Qt::LocalTime);
- QDateTime dt3(QDate(4004, 3, 25), QTime(0, 45, 57), Qt::UTC);
+ QDateTime dt3(QDate(4004, 3, 25), QTime(0, 45, 57), UTC);
dt3.setDate(QDate(4004, 6, 25));
QCOMPARE(dt3.date(), QDate(4004, 6, 25));
QCOMPARE(dt3.time(), QTime(0, 45, 57));
QCOMPARE(dt3.timeSpec(), Qt::UTC);
- QDateTime dt4(QDate(4004, 3, 25), QTime(0, 45, 57), Qt::LocalTime);
+ QDateTime dt4(QDate(4004, 3, 25), QTime(0, 45, 57));
dt4.setDate(QDate(4004, 6, 25));
QCOMPARE(dt4.date(), QDate(4004, 6, 25));
QCOMPARE(dt4.time(), QTime(0, 45, 57));
QCOMPARE(dt4.timeSpec(), Qt::LocalTime);
- QDateTime dt5(QDate(1760, 3, 25), QTime(0, 45, 57), Qt::UTC);
+ QDateTime dt5(QDate(1760, 3, 25), QTime(0, 45, 57), UTC);
dt5.setDate(QDate(1760, 6, 25));
QCOMPARE(dt5.date(), QDate(1760, 6, 25));
QCOMPARE(dt5.time(), QTime(0, 45, 57));
QCOMPARE(dt5.timeSpec(), Qt::UTC);
- QDateTime dt6(QDate(1760, 3, 25), QTime(0, 45, 57), Qt::LocalTime);
+ QDateTime dt6(QDate(1760, 3, 25), QTime(0, 45, 57));
dt6.setDate(QDate(1760, 6, 25));
QCOMPARE(dt6.date(), QDate(1760, 6, 25));
QCOMPARE(dt6.time(), QTime(0, 45, 57));
@@ -469,12 +527,18 @@ void tst_QDateTime::setTime_data()
QTest::addColumn<QDateTime>("dateTime");
QTest::addColumn<QTime>("newTime");
- QTest::newRow("data0") << QDateTime(QDate(2004, 3, 25), QTime(0, 45, 57), Qt::UTC) << QTime(23, 11, 22);
- QTest::newRow("data1") << QDateTime(QDate(2004, 3, 25), QTime(0, 45, 57), Qt::LocalTime) << QTime(23, 11, 22);
- QTest::newRow("data2") << QDateTime(QDate(4004, 3, 25), QTime(0, 45, 57), Qt::UTC) << QTime(23, 11, 22);
- QTest::newRow("data3") << QDateTime(QDate(4004, 3, 25), QTime(0, 45, 57), Qt::LocalTime) << QTime(23, 11, 22);
- QTest::newRow("data4") << QDateTime(QDate(1760, 3, 25), QTime(0, 45, 57), Qt::UTC) << QTime(23, 11, 22);
- QTest::newRow("data5") << QDateTime(QDate(1760, 3, 25), QTime(0, 45, 57), Qt::LocalTime) << QTime(23, 11, 22);
+ QTest::newRow("data0")
+ << QDateTime(QDate(2004, 3, 25), QTime(0, 45, 57), UTC) << QTime(23, 11, 22);
+ QTest::newRow("data1")
+ << QDateTime(QDate(2004, 3, 25), QTime(0, 45, 57)) << QTime(23, 11, 22);
+ QTest::newRow("data2")
+ << QDateTime(QDate(4004, 3, 25), QTime(0, 45, 57), UTC) << QTime(23, 11, 22);
+ QTest::newRow("data3")
+ << QDateTime(QDate(4004, 3, 25), QTime(0, 45, 57)) << QTime(23, 11, 22);
+ QTest::newRow("data4")
+ << QDateTime(QDate(1760, 3, 25), QTime(0, 45, 57), UTC) << QTime(23, 11, 22);
+ QTest::newRow("data5")
+ << QDateTime(QDate(1760, 3, 25), QTime(0, 45, 57)) << QTime(23, 11, 22);
QTest::newRow("set on std/dst") << QDateTime::currentDateTime() << QTime(23, 11, 22);
}
@@ -494,16 +558,73 @@ void tst_QDateTime::setTime()
QCOMPARE(dateTime.timeSpec(), expectedTimeSpec);
}
+void tst_QDateTime::setTimeZone_data()
+{
+ QTest::addColumn<QDateTime>("dateTime");
+ QTest::addColumn<QTimeZone>("zone");
+ const QDate day(2004, 3, 25);
+ const QTime time(0, 45, 57);
+ struct {
+ const char *id;
+ QTimeZone zone;
+ } data[] = {
+ { nullptr, QTimeZone() }, // For time-zone, when supported.
+ { "UTC", UTC },
+ { "LocalTime", QTimeZone() },
+ { "Offset", QTimeZone::fromSecondsAheadOfUtc(3600) }
+ };
+#if QT_CONFIG(timezone)
+ const QTimeZone cet("Europe/Oslo");
+ if (cet.isValid()) {
+ data[0].zone = cet;
+ data[0].id = "Zone";
+ }
+#endif
+ for (const auto &from : data) {
+ if (from.id) {
+ for (const auto &to : data) {
+ if (to.id) {
+ QTest::addRow("%s => %s", from.id, to.id)
+ << QDateTime(day, time, from.zone) << to.zone;
+ }
+ }
+ }
+ }
+}
+
+void tst_QDateTime::setTimeZone()
+{
+ QFETCH(QDateTime, dateTime);
+ QFETCH(QTimeZone, zone);
+
+ // QDateTime::setTimeZone() preserves the date and time rather than
+ // converting to the new time representation.
+ const QDate expectedDate(dateTime.date());
+ const QTime expectedTime(dateTime.time());
+
+ dateTime.setTimeZone(zone);
+
+ QCOMPARE(dateTime.date(), expectedDate);
+ QCOMPARE(dateTime.time(), expectedTime);
+ QCOMPARE(dateTime.timeRepresentation(), zone);
+}
+
+#if QT_DEPRECATED_SINCE(6, 9)
void tst_QDateTime::setTimeSpec_data()
{
QTest::addColumn<QDateTime>("dateTime");
QTest::addColumn<Qt::TimeSpec>("newTimeSpec");
- QTest::newRow("UTC => UTC") << QDateTime(QDate(2004, 3, 25), QTime(0, 45, 57), Qt::UTC) << Qt::UTC;
- QTest::newRow("UTC => LocalTime") << QDateTime(QDate(2004, 3, 25), QTime(0, 45, 57), Qt::UTC) << Qt::LocalTime;
- QTest::newRow("UTC => OffsetFromUTC") << QDateTime(QDate(2004, 3, 25), QTime(0, 45, 57), Qt::UTC) << Qt::OffsetFromUTC;
+ QTest::newRow("UTC => UTC")
+ << QDateTime(QDate(2004, 3, 25), QTime(0, 45, 57), UTC) << Qt::UTC;
+ QTest::newRow("UTC => LocalTime")
+ << QDateTime(QDate(2004, 3, 25), QTime(0, 45, 57), UTC) << Qt::LocalTime;
+ QTest::newRow("UTC => OffsetFromUTC")
+ << QDateTime(QDate(2004, 3, 25), QTime(0, 45, 57), UTC) << Qt::OffsetFromUTC;
}
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
void tst_QDateTime::setTimeSpec()
{
QFETCH(QDateTime, dateTime);
@@ -521,59 +642,61 @@ void tst_QDateTime::setTimeSpec()
else
QCOMPARE(dateTime.timeSpec(), newTimeSpec);
}
+QT_WARNING_POP
+#endif
void tst_QDateTime::setSecsSinceEpoch()
{
QDateTime dt1;
dt1.setSecsSinceEpoch(0);
- QCOMPARE(dt1.toUTC(), QDate(1970, 1, 1).startOfDay(Qt::UTC));
+ QCOMPARE(dt1.toUTC(), QDate(1970, 1, 1).startOfDay(UTC));
QCOMPARE(dt1.timeSpec(), Qt::LocalTime);
- dt1.setTimeSpec(Qt::UTC);
+ dt1.setTimeZone(UTC);
dt1.setSecsSinceEpoch(0);
- QCOMPARE(dt1, QDate(1970, 1, 1).startOfDay(Qt::UTC));
+ QCOMPARE(dt1, QDate(1970, 1, 1).startOfDay(UTC));
QCOMPARE(dt1.timeSpec(), Qt::UTC);
dt1.setSecsSinceEpoch(123456);
- QCOMPARE(dt1, QDateTime(QDate(1970, 1, 2), QTime(10, 17, 36), Qt::UTC));
+ QCOMPARE(dt1, QDateTime(QDate(1970, 1, 2), QTime(10, 17, 36), UTC));
if (zoneIsCET) {
QDateTime dt2;
dt2.setSecsSinceEpoch(123456);
- QCOMPARE(dt2, QDateTime(QDate(1970, 1, 2), QTime(11, 17, 36), Qt::LocalTime));
+ QCOMPARE(dt2, QDateTime(QDate(1970, 1, 2), QTime(11, 17, 36)));
}
dt1.setSecsSinceEpoch((uint)(quint32)-123456);
- QCOMPARE(dt1, QDateTime(QDate(2106, 2, 5), QTime(20, 10, 40), Qt::UTC));
+ QCOMPARE(dt1, QDateTime(QDate(2106, 2, 5), QTime(20, 10, 40), UTC));
if (zoneIsCET) {
QDateTime dt2;
dt2.setSecsSinceEpoch((uint)(quint32)-123456);
- QCOMPARE(dt2, QDateTime(QDate(2106, 2, 5), QTime(21, 10, 40), Qt::LocalTime));
+ QCOMPARE(dt2, QDateTime(QDate(2106, 2, 5), QTime(21, 10, 40)));
}
dt1.setSecsSinceEpoch(1214567890);
- QCOMPARE(dt1, QDateTime(QDate(2008, 6, 27), QTime(11, 58, 10), Qt::UTC));
+ QCOMPARE(dt1, QDateTime(QDate(2008, 6, 27), QTime(11, 58, 10), UTC));
if (zoneIsCET) {
QDateTime dt2;
dt2.setSecsSinceEpoch(1214567890);
- QCOMPARE(dt2, QDateTime(QDate(2008, 6, 27), QTime(13, 58, 10), Qt::LocalTime));
+ QCOMPARE(dt2, QDateTime(QDate(2008, 6, 27), QTime(13, 58, 10)));
}
dt1.setSecsSinceEpoch(0x7FFFFFFF);
- QCOMPARE(dt1, QDateTime(QDate(2038, 1, 19), QTime(3, 14, 7), Qt::UTC));
+ QCOMPARE(dt1, QDateTime(QDate(2038, 1, 19), QTime(3, 14, 7), UTC));
if (zoneIsCET) {
QDateTime dt2;
dt2.setSecsSinceEpoch(0x7FFFFFFF);
- QCOMPARE(dt2, QDateTime(QDate(2038, 1, 19), QTime(4, 14, 7), Qt::LocalTime));
+ QCOMPARE(dt2, QDateTime(QDate(2038, 1, 19), QTime(4, 14, 7)));
}
- dt1 = QDateTime(QDate(2013, 1, 1), QTime(0, 0), Qt::OffsetFromUTC, 60 * 60);
+ dt1 = QDateTime(QDate(2013, 1, 1), QTime(0, 0), QTimeZone::fromSecondsAheadOfUtc(60 * 60));
dt1.setSecsSinceEpoch(123456);
- QCOMPARE(dt1, QDateTime(QDate(1970, 1, 2), QTime(10, 17, 36), Qt::UTC));
+ QCOMPARE(dt1, QDateTime(QDate(1970, 1, 2), QTime(10, 17, 36), UTC));
QCOMPARE(dt1.timeSpec(), Qt::OffsetFromUTC);
QCOMPARE(dt1.offsetFromUtc(), 60 * 60);
// Only testing UTC; see fromSecsSinceEpoch() for fuller test.
- dt1.setTimeSpec(Qt::UTC);
+ dt1.setTimeZone(UTC);
const qint64 maxSeconds = std::numeric_limits<qint64>::max() / 1000;
dt1.setSecsSinceEpoch(maxSeconds);
QVERIFY(dt1.isValid());
@@ -595,56 +718,56 @@ void tst_QDateTime::setMSecsSinceEpoch_data()
QTest::newRow("zero")
<< Q_INT64_C(0)
- << QDateTime(QDate(1970, 1, 1), QTime(0, 0), Qt::UTC)
+ << QDateTime(QDate(1970, 1, 1), QTime(0, 0), UTC)
<< QDateTime(QDate(1970, 1, 1), QTime(1, 0));
QTest::newRow("+1ms")
<< Q_INT64_C(+1)
- << QDateTime(QDate(1970, 1, 1), QTime(0, 0, 0, 1), Qt::UTC)
+ << QDateTime(QDate(1970, 1, 1), QTime(0, 0, 0, 1), UTC)
<< QDateTime(QDate(1970, 1, 1), QTime(1, 0, 0, 1));
QTest::newRow("+1s")
<< Q_INT64_C(+1000)
- << QDateTime(QDate(1970, 1, 1), QTime(0, 0, 1), Qt::UTC)
+ << QDateTime(QDate(1970, 1, 1), QTime(0, 0, 1), UTC)
<< QDateTime(QDate(1970, 1, 1), QTime(1, 0, 1));
QTest::newRow("-1ms")
<< Q_INT64_C(-1)
- << QDateTime(QDate(1969, 12, 31), QTime(23, 59, 59, 999), Qt::UTC)
+ << QDateTime(QDate(1969, 12, 31), QTime(23, 59, 59, 999), UTC)
<< QDateTime(QDate(1970, 1, 1), QTime(0, 59, 59, 999));
QTest::newRow("-1s")
<< Q_INT64_C(-1000)
- << QDateTime(QDate(1969, 12, 31), QTime(23, 59, 59), Qt::UTC)
+ << QDateTime(QDate(1969, 12, 31), QTime(23, 59, 59), UTC)
<< QDateTime(QDate(1970, 1, 1), QTime(0, 59, 59));
QTest::newRow("123456789")
<< Q_INT64_C(123456789)
- << QDateTime(QDate(1970, 1, 2), QTime(10, 17, 36, 789), Qt::UTC)
- << QDateTime(QDate(1970, 1, 2), QTime(11, 17, 36, 789), Qt::LocalTime);
+ << QDateTime(QDate(1970, 1, 2), QTime(10, 17, 36, 789), UTC)
+ << QDateTime(QDate(1970, 1, 2), QTime(11, 17, 36, 789));
QTest::newRow("-123456789")
<< Q_INT64_C(-123456789)
- << QDateTime(QDate(1969, 12, 30), QTime(13, 42, 23, 211), Qt::UTC)
- << QDateTime(QDate(1969, 12, 30), QTime(14, 42, 23, 211), Qt::LocalTime);
+ << QDateTime(QDate(1969, 12, 30), QTime(13, 42, 23, 211), UTC)
+ << QDateTime(QDate(1969, 12, 30), QTime(14, 42, 23, 211));
QTest::newRow("post-32-bit-time_t")
<< (Q_INT64_C(1000) << 32)
- << QDateTime(QDate(2106, 2, 7), QTime(6, 28, 16), Qt::UTC)
+ << QDateTime(QDate(2106, 2, 7), QTime(6, 28, 16), UTC)
<< QDateTime(QDate(2106, 2, 7), QTime(7, 28, 16));
QTest::newRow("very-large")
<< (Q_INT64_C(123456) << 32)
- << QDateTime(QDate(18772, 8, 15), QTime(1, 8, 14, 976), Qt::UTC)
+ << QDateTime(QDate(18772, 8, 15), QTime(1, 8, 14, 976), UTC)
<< QDateTime(QDate(18772, 8, 15), QTime(3, 8, 14, 976));
QTest::newRow("old min (Tue Nov 25 00:00:00 -4714)")
<< Q_INT64_C(-210866716800000)
- << QDateTime(QDate::fromJulianDay(1), QTime(0, 0), Qt::UTC)
+ << QDateTime(QDate::fromJulianDay(1), QTime(0, 0), UTC)
<< QDateTime(QDate::fromJulianDay(1), QTime(1, 0)).addSecs(preZoneFix);
QTest::newRow("old max (Tue Jun 3 21:59:59 5874898)")
<< Q_INT64_C(185331720376799999)
- << QDateTime(QDate::fromJulianDay(0x7fffffff), QTime(21, 59, 59, 999), Qt::UTC)
+ << QDateTime(QDate::fromJulianDay(0x7fffffff), QTime(21, 59, 59, 999), UTC)
<< QDateTime(QDate::fromJulianDay(0x7fffffff), QTime(23, 59, 59, 999));
QTest::newRow("min")
<< std::numeric_limits<qint64>::min()
- << QDateTime(QDate(-292275056, 5, 16), QTime(16, 47, 4, 192), Qt::UTC)
+ << QDateTime(QDate(-292275056, 5, 16), QTime(16, 47, 4, 192), UTC)
<< QDateTime(QDate(-292275056, 5, 16), QTime(17, 47, 4, 192).addSecs(preZoneFix));
QTest::newRow("max")
<< std::numeric_limits<qint64>::max()
- << QDateTime(QDate(292278994, 8, 17), QTime(7, 12, 55, 807), Qt::UTC)
- << QDateTime(QDate(292278994, 8, 17), QTime(9, 12, 55, 807), Qt::LocalTime);
+ << QDateTime(QDate(292278994, 8, 17), QTime(7, 12, 55, 807), UTC)
+ << QDateTime(QDate(292278994, 8, 17), QTime(9, 12, 55, 807));
}
void tst_QDateTime::setMSecsSinceEpoch()
@@ -652,9 +775,10 @@ void tst_QDateTime::setMSecsSinceEpoch()
QFETCH(qint64, msecs);
QFETCH(QDateTime, utc);
QFETCH(QDateTime, cet);
+ using Bound = std::numeric_limits<qint64>;
QDateTime dt;
- dt.setTimeSpec(Qt::UTC);
+ dt.setTimeZone(UTC);
dt.setMSecsSinceEpoch(msecs);
QCOMPARE(dt, utc);
@@ -663,14 +787,14 @@ void tst_QDateTime::setMSecsSinceEpoch()
QCOMPARE(dt.timeSpec(), Qt::UTC);
{
- QDateTime dt1 = QDateTime::fromMSecsSinceEpoch(msecs, Qt::UTC);
+ QDateTime dt1 = QDateTime::fromMSecsSinceEpoch(msecs, UTC);
QCOMPARE(dt1, utc);
QCOMPARE(dt1.date(), utc.date());
QCOMPARE(dt1.time(), utc.time());
QCOMPARE(dt1.timeSpec(), Qt::UTC);
}
{
- QDateTime dt1(utc.date(), utc.time(), Qt::UTC);
+ QDateTime dt1(utc.date(), utc.time(), UTC);
QCOMPARE(dt1, utc);
QCOMPARE(dt1.date(), utc.date());
QCOMPARE(dt1.time(), utc.time());
@@ -685,10 +809,10 @@ void tst_QDateTime::setMSecsSinceEpoch()
QCOMPARE(dt1.timeSpec(), Qt::UTC);
}
- if (zoneIsCET && (msecs == std::numeric_limits<qint64>::max()
+ if (zoneIsCET && (msecs == Bound::max()
// LocalTime will also overflow for min in a CET zone west
// of Greenwich (Europe/Madrid):
- || (preZoneFix < -3600 && msecs == std::numeric_limits<qint64>::min()))) {
+ || (preZoneFix < -3600 && msecs == Bound::min()))) {
QVERIFY(!cet.isValid()); // overflows
} else if (zoneIsCET) {
QVERIFY(cet.isValid());
@@ -696,7 +820,7 @@ void tst_QDateTime::setMSecsSinceEpoch()
// Test converting from LocalTime to UTC back to LocalTime.
QDateTime localDt;
- localDt.setTimeSpec(Qt::LocalTime);
+ localDt.setTimeZone(QTimeZone::LocalTime);
localDt.setMSecsSinceEpoch(msecs);
QCOMPARE(localDt, utc);
@@ -726,53 +850,51 @@ void tst_QDateTime::setMSecsSinceEpoch()
QCOMPARE(dt.toMSecsSinceEpoch(), msecs);
QCOMPARE(qint64(dt.toSecsSinceEpoch()), msecs / 1000);
- QDateTime reference(QDate(1970, 1, 1), QTime(0, 0), Qt::UTC);
+ QDateTime reference(QDate(1970, 1, 1), QTime(0, 0), UTC);
QCOMPARE(dt, reference.addMSecs(msecs));
// Tests that we correctly recognize when we fall off the extremities:
- if (msecs == std::numeric_limits<qint64>::max()) {
- QDateTime off(QDate(1970, 1, 1).startOfDay(Qt::OffsetFromUTC, 1));
+ if (msecs == Bound::max()) {
+ QDateTime off(QDate(1970, 1, 1).startOfDay(QTimeZone::fromSecondsAheadOfUtc(1)));
off.setMSecsSinceEpoch(msecs);
QVERIFY(!off.isValid());
- } else if (msecs == std::numeric_limits<qint64>::min()) {
- QDateTime off(QDate(1970, 1, 1).startOfDay(Qt::OffsetFromUTC, -1));
+ } else if (msecs == Bound::min()) {
+ QDateTime off(QDate(1970, 1, 1).startOfDay(QTimeZone::fromSecondsAheadOfUtc(-1)));
off.setMSecsSinceEpoch(msecs);
QVERIFY(!off.isValid());
}
- if ((localTimeType == LocalTimeAheadOfUtc && msecs == std::numeric_limits<qint64>::max())
- || (localTimeType == LocalTimeBehindUtc && msecs == std::numeric_limits<qint64>::min())) {
+ // Check overflow; only robust if local time is the same at epoch as relevant bound.
+ // See setting of LocalTimeType values for details.
+ if (epochTimeType == LocalTimeAheadOfUtc
+ ? distantTimeType == LocalTimeAheadOfUtc && msecs == Bound::max()
+ : (solarMeanType == LocalTimeBehindUtc && msecs == Bound::min()
+ && epochTimeType == LocalTimeBehindUtc)) {
QDateTime curt = QDate(1970, 1, 1).startOfDay(); // initially in short-form
curt.setMSecsSinceEpoch(msecs); // Overflows due to offset
QVERIFY(!curt.isValid());
}
}
-void tst_QDateTime::fromMSecsSinceEpoch_data()
-{
- setMSecsSinceEpoch_data();
-}
-
void tst_QDateTime::fromMSecsSinceEpoch()
{
QFETCH(qint64, msecs);
QFETCH(QDateTime, utc);
QFETCH(QDateTime, cet);
using Bound = std::numeric_limits<qint64>;
- if (msecs == Bound::min())
- qDebug() << "Local overflow:" << preZoneFix << Qt::hex;
- QDateTime dtLocal = QDateTime::fromMSecsSinceEpoch(msecs, Qt::LocalTime);
- QDateTime dtUtc = QDateTime::fromMSecsSinceEpoch(msecs, Qt::UTC);
- QDateTime dtOffset = QDateTime::fromMSecsSinceEpoch(msecs, Qt::OffsetFromUTC, 60*60);
+ QDateTime dtLocal = QDateTime::fromMSecsSinceEpoch(msecs);
+ QDateTime dtUtc = QDateTime::fromMSecsSinceEpoch(msecs, UTC);
+ QDateTime dtOffset
+ = QDateTime::fromMSecsSinceEpoch(msecs, QTimeZone::fromSecondsAheadOfUtc(60 * 60));
// LocalTime will overflow for "min" or "max" tests, depending on whether
// you're East or West of Greenwich. In UTC, we won't overflow. If we're
// actually west of Greenwich but (e.g. Europe/Madrid) our zone claims east,
// "min" can also overflow (case only caught if local time is CET).
- const bool localOverflow = (localTimeType == LocalTimeAheadOfUtc
- ? msecs == Bound::max() || preZoneFix < -3600
- : localTimeType == LocalTimeBehindUtc && msecs == Bound::min());
- if (!localOverflow)
+ const bool localOverflow =
+ (distantTimeType == LocalTimeAheadOfUtc && (msecs == Bound::max() || preZoneFix < -3600))
+ || (solarMeanType == LocalTimeBehindUtc && msecs == Bound::min());
+ if (!localOverflow) // Can fail if offset changes sign, e.g. Alaska, Philippines.
QCOMPARE(dtLocal, utc);
QCOMPARE(dtUtc, utc);
@@ -806,7 +928,7 @@ void tst_QDateTime::fromMSecsSinceEpoch()
if (msecs != Bound::max())
QCOMPARE(qint64(dtOffset.toSecsSinceEpoch()), msecs / 1000);
- QDateTime reference(QDate(1970, 1, 1), QTime(0, 0), Qt::UTC);
+ QDateTime reference(QDate(1970, 1, 1), QTime(0, 0), UTC);
if (!localOverflow)
QCOMPARE(dtLocal, reference.addMSecs(msecs));
QCOMPARE(dtUtc, reference.addMSecs(msecs));
@@ -818,16 +940,31 @@ void tst_QDateTime::fromSecsSinceEpoch()
{
// Compare setSecsSinceEpoch()
const qint64 maxSeconds = std::numeric_limits<qint64>::max() / 1000;
- const QDateTime early = QDateTime::fromSecsSinceEpoch(-maxSeconds, Qt::UTC);
- const QDateTime late = QDateTime::fromSecsSinceEpoch(maxSeconds, Qt::UTC);
+ const QDateTime early = QDateTime::fromSecsSinceEpoch(-maxSeconds, UTC);
+ const QDateTime late = QDateTime::fromSecsSinceEpoch(maxSeconds, UTC);
QVERIFY(late.isValid());
- QVERIFY(!QDateTime::fromSecsSinceEpoch(maxSeconds + 1, Qt::UTC).isValid());
+ QVERIFY(!QDateTime::fromSecsSinceEpoch(maxSeconds + 1, UTC).isValid());
QVERIFY(early.isValid());
- QVERIFY(!QDateTime::fromSecsSinceEpoch(-maxSeconds - 1, Qt::UTC).isValid());
+ QVERIFY(!QDateTime::fromSecsSinceEpoch(-maxSeconds - 1, UTC).isValid());
// Local time: need to adjust for its zone offset
- const qint64 last = maxSeconds - qMax(late.addYears(-1).toLocalTime().offsetFromUtc(), 0);
+ const int lateOffset = late.addYears(-1).toLocalTime().offsetFromUtc();
+#if QT_CONFIG(timezone)
+ // Check what system zone believes in, as it's used as fall-back to cope
+ // with times outside the system time_t functions' range, or overflow on the
+ // results of using those functions. (It seems glibc's handling of
+ // Australasian zones parts company with the IANA DB after about 5881580 CE,
+ // leaving NZ in permanent DST after that, for example.) Of course, if
+ // that's less than lateOffset (as it is for glibc's similar handling of
+ // MET), the fall-back code will also fail when the primary code fails, so
+ // use the lesser of these late offsets.
+ const int lateZone = qMin(QTimeZone::systemTimeZone().offsetFromUtc(late), lateOffset);
+#else
+ const int lateZone = lateOffset;
+#endif
+
+ const qint64 last = maxSeconds - qMax(lateZone, 0);
QVERIFY(QDateTime::fromSecsSinceEpoch(last).isValid());
QVERIFY(!QDateTime::fromSecsSinceEpoch(last + 1).isValid());
const qint64 first = -maxSeconds - qMin(early.addYears(1).toLocalTime().offsetFromUtc(), 0);
@@ -835,10 +972,14 @@ void tst_QDateTime::fromSecsSinceEpoch()
QVERIFY(!QDateTime::fromSecsSinceEpoch(first - 1).isValid());
// Use an offset for which .toUTC()'s return would flip the validity:
- QVERIFY(QDateTime::fromSecsSinceEpoch(maxSeconds - 7200, Qt::OffsetFromUTC, 7200).isValid());
- QVERIFY(!QDateTime::fromSecsSinceEpoch(maxSeconds - 7199, Qt::OffsetFromUTC, 7200).isValid());
- QVERIFY(QDateTime::fromSecsSinceEpoch(7200 - maxSeconds, Qt::OffsetFromUTC, -7200).isValid());
- QVERIFY(!QDateTime::fromSecsSinceEpoch(7199 - maxSeconds, Qt::OffsetFromUTC, -7200).isValid());
+ QVERIFY(QDateTime::fromSecsSinceEpoch(maxSeconds - 7200,
+ QTimeZone::fromSecondsAheadOfUtc(7200)).isValid());
+ QVERIFY(!QDateTime::fromSecsSinceEpoch(maxSeconds - 7199,
+ QTimeZone::fromSecondsAheadOfUtc(7200)).isValid());
+ QVERIFY(QDateTime::fromSecsSinceEpoch(7200 - maxSeconds,
+ QTimeZone::fromSecondsAheadOfUtc(-7200)).isValid());
+ QVERIFY(!QDateTime::fromSecsSinceEpoch(7199 - maxSeconds,
+ QTimeZone::fromSecondsAheadOfUtc(-7200)).isValid());
#if QT_CONFIG(timezone)
// As for offset, use zones each side of UTC:
@@ -861,23 +1002,23 @@ void tst_QDateTime::toString_isoDate_data()
<< QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34))
<< Qt::ISODate << QString("1978-11-09T13:28:34");
QTest::newRow("UTC")
- << QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34), Qt::UTC)
+ << QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34), UTC)
<< Qt::ISODate << QString("1978-11-09T13:28:34Z");
QDateTime dt(QDate(1978, 11, 9), QTime(13, 28, 34));
- dt.setOffsetFromUtc(19800);
+ dt.setTimeZone(QTimeZone::fromSecondsAheadOfUtc(19800));
QTest::newRow("positive OffsetFromUTC")
<< dt << Qt::ISODate
<< QString("1978-11-09T13:28:34+05:30");
- dt.setOffsetFromUtc(-7200);
+ dt.setTimeZone(QTimeZone::fromSecondsAheadOfUtc(-7200));
QTest::newRow("negative OffsetFromUTC")
<< dt << Qt::ISODate
<< QString("1978-11-09T13:28:34-02:00");
- dt.setOffsetFromUtc(-900);
+ dt.setTimeZone(QTimeZone::fromSecondsAheadOfUtc(-900));
QTest::newRow("negative non-integral OffsetFromUTC")
<< dt << Qt::ISODate
<< QString("1978-11-09T13:28:34-00:15");
QTest::newRow("invalid") // ISODate < 2019 doesn't allow -ve year numbers; QTBUG-91070
- << QDateTime(QDate(-1, 11, 9), QTime(13, 28, 34), Qt::UTC)
+ << QDateTime(QDate(-1, 11, 9), QTime(13, 28, 34), UTC)
<< Qt::ISODate << QString();
QTest::newRow("without-ms")
<< QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34, 20))
@@ -914,7 +1055,7 @@ void tst_QDateTime::toString_isoDate()
void tst_QDateTime::toString_isoDate_extra()
{
- QDateTime dt = QDateTime::fromMSecsSinceEpoch(0, Qt::UTC);
+ QDateTime dt = QDateTime::fromMSecsSinceEpoch(0, UTC);
QCOMPARE(dt.toString(Qt::ISODate), QLatin1String("1970-01-01T00:00:00Z"));
#if QT_CONFIG(timezone)
QTimeZone PST("America/Vancouver");
@@ -943,15 +1084,15 @@ void tst_QDateTime::toString_textDate_data()
+ ' ' + QLocale::c().monthName(1, QLocale::ShortFormat);
// ### Qt 7 GMT: change to UTC - see matching QDateTime::fromString() comment
- QTest::newRow("localtime") << QDateTime(QDate(2013, 1, 2), QTime(1, 2, 3), Qt::LocalTime)
+ QTest::newRow("localtime") << QDateTime(QDate(2013, 1, 2), QTime(1, 2, 3))
<< wednesdayJanuary + QString(" 2 01:02:03 2013");
- QTest::newRow("utc") << QDateTime(QDate(2013, 1, 2), QTime(1, 2, 3), Qt::UTC)
+ QTest::newRow("utc") << QDateTime(QDate(2013, 1, 2), QTime(1, 2, 3), UTC)
<< wednesdayJanuary + QString(" 2 01:02:03 2013 GMT");
- QTest::newRow("offset+") << QDateTime(QDate(2013, 1, 2), QTime(1, 2, 3), Qt::OffsetFromUTC,
- 10 * 60 * 60)
+ QTest::newRow("offset+") << QDateTime(QDate(2013, 1, 2), QTime(1, 2, 3),
+ QTimeZone::fromSecondsAheadOfUtc(10 * 60 * 60))
<< wednesdayJanuary + QString(" 2 01:02:03 2013 GMT+1000");
- QTest::newRow("offset-") << QDateTime(QDate(2013, 1, 2), QTime(1, 2, 3), Qt::OffsetFromUTC,
- -10 * 60 * 60)
+ QTest::newRow("offset-") << QDateTime(QDate(2013, 1, 2), QTime(1, 2, 3),
+ QTimeZone::fromSecondsAheadOfUtc(-10 * 60 * 60))
<< wednesdayJanuary + QString(" 2 01:02:03 2013 GMT-1000");
QTest::newRow("invalid") << QDateTime()
<< QString("");
@@ -981,9 +1122,9 @@ void tst_QDateTime::toString_textDate_extra()
auto endsWithGmt = [](const QDateTime &dt) {
return dt.toString().endsWith(QLatin1String("GMT"));
};
- QDateTime dt = QDateTime::fromMSecsSinceEpoch(0, Qt::LocalTime);
+ QDateTime dt = QDateTime::fromMSecsSinceEpoch(0);
QVERIFY(!endsWithGmt(dt));
- dt = QDateTime::fromMSecsSinceEpoch(0, Qt::UTC).toLocalTime();
+ dt = QDateTime::fromMSecsSinceEpoch(0, UTC).toLocalTime();
QVERIFY(!endsWithGmt(dt));
#if QT_CONFIG(timezone)
@@ -1016,7 +1157,7 @@ void tst_QDateTime::toString_textDate_extra()
else
QCOMPARE(dt.toString(), QLatin1String("Thu Jan 1 00:00:00 1970"));
#endif
- dt = QDateTime::fromMSecsSinceEpoch(0, Qt::UTC);
+ dt = QDateTime::fromMSecsSinceEpoch(0, UTC);
QVERIFY(endsWithGmt(dt));
}
@@ -1031,22 +1172,22 @@ void tst_QDateTime::toString_rfcDate_data()
<< QString("09 Nov 1978 13:28:34 +0100");
}
QTest::newRow("UTC")
- << QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34), Qt::UTC)
+ << QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34), UTC)
<< QString("09 Nov 1978 13:28:34 +0000");
QDateTime dt(QDate(1978, 11, 9), QTime(13, 28, 34));
- dt.setOffsetFromUtc(19800);
+ dt.setTimeZone(QTimeZone::fromSecondsAheadOfUtc(19800));
QTest::newRow("positive OffsetFromUTC")
<< dt
<< QString("09 Nov 1978 13:28:34 +0530");
- dt.setOffsetFromUtc(-7200);
+ dt.setTimeZone(QTimeZone::fromSecondsAheadOfUtc(-7200));
QTest::newRow("negative OffsetFromUTC")
<< dt
<< QString("09 Nov 1978 13:28:34 -0200");
QTest::newRow("invalid")
- << QDateTime(QDate(1978, 13, 9), QTime(13, 28, 34), Qt::UTC)
+ << QDateTime(QDate(1978, 13, 9), QTime(13, 28, 34), UTC)
<< QString();
QTest::newRow("999 milliseconds UTC")
- << QDateTime(QDate(2000, 1, 1), QTime(13, 28, 34, 999), Qt::UTC)
+ << QDateTime(QDate(2000, 1, 1), QTime(13, 28, 34, 999), UTC)
<< QString("01 Jan 2000 13:28:34 +0000");
}
@@ -1078,29 +1219,44 @@ void tst_QDateTime::toString_strformat()
{
// Most tests are in QLocale, just test that the api works.
QDate testDate(2013, 1, 1);
- QTime testTime(1, 2, 3);
- QDateTime testDateTime(testDate, testTime, Qt::UTC);
+ QTime testTime(1, 2, 3, 456);
+ QDateTime testDateTime(testDate, testTime, UTC);
QCOMPARE(testDate.toString("yyyy-MM-dd"), QString("2013-01-01"));
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
void tst_QDateTime::addDays()
{
- for (int pass = 0; pass < 2; ++pass) {
- QDateTime dt(QDate(2004, 1, 1), QTime(12, 34, 56), pass == 0 ? Qt::LocalTime : Qt::UTC);
- dt = dt.addDays(185);
+ const QTimeZone zones[] = {
+ QTimeZone(QTimeZone::LocalTime),
+ QTimeZone(QTimeZone::UTC),
+#if QT_CONFIG(timezone)
+ QTimeZone("Europe/Oslo"),
+#endif
+ QTimeZone::fromSecondsAheadOfUtc(3600)
+ };
+ for (const auto &zone : zones) {
+ QDateTime dt = QDateTime(QDate(2004, 1, 1), QTime(12, 34, 56), zone).addDays(185);
QVERIFY(dt.date().year() == 2004 && dt.date().month() == 7 && dt.date().day() == 4);
QVERIFY(dt.time().hour() == 12 && dt.time().minute() == 34 && dt.time().second() == 56
&& dt.time().msec() == 0);
- QCOMPARE(dt.timeSpec(), (pass == 0 ? Qt::LocalTime : Qt::UTC));
+ QCOMPARE(dt.timeRepresentation(), zone);
dt = dt.addDays(-185);
QCOMPARE(dt.date(), QDate(2004, 1, 1));
QCOMPARE(dt.time(), QTime(12, 34, 56));
+
+ // Test we can do this before time-zones existed:
+ dt = QDateTime(QDate(1704, 1, 1), QTime(12, 0), zone).addDays(185);
+ QCOMPARE(dt.date(), QDate(1704, 7, 4));
+ QCOMPARE(dt.time(), QTime(12, 0));
+ QCOMPARE(dt.timeRepresentation(), zone);
}
QDateTime dt(QDate(1752, 9, 14), QTime(12, 34, 56));
@@ -1115,19 +1271,19 @@ void tst_QDateTime::addDays()
}
// Test preserves TimeSpec
- QDateTime dt1(QDate(2013, 1, 1), QTime(0, 0), Qt::UTC);
+ QDateTime dt1(QDate(2013, 1, 1), QTime(0, 0), UTC);
QDateTime dt2 = dt1.addDays(2);
QCOMPARE(dt2.date(), QDate(2013, 1, 3));
QCOMPARE(dt2.time(), QTime(0, 0));
QCOMPARE(dt2.timeSpec(), Qt::UTC);
- dt1 = QDateTime(QDate(2013, 1, 1), QTime(0, 0), Qt::LocalTime);
+ dt1 = QDateTime(QDate(2013, 1, 1), QTime(0, 0));
dt2 = dt1.addDays(2);
QCOMPARE(dt2.date(), QDate(2013, 1, 3));
QCOMPARE(dt2.time(), QTime(0, 0));
QCOMPARE(dt2.timeSpec(), Qt::LocalTime);
- dt1 = QDateTime(QDate(2013, 1, 1), QTime(0, 0), Qt::OffsetFromUTC, 60*60);
+ dt1 = QDateTime(QDate(2013, 1, 1), QTime(0, 0), QTimeZone::fromSecondsAheadOfUtc(60 * 60));
dt2 = dt1.addDays(2);
QCOMPARE(dt2.date(), QDate(2013, 1, 3));
QCOMPARE(dt2.time(), QTime(0, 0));
@@ -1144,15 +1300,62 @@ void tst_QDateTime::addDays()
QCOMPARE(dt2.timeSpec(), Qt::TimeZone);
QCOMPARE(dt2.timeZone(), cet);
}
-#endif
+# ifndef INADEQUATE_TZ_DATA
+ if (const QTimeZone lint("Pacific/Kiritimati"); lint.isValid()) {
+ // Line Islands Time skipped Sat 1994-12-31:
+ dt1 = QDateTime(QDate(1994, 12, 30), QTime(12, 0), lint);
+ dt2 = QDateTime(QDate(1995, 1, 1), QTime(12, 0), lint);
+ // Trying to step into the hole gets the other side:
+ QCOMPARE(dt1.addDays(1), dt2);
+ QCOMPARE(dt2.addDays(-1), dt1);
+ // But the other side is in fact two days away:
+ QCOMPARE(dt1.addDays(2), dt2);
+ QCOMPARE(dt2.addDays(-2), dt1);
+ QCOMPARE(dt1.daysTo(dt2), 2);
+ }
+# ifndef Q_OS_DARWIN
+ if (const QTimeZone alaska("America/Anchorage"); alaska.isValid()) {
+ // On Julian date 1867, Sat Oct 7 (at 14:31 local solar mean time for
+ // Anchorage, 15:30 LMT in Sitka, which hosted the transfer ceremony)
+ // Russia sold Alaska to the USA, which changed the calendar to
+ // Gregorian, hence the date to Fri Oct 18. Compare addSecs:Alaska-Day.
+ // Friday evening and Saturday morning were repeated, with different dates.
+ // Friday noon, as described by the Russians:
+ dt1 = QDateTime(QDate(1867, 10, 6, QCalendar(QCalendar::System::Julian)),
+ QTime(12, 0), alaska);
+ // Sunday noon, as described by the Americans:
+ dt2 = QDateTime(QDate(1867, 10, 20), QTime(12, 0), alaska);
+ // Three elapsed days, but daysTo() and addDays only see two:
+ QCOMPARE(dt1.addDays(2), dt2);
+ QCOMPARE(dt2.addDays(-2), dt1);
+ QCOMPARE(dt1.daysTo(dt2), 2);
+ // Stepping into the duplicated day (Julian 7th, Gregorian 19th) gets
+ // the nearer side, with the same nominal date (and time):
+ QCOMPARE(dt1.addDays(1).date(), dt2.addDays(-1).date());
+ QCOMPARE(dt1.addDays(1).time(), dt2.addDays(-1).time());
+ QCOMPARE(dt1.addDays(1).daysTo(dt2.addDays(-1)), 0);
+ // Yet they differ by a day:
+ QCOMPARE_NE(dt1.addDays(1), dt2.addDays(-1));
+ QCOMPARE(dt1.addDays(1).secsTo(dt2.addDays(-1)), 24 * 60 * 60);
+ // Stepping from one duplicate one day towards the other jumps it:
+ QCOMPARE(dt1, dt2.addDays(-1).addDays(-1));
+ QCOMPARE(dt1.addDays(1).addDays(1), dt2);
+ }
+# endif // Darwin
+# endif // inadequate zone data
+#endif // timezone
- // Test last UTC second of 1969 *is* valid (despite being time_t(-1))
- dt1 = QDateTime(QDate(1969, 12, 30), QTime(23, 59, 59), Qt::UTC).toLocalTime().addDays(1);
- QVERIFY(dt1.isValid());
- QCOMPARE(dt1.toSecsSinceEpoch(), -1);
- dt2 = QDateTime(QDate(1970, 1, 1), QTime(23, 59, 59), Qt::UTC).toLocalTime().addDays(-1);
- QVERIFY(dt2.isValid());
- QCOMPARE(dt2.toSecsSinceEpoch(), -1);
+ // Baja Mexico has a transition at the epoch, see fromStringDateFormat_data().
+ if (QDateTime(QDate(1969, 12, 30), QTime(0, 0)).secsTo(
+ QDateTime(QDate(1970, 1, 2), QTime(0, 0))) == 3 * 24 * 60 * 60) {
+ // Test last UTC second of 1969 *is* valid (despite being time_t(-1))
+ dt1 = QDateTime(QDate(1969, 12, 30), QTime(23, 59, 59), UTC).toLocalTime().addDays(1);
+ QVERIFY(dt1.isValid());
+ QCOMPARE(dt1.toSecsSinceEpoch(), -1);
+ dt2 = QDateTime(QDate(1970, 1, 1), QTime(23, 59, 59), UTC).toLocalTime().addDays(-1);
+ QVERIFY(dt2.isValid());
+ QCOMPARE(dt2.toSecsSinceEpoch(), -1);
+ }
}
void tst_QDateTime::addInvalid()
@@ -1172,7 +1375,7 @@ void tst_QDateTime::addInvalid()
offset = bad.addMSecs(73);
QVERIFY(offset.isNull());
- QDateTime bound = QDateTime::fromMSecsSinceEpoch(std::numeric_limits<qint64>::min(), Qt::UTC);
+ QDateTime bound = QDateTime::fromMSecsSinceEpoch(std::numeric_limits<qint64>::min(), UTC);
QVERIFY(bound.isValid());
offset = bound.addMSecs(-1);
QVERIFY(!offset.isValid());
@@ -1251,13 +1454,13 @@ void tst_QDateTime::addMonths()
QCOMPARE(end.time(), testTime);
QCOMPARE(end.timeSpec(), Qt::LocalTime);
- start = QDateTime(testDate, testTime, Qt::UTC);
+ start = QDateTime(testDate, testTime, UTC);
end = start.addMonths(months);
QCOMPARE(end.date(), resultDate);
QCOMPARE(end.time(), testTime);
QCOMPARE(end.timeSpec(), Qt::UTC);
- start = QDateTime(testDate, testTime, Qt::OffsetFromUTC, 60 * 60);
+ start = QDateTime(testDate, testTime, QTimeZone::fromSecondsAheadOfUtc(60 * 60));
end = start.addMonths(months);
QCOMPARE(end.date(), resultDate);
QCOMPARE(end.time(), testTime);
@@ -1303,13 +1506,13 @@ void tst_QDateTime::addYears()
QCOMPARE(end.time(), testTime);
QCOMPARE(end.timeSpec(), Qt::LocalTime);
- start = QDateTime(startDate, testTime, Qt::UTC);
+ start = QDateTime(startDate, testTime, UTC);
end = start.addYears(years1).addYears(years2);
QCOMPARE(end.date(), resultDate);
QCOMPARE(end.time(), testTime);
QCOMPARE(end.timeSpec(), Qt::UTC);
- start = QDateTime(startDate, testTime, Qt::OffsetFromUTC, 60 * 60);
+ start = QDateTime(startDate, testTime, QTimeZone::fromSecondsAheadOfUtc(60 * 60));
end = start.addYears(years1).addYears(years2);
QCOMPARE(end.date(), resultDate);
QCOMPARE(end.time(), testTime);
@@ -1328,107 +1531,144 @@ void tst_QDateTime::addMSecs_data()
const qint64 daySecs(86400);
QTest::newRow("utc0")
- << QDateTime(QDate(2004, 1, 1), standardTime, Qt::UTC) << daySecs
- << QDateTime(QDate(2004, 1, 2), standardTime, Qt::UTC);
+ << QDateTime(QDate(2004, 1, 1), standardTime, UTC) << daySecs
+ << QDateTime(QDate(2004, 1, 2), standardTime, UTC);
QTest::newRow("utc1")
- << QDateTime(QDate(2004, 1, 1), standardTime, Qt::UTC) << (daySecs * 185)
- << QDateTime(QDate(2004, 7, 4), standardTime, Qt::UTC);
+ << QDateTime(QDate(2004, 1, 1), standardTime, UTC) << (daySecs * 185)
+ << QDateTime(QDate(2004, 7, 4), standardTime, UTC);
QTest::newRow("utc2")
- << QDateTime(QDate(2004, 1, 1), standardTime, Qt::UTC) << (daySecs * 366)
- << QDateTime(QDate(2005, 1, 1), standardTime, Qt::UTC);
+ << QDateTime(QDate(2004, 1, 1), standardTime, UTC) << (daySecs * 366)
+ << QDateTime(QDate(2005, 1, 1), standardTime, UTC);
QTest::newRow("utc3")
- << QDateTime(QDate(1760, 1, 1), standardTime, Qt::UTC) << daySecs
- << QDateTime(QDate(1760, 1, 2), standardTime, Qt::UTC);
+ << QDateTime(QDate(1760, 1, 1), standardTime, UTC) << daySecs
+ << QDateTime(QDate(1760, 1, 2), standardTime, UTC);
QTest::newRow("utc4")
- << QDateTime(QDate(1760, 1, 1), standardTime, Qt::UTC) << (daySecs * 185)
- << QDateTime(QDate(1760, 7, 4), standardTime, Qt::UTC);
+ << QDateTime(QDate(1760, 1, 1), standardTime, UTC) << (daySecs * 185)
+ << QDateTime(QDate(1760, 7, 4), standardTime, UTC);
QTest::newRow("utc5")
- << QDateTime(QDate(1760, 1, 1), standardTime, Qt::UTC) << (daySecs * 366)
- << QDateTime(QDate(1761, 1, 1), standardTime, Qt::UTC);
+ << QDateTime(QDate(1760, 1, 1), standardTime, UTC) << (daySecs * 366)
+ << QDateTime(QDate(1761, 1, 1), standardTime, UTC);
QTest::newRow("utc6")
- << QDateTime(QDate(4000, 1, 1), standardTime, Qt::UTC) << daySecs
- << QDateTime(QDate(4000, 1, 2), standardTime, Qt::UTC);
+ << QDateTime(QDate(4000, 1, 1), standardTime, UTC) << daySecs
+ << QDateTime(QDate(4000, 1, 2), standardTime, UTC);
QTest::newRow("utc7")
- << QDateTime(QDate(4000, 1, 1), standardTime, Qt::UTC) << (daySecs * 185)
- << QDateTime(QDate(4000, 7, 4), standardTime, Qt::UTC);
+ << QDateTime(QDate(4000, 1, 1), standardTime, UTC) << (daySecs * 185)
+ << QDateTime(QDate(4000, 7, 4), standardTime, UTC);
QTest::newRow("utc8")
- << QDateTime(QDate(4000, 1, 1), standardTime, Qt::UTC) << (daySecs * 366)
- << QDateTime(QDate(4001, 1, 1), standardTime, Qt::UTC);
+ << QDateTime(QDate(4000, 1, 1), standardTime, UTC) << (daySecs * 366)
+ << QDateTime(QDate(4001, 1, 1), standardTime, UTC);
QTest::newRow("utc9")
- << QDateTime(QDate(4000, 1, 1), standardTime, Qt::UTC) << qint64(0)
- << QDateTime(QDate(4000, 1, 1), standardTime, Qt::UTC);
+ << QDateTime(QDate(4000, 1, 1), standardTime, UTC) << qint64(0)
+ << QDateTime(QDate(4000, 1, 1), standardTime, UTC);
if (zoneIsCET) {
QTest::newRow("cet0")
- << QDateTime(QDate(2004, 1, 1), standardTime, Qt::LocalTime) << daySecs
- << QDateTime(QDate(2004, 1, 2), standardTime, Qt::LocalTime);
+ << QDateTime(QDate(2004, 1, 1), standardTime) << daySecs
+ << QDateTime(QDate(2004, 1, 2), standardTime);
QTest::newRow("cet1")
- << QDateTime(QDate(2004, 1, 1), standardTime, Qt::LocalTime) << (daySecs * 185)
- << QDateTime(QDate(2004, 7, 4), daylightTime, Qt::LocalTime);
+ << QDateTime(QDate(2004, 1, 1), standardTime) << (daySecs * 185)
+ << QDateTime(QDate(2004, 7, 4), daylightTime);
QTest::newRow("cet2")
- << QDateTime(QDate(2004, 1, 1), standardTime, Qt::LocalTime) << (daySecs * 366)
- << QDateTime(QDate(2005, 1, 1), standardTime, Qt::LocalTime);
+ << QDateTime(QDate(2004, 1, 1), standardTime) << (daySecs * 366)
+ << QDateTime(QDate(2005, 1, 1), standardTime);
QTest::newRow("cet3")
- << QDateTime(QDate(1760, 1, 1), standardTime, Qt::LocalTime) << daySecs
- << QDateTime(QDate(1760, 1, 2), standardTime, Qt::LocalTime);
+ << QDateTime(QDate(1760, 1, 1), standardTime) << daySecs
+ << QDateTime(QDate(1760, 1, 2), standardTime);
QTest::newRow("cet4")
- << QDateTime(QDate(1760, 1, 1), standardTime, Qt::LocalTime) << (daySecs * 185)
- << QDateTime(QDate(1760, 7, 4), standardTime, Qt::LocalTime);
+ << QDateTime(QDate(1760, 1, 1), standardTime) << (daySecs * 185)
+ << QDateTime(QDate(1760, 7, 4), standardTime);
QTest::newRow("cet5")
- << QDateTime(QDate(1760, 1, 1), standardTime, Qt::LocalTime) << (daySecs * 366)
- << QDateTime(QDate(1761, 1, 1), standardTime, Qt::LocalTime);
+ << QDateTime(QDate(1760, 1, 1), standardTime) << (daySecs * 366)
+ << QDateTime(QDate(1761, 1, 1), standardTime);
QTest::newRow("cet6")
- << QDateTime(QDate(4000, 1, 1), standardTime, Qt::LocalTime) << daySecs
- << QDateTime(QDate(4000, 1, 2), standardTime, Qt::LocalTime);
+ << QDateTime(QDate(4000, 1, 1), standardTime) << daySecs
+ << QDateTime(QDate(4000, 1, 2), standardTime);
QTest::newRow("cet7")
- << QDateTime(QDate(4000, 1, 1), standardTime, Qt::LocalTime) << (daySecs * 185)
- << QDateTime(QDate(4000, 7, 4), daylightTime, Qt::LocalTime);
+ << QDateTime(QDate(4000, 1, 1), standardTime) << (daySecs * 185)
+ << QDateTime(QDate(4000, 7, 4), daylightTime);
QTest::newRow("cet8")
- << QDateTime(QDate(4000, 1, 1), standardTime, Qt::LocalTime) << (daySecs * 366)
- << QDateTime(QDate(4001, 1, 1), standardTime, Qt::LocalTime);
+ << QDateTime(QDate(4000, 1, 1), standardTime) << (daySecs * 366)
+ << QDateTime(QDate(4001, 1, 1), standardTime);
QTest::newRow("cet9")
- << QDateTime(QDate(4000, 1, 1), standardTime, Qt::LocalTime) << qint64(0)
- << QDateTime(QDate(4000, 1, 1), standardTime, Qt::LocalTime);
+ << QDateTime(QDate(4000, 1, 1), standardTime) << qint64(0)
+ << QDateTime(QDate(4000, 1, 1), standardTime);
}
// Year sign change
QTest::newRow("toNegative")
- << QDateTime(QDate(1, 1, 1), QTime(0, 0), Qt::UTC) << qint64(-1)
- << QDateTime(QDate(-1, 12, 31), QTime(23, 59, 59), Qt::UTC);
+ << QDateTime(QDate(1, 1, 1), QTime(0, 0), UTC) << qint64(-1)
+ << QDateTime(QDate(-1, 12, 31), QTime(23, 59, 59), UTC);
QTest::newRow("toPositive")
- << QDateTime(QDate(-1, 12, 31), QTime(23, 59, 59), Qt::UTC) << qint64(1)
- << QDateTime(QDate(1, 1, 1), QTime(0, 0), Qt::UTC);
+ << QDateTime(QDate(-1, 12, 31), QTime(23, 59, 59), UTC) << qint64(1)
+ << QDateTime(QDate(1, 1, 1), QTime(0, 0), UTC);
QTest::newRow("invalid") << QDateTime() << qint64(1) << QDateTime();
// Check Offset details are preserved
QTest::newRow("offset0")
- << QDateTime(QDate(2013, 1, 1), QTime(1, 2, 3), Qt::OffsetFromUTC, 60 * 60)
+ << QDateTime(QDate(2013, 1, 1), QTime(1, 2, 3), QTimeZone::fromSecondsAheadOfUtc(60 * 60))
<< qint64(60 * 60)
- << QDateTime(QDate(2013, 1, 1), QTime(2, 2, 3), Qt::OffsetFromUTC, 60 * 60);
+ << QDateTime(QDate(2013, 1, 1), QTime(2, 2, 3), QTimeZone::fromSecondsAheadOfUtc(60 * 60));
// Check last second of 1969
QTest::newRow("epoch-1s-utc")
- << QDateTime(QDate(1970, 1, 1), QTime(0, 0), Qt::UTC) << qint64(-1)
- << QDateTime(QDate(1969, 12, 31), QTime(23, 59, 59), Qt::UTC);
+ << QDate(1970, 1, 1).startOfDay(UTC) << qint64(-1)
+ << QDateTime(QDate(1969, 12, 31), QTime(23, 59, 59), UTC);
QTest::newRow("epoch-1s-local")
- << QDateTime(QDate(1970, 1, 1), QTime(0, 0)) << qint64(-1)
+ << QDate(1970, 1, 1).startOfDay() << qint64(-1)
<< QDateTime(QDate(1969, 12, 31), QTime(23, 59, 59));
QTest::newRow("epoch-1s-utc-as-local")
- << QDate(1970, 1, 1).startOfDay(Qt::UTC).toLocalTime() << qint64(-1)
- << QDateTime(QDate(1969, 12, 31), QTime(23, 59, 59), Qt::UTC).toLocalTime();
+ << QDate(1970, 1, 1).startOfDay(UTC).toLocalTime() << qint64(-1)
+ << QDateTime(QDate(1969, 12, 31), QTime(23, 59, 59), UTC).toLocalTime();
// Overflow and Underflow
const qint64 maxSeconds = std::numeric_limits<qint64>::max() / 1000;
QTest::newRow("after-last")
- << QDateTime::fromSecsSinceEpoch(maxSeconds, Qt::UTC) << qint64(1) << QDateTime();
+ << QDateTime::fromSecsSinceEpoch(maxSeconds, UTC) << qint64(1) << QDateTime();
QTest::newRow("to-last")
- << QDateTime::fromSecsSinceEpoch(maxSeconds - 1, Qt::UTC) << qint64(1)
- << QDateTime::fromSecsSinceEpoch(maxSeconds, Qt::UTC);
+ << QDateTime::fromSecsSinceEpoch(maxSeconds - 1, UTC) << qint64(1)
+ << QDateTime::fromSecsSinceEpoch(maxSeconds, UTC);
QTest::newRow("before-first")
- << QDateTime::fromSecsSinceEpoch(-maxSeconds, Qt::UTC) << qint64(-1) << QDateTime();
+ << QDateTime::fromSecsSinceEpoch(-maxSeconds, UTC) << qint64(-1) << QDateTime();
QTest::newRow("to-first")
- << QDateTime::fromSecsSinceEpoch(1 - maxSeconds, Qt::UTC) << qint64(-1)
- << QDateTime::fromSecsSinceEpoch(-maxSeconds, Qt::UTC);
+ << QDateTime::fromSecsSinceEpoch(1 - maxSeconds, UTC) << qint64(-1)
+ << QDateTime::fromSecsSinceEpoch(-maxSeconds, UTC);
+
+#if QT_CONFIG(timezone)
+ if (const QTimeZone cet("Europe/Oslo"); cet.isValid()) {
+ QTest::newRow("CET-spring-forward")
+ << QDateTime(QDate(2023, 3, 26), QTime(1, 30), cet) << qint64(60 * 60)
+ << QDateTime(QDate(2023, 3, 26), QTime(3, 30), cet);
+ QTest::newRow("CET-fall-back")
+ << QDateTime(QDate(2023, 10, 29), QTime(1, 30), cet) << qint64(3 * 60 * 60)
+ << QDateTime(QDate(2023, 10, 29), QTime(3, 30), cet);
+ }
+# ifndef INADEQUATE_TZ_DATA
+ const QTimeZone lint("Pacific/Kiritimati");
+ if (lint.isValid()) {
+ // Line Islands Time skipped Sat 1994-12-31:
+ QTest::newRow("Kiritimati-day-off")
+ << QDateTime(QDate(1994, 12, 30), QTime(23, 30), lint) << qint64(60 * 60)
+ << QDateTime(QDate(1995, 1, 1), QTime(0, 30), lint);
+ }
+# ifndef Q_OS_DARWIN
+ if (const QTimeZone alaska("America/Anchorage"); alaska.isValid()) {
+ // On Julian date 1867, Sat Oct 7 (at 14:31 local solar mean time for
+ // Anchorage, 15:30 LMT in Sitka, which hosted the transfer ceremony)
+ // Russia sold Alaska to the USA, which changed the calendar to
+ // Gregorian, hence the date to Fri Oct 18. Contrast addDays().
+ const QDate sat(1867, 10, 19);
+ Q_ASSERT(sat == QDate(1867, 10, 7, QCalendar(QCalendar::System::Julian)));
+ // At the start of the day, it was Sat 7th; by evening it was Fri 18th;
+ // then the next day was Sat 19th.
+ QTest::newRow("Alaska-Day")
+ // The actual morning of the hand-over:
+ << QDateTime(sat, QTime(6, 0), alaska) << qint64(12 * 60 * 60)
+ // The evening of the same day.
+ << QDateTime(sat, QTime(18, 0), alaska).addDays(-1);
+ }
+# endif // Darwin
+# endif // inadequate zone data
+#endif // timezone
}
void tst_QDateTime::addSecs_data()
@@ -1438,9 +1678,9 @@ void tst_QDateTime::addSecs_data()
const qint64 maxSeconds = std::numeric_limits<qint64>::max() / 1000;
// Results would be representable, but the step isn't
QTest::newRow("leap-up")
- << QDateTime::fromSecsSinceEpoch(-1, Qt::UTC) << 1 + maxSeconds << QDateTime();
+ << QDateTime::fromSecsSinceEpoch(-1, UTC) << 1 + maxSeconds << QDateTime();
QTest::newRow("leap-down")
- << QDateTime::fromSecsSinceEpoch(1, Qt::UTC) << -1 - maxSeconds << QDateTime();
+ << QDateTime::fromSecsSinceEpoch(1, UTC) << -1 - maxSeconds << QDateTime();
}
void tst_QDateTime::addSecs()
@@ -1449,14 +1689,30 @@ void tst_QDateTime::addSecs()
QFETCH(const qint64, nsecs);
QFETCH(const QDateTime, result);
QDateTime test = dt.addSecs(nsecs);
+ QDateTime test2 = dt + std::chrono::seconds(nsecs);
+ QDateTime test3 = dt;
+ test3 += std::chrono::seconds(nsecs);
if (!result.isValid()) {
QVERIFY(!test.isValid());
+ QVERIFY(!test2.isValid());
+ QVERIFY(!test3.isValid());
} else {
QCOMPARE(test, result);
+ QCOMPARE(test2, result);
+ QCOMPARE(test3, result);
QCOMPARE(test.timeSpec(), dt.timeSpec());
- if (test.timeSpec() == Qt::OffsetFromUTC)
+ QCOMPARE(test2.timeSpec(), dt.timeSpec());
+ QCOMPARE(test3.timeSpec(), dt.timeSpec());
+ if (test.timeSpec() == Qt::OffsetFromUTC) {
QCOMPARE(test.offsetFromUtc(), dt.offsetFromUtc());
+ QCOMPARE(test2.offsetFromUtc(), dt.offsetFromUtc());
+ QCOMPARE(test3.offsetFromUtc(), dt.offsetFromUtc());
+ }
QCOMPARE(result.addSecs(-nsecs), dt);
+ QCOMPARE(result - std::chrono::seconds(nsecs), dt);
+ test3 -= std::chrono::seconds(nsecs);
+ QCOMPARE(test3, dt);
+ QCOMPARE(dt.secsTo(result), nsecs);
}
}
@@ -1466,18 +1722,29 @@ void tst_QDateTime::addMSecs()
QFETCH(const qint64, nsecs);
QFETCH(const QDateTime, result);
- QDateTime test = dt.addMSecs(qint64(nsecs) * 1000);
- if (!result.isValid()) {
- QVERIFY(!test.isValid());
- } else {
- QCOMPARE(test, result);
- QCOMPARE(test.timeSpec(), dt.timeSpec());
- if (test.timeSpec() == Qt::OffsetFromUTC)
- QCOMPARE(test.offsetFromUtc(), dt.offsetFromUtc());
- QCOMPARE(result.addMSecs(qint64(-nsecs) * 1000), dt);
- }
+ const auto verify = [&](const QDateTime &test) {
+ if (!result.isValid()) {
+ QVERIFY(!test.isValid());
+ } else {
+ QCOMPARE(test, result);
+ QCOMPARE(test.timeSpec(), dt.timeSpec());
+ if (test.timeSpec() == Qt::OffsetFromUTC)
+ QCOMPARE(test.offsetFromUtc(), dt.offsetFromUtc());
+ QCOMPARE(result.addMSecs(qint64(-nsecs) * 1000), dt);
+ }
+ };
+#define VERIFY(datum) \
+ verify(datum); \
+ if (QTest::currentTestFailed()) \
+ return
+
+ VERIFY(dt.addMSecs(qint64(nsecs) * 1000));
+ VERIFY(dt.addDuration(std::chrono::seconds(nsecs)));
+ VERIFY(dt.addDuration(std::chrono::milliseconds(nsecs * 1000)));
+#undef VERIFY
}
+#if QT_DEPRECATED_SINCE(6, 9)
void tst_QDateTime::toTimeSpec_data()
{
if (!zoneIsCET)
@@ -1490,56 +1757,64 @@ void tst_QDateTime::toTimeSpec_data()
QTime localStandardTime(5, 20, 30);
QTime localDaylightTime(6, 20, 30);
- QTest::newRow("winter1") << QDateTime(QDate(2004, 1, 1), utcTime, Qt::UTC)
- << QDateTime(QDate(2004, 1, 1), localStandardTime, Qt::LocalTime);
- QTest::newRow("winter2") << QDateTime(QDate(2004, 2, 29), utcTime, Qt::UTC)
- << QDateTime(QDate(2004, 2, 29), localStandardTime, Qt::LocalTime);
+ QTest::newRow("winter1")
+ << QDateTime(QDate(2004, 1, 1), utcTime, UTC)
+ << QDateTime(QDate(2004, 1, 1), localStandardTime);
+ QTest::newRow("winter2")
+ << QDateTime(QDate(2004, 2, 29), utcTime, UTC)
+ << QDateTime(QDate(2004, 2, 29), localStandardTime);
QTest::newRow("winter3")
- << QDateTime(QDate(1760, 2, 29), utcTime, Qt::UTC)
+ << QDateTime(QDate(1760, 2, 29), utcTime, UTC)
<< QDateTime(QDate(1760, 2, 29), localStandardTime.addSecs(preZoneFix));
- QTest::newRow("winter4") << QDateTime(QDate(6000, 2, 29), utcTime, Qt::UTC)
- << QDateTime(QDate(6000, 2, 29), localStandardTime, Qt::LocalTime);
+ QTest::newRow("winter4")
+ << QDateTime(QDate(6000, 2, 29), utcTime, UTC)
+ << QDateTime(QDate(6000, 2, 29), localStandardTime);
// Test mktime boundaries (1970 - 2038) and adjustDate().
QTest::newRow("1969/12/31 23:00 UTC")
- << QDateTime(QDate(1969, 12, 31), QTime(23, 0), Qt::UTC)
- << QDateTime(QDate(1970, 1, 1), QTime(0, 0), Qt::LocalTime);
+ << QDateTime(QDate(1969, 12, 31), QTime(23, 0), UTC)
+ << QDateTime(QDate(1970, 1, 1), QTime(0, 0));
QTest::newRow("1969/12/31 23:59:59 UTC")
- << QDateTime(QDate(1969, 12, 31), QTime(23, 59, 59), Qt::UTC)
- << QDateTime(QDate(1970, 1, 1), QTime(0, 59, 59), Qt::LocalTime);
+ << QDateTime(QDate(1969, 12, 31), QTime(23, 59, 59), UTC)
+ << QDateTime(QDate(1970, 1, 1), QTime(0, 59, 59));
QTest::newRow("2037/12/31 23:00 UTC")
- << QDateTime(QDate(2037, 12, 31), QTime(23, 0), Qt::UTC)
- << QDateTime(QDate(2038, 1, 1), QTime(0, 0), Qt::LocalTime);
+ << QDateTime(QDate(2037, 12, 31), QTime(23, 0), UTC)
+ << QDateTime(QDate(2038, 1, 1), QTime(0, 0));
QTest::newRow("-271821/4/20 00:00 UTC (JavaScript min date, start of day)")
- << QDateTime(QDate(-271821, 4, 20), QTime(0, 0), Qt::UTC)
+ << QDateTime(QDate(-271821, 4, 20), QTime(0, 0), UTC)
<< QDateTime(QDate(-271821, 4, 20), QTime(1, 0)).addSecs(preZoneFix);
QTest::newRow("-271821/4/20 23:00 UTC (JavaScript min date, end of day)")
- << QDateTime(QDate(-271821, 4, 20), QTime(23, 0), Qt::UTC)
+ << QDateTime(QDate(-271821, 4, 20), QTime(23, 0), UTC)
<< QDateTime(QDate(-271821, 4, 21), QTime(0, 0)).addSecs(preZoneFix);
if (zoneIsCET) {
- QTest::newRow("summer1") << QDateTime(QDate(2004, 6, 30), utcTime, Qt::UTC)
- << QDateTime(QDate(2004, 6, 30), localDaylightTime, Qt::LocalTime);
+ QTest::newRow("summer1")
+ << QDateTime(QDate(2004, 6, 30), utcTime, UTC)
+ << QDateTime(QDate(2004, 6, 30), localDaylightTime);
QTest::newRow("summer2")
- << QDateTime(QDate(1760, 6, 30), utcTime, Qt::UTC)
+ << QDateTime(QDate(1760, 6, 30), utcTime, UTC)
<< QDateTime(QDate(1760, 6, 30), localStandardTime.addSecs(preZoneFix));
- QTest::newRow("summer3") << QDateTime(QDate(4000, 6, 30), utcTime, Qt::UTC)
- << QDateTime(QDate(4000, 6, 30), localDaylightTime, Qt::LocalTime);
+ QTest::newRow("summer3")
+ << QDateTime(QDate(4000, 6, 30), utcTime, UTC)
+ << QDateTime(QDate(4000, 6, 30), localDaylightTime);
QTest::newRow("275760/9/23 00:00 UTC (JavaScript max date, start of day)")
- << QDateTime(QDate(275760, 9, 23), QTime(0, 0), Qt::UTC)
- << QDateTime(QDate(275760, 9, 23), QTime(2, 0), Qt::LocalTime);
+ << QDate(275760, 9, 23).startOfDay(UTC)
+ << QDateTime(QDate(275760, 9, 23), QTime(2, 0));
QTest::newRow("275760/9/23 22:00 UTC (JavaScript max date, end of day)")
- << QDateTime(QDate(275760, 9, 23), QTime(22, 0), Qt::UTC)
- << QDateTime(QDate(275760, 9, 24), QTime(0, 0), Qt::LocalTime);
+ << QDateTime(QDate(275760, 9, 23), QTime(22, 0), UTC)
+ << QDate(275760, 9, 24).startOfDay();
}
- QTest::newRow("msec") << QDateTime(QDate(4000, 6, 30), utcTime.addMSecs(1), Qt::UTC)
- << QDateTime(QDate(4000, 6, 30), localDaylightTime.addMSecs(1), Qt::LocalTime);
+ QTest::newRow("msec")
+ << QDateTime(QDate(4000, 6, 30), utcTime.addMSecs(1), UTC)
+ << QDateTime(QDate(4000, 6, 30), localDaylightTime.addMSecs(1));
}
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
void tst_QDateTime::toTimeSpec()
{
QFETCH(QDateTime, fromUtc);
@@ -1598,11 +1873,6 @@ void tst_QDateTime::toTimeSpec()
QCOMPARE(localToOffset.toTimeSpec(Qt::LocalTime), fromLocal);
}
-void tst_QDateTime::toLocalTime_data()
-{
- toTimeSpec_data();
-}
-
void tst_QDateTime::toLocalTime()
{
QFETCH(QDateTime, fromUtc);
@@ -1613,11 +1883,6 @@ void tst_QDateTime::toLocalTime()
QCOMPARE(fromUtc.toLocalTime(), fromLocal.toLocalTime());
}
-void tst_QDateTime::toUTC_data()
-{
- toTimeSpec_data();
-}
-
void tst_QDateTime::toUTC()
{
QFETCH(QDateTime, fromUtc);
@@ -1637,6 +1902,8 @@ void tst_QDateTime::toUTC_extra()
QString t = dt.toUTC().toString("zzz");
QCOMPARE(s, t);
}
+QT_WARNING_POP
+#endif // 6.9 deprecation
void tst_QDateTime::daysTo()
{
@@ -1668,11 +1935,11 @@ void tst_QDateTime::secsTo_data()
addSecs_data();
QTest::newRow("disregard milliseconds #1")
- << QDateTime(QDate(2012, 3, 7), QTime(0, 58, 0, 0)) << qint64(60)
+ << QDateTime(QDate(2012, 3, 7), QTime(0, 58)) << qint64(60)
<< QDateTime(QDate(2012, 3, 7), QTime(0, 59, 0, 400));
QTest::newRow("disregard milliseconds #2")
- << QDateTime(QDate(2012, 3, 7), QTime(0, 59, 0, 0)) << qint64(60)
+ << QDateTime(QDate(2012, 3, 7), QTime(0, 59)) << qint64(60)
<< QDateTime(QDate(2012, 3, 7), QTime(1, 0, 0, 400));
}
@@ -1697,11 +1964,6 @@ void tst_QDateTime::secsTo()
}
}
-void tst_QDateTime::msecsTo_data()
-{
- addMSecs_data();
-}
-
void tst_QDateTime::msecsTo()
{
QFETCH(const QDateTime, dt);
@@ -1710,7 +1972,9 @@ void tst_QDateTime::msecsTo()
if (result.isValid()) {
QCOMPARE(dt.msecsTo(result), qint64(nsecs) * 1000);
+ QCOMPARE(result - dt, std::chrono::milliseconds(nsecs * 1000));
QCOMPARE(result.msecsTo(dt), -qint64(nsecs) * 1000);
+ QCOMPARE(dt - result, -std::chrono::milliseconds(nsecs * 1000));
QVERIFY((dt == result) == (0 == (qint64(nsecs) * 1000)));
QVERIFY((dt != result) == (0 != (qint64(nsecs) * 1000)));
QVERIFY((dt < result) == (0 < (qint64(nsecs) * 1000)));
@@ -1719,10 +1983,17 @@ void tst_QDateTime::msecsTo()
QVERIFY((dt >= result) == (0 >= (qint64(nsecs) * 1000)));
} else {
QVERIFY(dt.msecsTo(result) == 0);
+ QCOMPARE(result - dt, std::chrono::milliseconds(0));
QVERIFY(result.msecsTo(dt) == 0);
+ QCOMPARE(dt - result, std::chrono::milliseconds(0));
}
}
+void tst_QDateTime::orderingCompiles()
+{
+ QTestPrivate::testAllComparisonOperatorsCompile<QDateTime>();
+}
+
void tst_QDateTime::currentDateTime()
{
time_t buf1, buf2;
@@ -1742,30 +2013,32 @@ void tst_QDateTime::currentDateTime()
// 1 second difference from the more accurate method used by QDateTime::currentDateTime()
upperBound = upperBound.addSecs(2);
- QString details = QString("\n"
- "lowerBound: %1\n"
- "dt1: %2\n"
- "dt2: %3\n"
- "dt3: %4\n"
- "upperBound: %5\n")
- .arg(lowerBound.toSecsSinceEpoch())
- .arg(dt1.toSecsSinceEpoch())
- .arg(dt2.toSecsSinceEpoch())
- .arg(dt3.toSecsSinceEpoch())
- .arg(upperBound.toSecsSinceEpoch());
+ auto reporter = qScopeGuard([=]() {
+ qInfo("\n"
+ "lowerBound: %lld\n"
+ "dt1: %lld\n"
+ "dt2: %lld\n"
+ "dt3: %lld\n"
+ "upperBound: %lld\n",
+ lowerBound.toSecsSinceEpoch(),
+ dt1.toSecsSinceEpoch(),
+ dt2.toSecsSinceEpoch(),
+ dt3.toSecsSinceEpoch(),
+ upperBound.toSecsSinceEpoch());
+ });
+
+ QCOMPARE_LT(lowerBound, upperBound);
+ QCOMPARE_LE(lowerBound, dt1);
+ QCOMPARE_LT(dt1, upperBound);
+ QCOMPARE_LE(lowerBound, dt2);
+ QCOMPARE_LT(dt2, upperBound);
+ QCOMPARE_LE(lowerBound, dt3);
+ QCOMPARE_LT(dt3, upperBound);
+ reporter.dismiss();
- QVERIFY2(lowerBound < upperBound, qPrintable(details));
-
- QVERIFY2(lowerBound <= dt1, qPrintable(details));
- QVERIFY2(dt1 < upperBound, qPrintable(details));
- QVERIFY2(lowerBound <= dt2, qPrintable(details));
- QVERIFY2(dt2 < upperBound, qPrintable(details));
- QVERIFY2(lowerBound <= dt3, qPrintable(details));
- QVERIFY2(dt3 < upperBound, qPrintable(details));
-
- QVERIFY(dt1.timeSpec() == Qt::LocalTime);
- QVERIFY(dt2.timeSpec() == Qt::LocalTime);
- QVERIFY(dt3.timeSpec() == Qt::UTC);
+ QCOMPARE(dt1.timeSpec(), Qt::LocalTime);
+ QCOMPARE(dt2.timeSpec(), Qt::LocalTime);
+ QCOMPARE(dt3.timeSpec(), Qt::UTC);
}
void tst_QDateTime::currentDateTimeUtc()
@@ -1788,30 +2061,32 @@ void tst_QDateTime::currentDateTimeUtc()
// 1 second difference from the more accurate method used by QDateTime::currentDateTime()
upperBound = upperBound.addSecs(2);
- QString details = QString("\n"
- "lowerBound: %1\n"
- "dt1: %2\n"
- "dt2: %3\n"
- "dt3: %4\n"
- "upperBound: %5\n")
- .arg(lowerBound.toSecsSinceEpoch())
- .arg(dt1.toSecsSinceEpoch())
- .arg(dt2.toSecsSinceEpoch())
- .arg(dt3.toSecsSinceEpoch())
- .arg(upperBound.toSecsSinceEpoch());
+ auto reporter = qScopeGuard([=]() {
+ qInfo("\n"
+ "lowerBound: %lld\n"
+ "dt1: %lld\n"
+ "dt2: %lld\n"
+ "dt3: %lld\n"
+ "upperBound: %lld\n",
+ lowerBound.toSecsSinceEpoch(),
+ dt1.toSecsSinceEpoch(),
+ dt2.toSecsSinceEpoch(),
+ dt3.toSecsSinceEpoch(),
+ upperBound.toSecsSinceEpoch());
+ });
+
+ QCOMPARE_LT(lowerBound, upperBound);
+ QCOMPARE_LE(lowerBound, dt1);
+ QCOMPARE_LT(dt1, upperBound);
+ QCOMPARE_LE(lowerBound, dt2);
+ QCOMPARE_LT(dt2, upperBound);
+ QCOMPARE_LE(lowerBound, dt3);
+ QCOMPARE_LT(dt3, upperBound);
+ reporter.dismiss();
- QVERIFY2(lowerBound < upperBound, qPrintable(details));
-
- QVERIFY2(lowerBound <= dt1, qPrintable(details));
- QVERIFY2(dt1 < upperBound, qPrintable(details));
- QVERIFY2(lowerBound <= dt2, qPrintable(details));
- QVERIFY2(dt2 < upperBound, qPrintable(details));
- QVERIFY2(lowerBound <= dt3, qPrintable(details));
- QVERIFY2(dt3 < upperBound, qPrintable(details));
-
- QVERIFY(dt1.timeSpec() == Qt::UTC);
- QVERIFY(dt2.timeSpec() == Qt::LocalTime);
- QVERIFY(dt3.timeSpec() == Qt::UTC);
+ QCOMPARE(dt1.timeSpec(), Qt::UTC);
+ QCOMPARE(dt2.timeSpec(), Qt::LocalTime);
+ QCOMPARE(dt3.timeSpec(), Qt::UTC);
}
void tst_QDateTime::currentDateTimeUtc2()
@@ -1910,7 +2185,7 @@ void tst_QDateTime::daylightSavingsTimeChange()
QFETCH(int, months);
// First with simple construction
- QDateTime dt = QDateTime(outDST, QTime(0, 0, 0), Qt::LocalTime);
+ QDateTime dt = outDST.startOfDay();
int outDSTsecs = dt.toSecsSinceEpoch();
dt.setDate(inDST);
@@ -1935,29 +2210,29 @@ void tst_QDateTime::daylightSavingsTimeChange()
// now using fromSecsSinceEpoch
dt = QDateTime::fromSecsSinceEpoch(outDSTsecs);
- QCOMPARE(dt, QDateTime(outDST, QTime(0, 0, 0)));
+ QCOMPARE(dt, outDST.startOfDay());
dt.setDate(inDST);
dt = dt.addSecs(60);
- QCOMPARE(dt, QDateTime(inDST, QTime(0, 1, 0)));
+ QCOMPARE(dt, QDateTime(inDST, QTime(0, 1)));
// using addMonths:
dt = dt.addMonths(months).addSecs(60);
- QCOMPARE(dt, QDateTime(outDST, QTime(0, 2, 0)));
+ QCOMPARE(dt, QDateTime(outDST, QTime(0, 2)));
// back again:
dt = dt.addMonths(-months).addSecs(60);
- QCOMPARE(dt, QDateTime(inDST, QTime(0, 3, 0)));
+ QCOMPARE(dt, QDateTime(inDST, QTime(0, 3)));
// using addDays:
dt = dt.addDays(days).addSecs(60);
- QCOMPARE(dt, QDateTime(outDST, QTime(0, 4, 0)));
+ QCOMPARE(dt, QDateTime(outDST, QTime(0, 4)));
// back again:
dt = dt.addDays(-days).addSecs(60);
- QCOMPARE(dt, QDateTime(inDST, QTime(0, 5, 0)));
+ QCOMPARE(dt, QDateTime(inDST, QTime(0, 5)));
// Now use the result of a UTC -> LocalTime conversion
- dt = QDateTime(outDST, QTime(0, 0), Qt::LocalTime).toUTC();
- dt = QDateTime(dt.date(), dt.time(), Qt::UTC).toLocalTime();
+ dt = outDST.startOfDay().toUTC();
+ dt = QDateTime(dt.date(), dt.time(), UTC).toLocalTime();
QCOMPARE(dt, QDateTime(outDST, QTime(0, 0)));
// using addDays:
@@ -1982,6 +2257,7 @@ void tst_QDateTime::daylightSavingsTimeChange()
void tst_QDateTime::springForward_data()
{
+ QTest::addColumn<QTimeZone>("zone");
QTest::addColumn<QDate>("day"); // day of DST transition
QTest::addColumn<QTime>("time"); // in the "missing hour"
QTest::addColumn<int>("step"); // days to step; +ve from before, -ve from after
@@ -1995,67 +2271,136 @@ void tst_QDateTime::springForward_data()
document any such conflicts, if discovered.
See http://www.timeanddate.com/time/zones/ for data on more candidates to
- test.
- */
+ test. Note, however, that the IANA DB disagrees with it for some zones,
+ and is authoritative.
+ */
- uint winter = QDate(2015, 1, 1).startOfDay().toSecsSinceEpoch();
- uint summer = QDate(2015, 7, 1).startOfDay().toSecsSinceEpoch();
+ const QTimeZone local(QTimeZone::LocalTime);
+ const uint winter = QDate(2015, 1, 1).startOfDay(local).toSecsSinceEpoch();
+ const uint summer = QDate(2015, 7, 1).startOfDay(local).toSecsSinceEpoch();
if (winter == 1420066800 && summer == 1435701600) {
- QTest::newRow("CET from day before") << QDate(2015, 3, 29) << QTime(2, 30, 0) << 1 << 60;
- QTest::newRow("CET from day after") << QDate(2015, 3, 29) << QTime(2, 30, 0) << -1 << 120;
+ QTest::newRow("Local (CET) from day before")
+ << local << QDate(2015, 3, 29) << QTime(2, 30) << 1 << 60;
+ QTest::newRow("Local (CET) from day after")
+ << local << QDate(2015, 3, 29) << QTime(2, 30) << -1 << 120;
} else if (winter == 1420063200 && summer == 1435698000) {
- // e.g. Finland, where our CI runs ...
- QTest::newRow("EET from day before") << QDate(2015, 3, 29) << QTime(3, 30, 0) << 1 << 120;
- QTest::newRow("EET from day after") << QDate(2015, 3, 29) << QTime(3, 30, 0) << -1 << 180;
+ // EET: but there's some variation in the date and time.
+ // Asia/{Amman,Beirut,Gaza,Hebron}, Europe/Chisinau and Israel: at start of
+ QDate date(2015, 3, 29); // Sunday by default.
+ QTime time(0, 30);
+ if (auto thursday = QDate(2015, 3, 26); thursday.startOfDay(local).time() > time) {
+ // Asia/Damascus: start of March 26th.
+ date = thursday;
+ } else if (auto friday = QDate(2015, 3, 27); friday.startOfDay(local).time() > time) {
+ // Israel, Asia/{Jerusalem,Tel_Aviv}: start of March 27th (IANA DB).
+ date = friday;
+ } else if (friday.startOfDay(local).addSecs(2 * 60 * 60).time() == QTime(3, 0)) {
+ // Israel, Asia/{Jerusalem,Tel_Aviv} according to glibc at 02:00 on March 27th.
+ date = friday;
+ time = QTime(2, 30);
+ } else if (date.startOfDay(local).time() < time) {
+ // Most of Europeean EET, e.g. Finland.
+ time = QTime(3, 30);
+ }
+ QTest::newRow("Local (EET) from day before")
+ << local << date << time << 1 << 120;
+ QTest::newRow("Local (EET) from day after")
+ << local << date << time << -1 << 180;
} else if (winter == 1420070400 && summer == 1435705200) {
// Western European Time, WET/WEST; a.k.a. GMT/BST
- QTest::newRow("WET from day before") << QDate(2015, 3, 29) << QTime(1, 30, 0) << 1 << 0;
- QTest::newRow("WET from day after") << QDate(2015, 3, 29) << QTime(1, 30, 0) << -1 << 60;
+ QTest::newRow("Local (WET) from day before")
+ << local << QDate(2015, 3, 29) << QTime(1, 30) << 1 << 0;
+ QTest::newRow("Local (WET) from day after")
+ << local << QDate(2015, 3, 29) << QTime(1, 30) << -1 << 60;
} else if (winter == 1420099200 && summer == 1435734000) {
// Western USA, Canada: Pacific Time (e.g. US/Pacific)
- QTest::newRow("PT from day before") << QDate(2015, 3, 8) << QTime(2, 30, 0) << 1 << -480;
- QTest::newRow("PT from day after") << QDate(2015, 3, 8) << QTime(2, 30, 0) << -1 << -420;
+ QDate date(2015, 3, 8);
+ // America/Ensenada did its transition on April 5th, like the rest of Mexico.
+ if (QDate(2015, 4, 1).startOfDay().toSecsSinceEpoch() == 1427875200)
+ date = QDate(2015, 4, 5);
+ QTest::newRow("Local (PT) from day before")
+ << local << date << QTime(2, 30) << 1 << -480;
+ QTest::newRow("Local (PT) from day after")
+ << local << date << QTime(2, 30) << -1 << -420;
} else if (winter == 1420088400 && summer == 1435723200) {
// Eastern USA, Canada: Eastern Time (e.g. US/Eastern)
- QTest::newRow("ET from day before") << QDate(2015, 3, 8) << QTime(2, 30, 0) << 1 << -300;
- QTest::newRow("ET from day after") << QDate(2015, 3, 8) << QTime(2, 30, 0) << -1 << -240;
+ // Havana matches offset and date, but at midnight.
+ const QTime start = QDate(2015, 3, 8).startOfDay(local).time();
+ const QTime when = start == QTime(0, 0) ? QTime(2, 30) : QTime(0, 30);
+ QTest::newRow("Local(ET) from day before")
+ << local << QDate(2015, 3, 8) << when << 1 << -300;
+ QTest::newRow("Local(ET) from day after")
+ << local << QDate(2015, 3, 8) << when << -1 << -240;
+#if !QT_CONFIG(timezone)
} else {
// Includes the numbers you need to test for your zone, as above:
QString msg(QString::fromLatin1("No spring forward test data for this TZ (%1, %2)"
).arg(winter).arg(summer));
QSKIP(qPrintable(msg));
+#endif
+ }
+#if QT_CONFIG(timezone)
+ if (const QTimeZone cet("Europe/Oslo"); cet.isValid()) {
+ QTest::newRow("CET from day before")
+ << cet << QDate(2015, 3, 29) << QTime(2, 30) << 1 << 60;
+ QTest::newRow("CET from day after")
+ << cet << QDate(2015, 3, 29) << QTime(2, 30) << -1 << 120;
+ }
+ if (const QTimeZone eet("Europe/Helsinki"); eet.isValid()) {
+ QTest::newRow("EET from day before")
+ << eet << QDate(2015, 3, 29) << QTime(3, 30) << 1 << 120;
+ QTest::newRow("EET from day after")
+ << eet << QDate(2015, 3, 29) << QTime(3, 30) << -1 << 180;
+ }
+ if (const QTimeZone wet("Europe/Lisbon"); wet.isValid()) {
+ QTest::newRow("WET from day before")
+ << wet << QDate(2015, 3, 29) << QTime(1, 30) << 1 << 0;
+ QTest::newRow("WET from day after")
+ << wet << QDate(2015, 3, 29) << QTime(1, 30) << -1 << 60;
+ }
+ if (const QTimeZone pacific("America/Vancouver"); pacific.isValid()) {
+ QTest::newRow("PT from day before")
+ << pacific << QDate(2015, 3, 8) << QTime(2, 30) << 1 << -480;
+ QTest::newRow("PT from day after")
+ << pacific << QDate(2015, 3, 8) << QTime(2, 30) << -1 << -420;
+ }
+ if (const QTimeZone eastern("America/Ottawa"); eastern.isValid()) {
+ QTest::newRow("ET from day before")
+ << eastern << QDate(2015, 3, 8) << QTime(2, 30) << 1 << -300;
+ QTest::newRow("ET from day after")
+ << eastern << QDate(2015, 3, 8) << QTime(2, 30) << -1 << -240;
}
+#endif
}
void tst_QDateTime::springForward()
{
+ QFETCH(QTimeZone, zone);
QFETCH(QDate, day);
QFETCH(QTime, time);
QFETCH(int, step);
QFETCH(int, adjust);
- QDateTime direct = QDateTime(day.addDays(-step), time, Qt::LocalTime).addDays(step);
- if (direct.isValid()) { // mktime() may deem a time in the gap invalid
- QCOMPARE(direct.date(), day);
- QCOMPARE(direct.time().minute(), time.minute());
- QCOMPARE(direct.time().second(), time.second());
- int off = direct.time().hour() - time.hour();
- QVERIFY(off == 1 || off == -1);
- // Note: function doc claims always +1, but this should be reviewed !
- }
-
- // Repeat, but getting there via .toLocalTime():
- QDateTime detour = QDateTime(day.addDays(-step),
- time.addSecs(-60 * adjust),
- Qt::UTC).toLocalTime();
+ QDateTime direct = QDateTime(day.addDays(-step), time, zone).addDays(step);
+ QVERIFY(direct.isValid());
+ QCOMPARE(direct.date(), day);
+ QCOMPARE(direct.time().minute(), time.minute());
+ QCOMPARE(direct.time().second(), time.second());
+ const int off = step < 0 ? -1 : 1;
+ QCOMPARE(direct.time().hour() - time.hour(), off);
+ // adjust is the offset on the other side of the gap:
+ QCOMPARE(direct.offsetFromUtc(), (adjust + off * 60) * 60);
+
+ // Repeat, but getting there via .toTimeZone(). Apply adjust to datetime,
+ // not time, as the time wraps round if the adjustment crosses midnight.
+ QDateTime detour = QDateTime(day.addDays(-step), time,
+ UTC).addSecs(-60 * adjust).toTimeZone(zone);
QCOMPARE(detour.time(), time);
detour = detour.addDays(step);
// Insist on consistency:
- if (direct.isValid())
- QCOMPARE(detour, direct);
- else
- QVERIFY(!detour.isValid());
+ QCOMPARE(detour, direct);
+ QCOMPARE(detour.offsetFromUtc(), direct.offsetFromUtc());
}
void tst_QDateTime::operator_eqeq_data()
@@ -2069,14 +2414,14 @@ void tst_QDateTime::operator_eqeq_data()
QDateTime dateTime1a = dateTime1.addMSecs(1);
QDateTime dateTime2(QDate(2012, 20, 6), QTime(14, 33, 2, 500)); // Invalid
QDateTime dateTime2a = dateTime2.addMSecs(-1); // Still invalid
- QDateTime dateTime3(QDate(1970, 1, 1), QTime(0, 0), Qt::UTC); // UTC epoch
+ QDateTime dateTime3(QDate(1970, 1, 1), QTime(0, 0), UTC); // UTC epoch
QDateTime dateTime3a = dateTime3.addDays(1);
QDateTime dateTime3b = dateTime3.addDays(-1);
// Ensure that different times may be equal when considering timezone.
QDateTime dateTime3c(dateTime3.addSecs(3600));
- dateTime3c.setOffsetFromUtc(3600);
+ dateTime3c.setTimeZone(QTimeZone::fromSecondsAheadOfUtc(3600));
QDateTime dateTime3d(dateTime3.addSecs(-3600));
- dateTime3d.setOffsetFromUtc(-3600);
+ dateTime3d.setTimeZone(QTimeZone::fromSecondsAheadOfUtc(-3600));
QDateTime dateTime3e(dateTime3.date(), dateTime3.time()); // Local time's epoch
QTest::newRow("data0") << dateTime1 << dateTime1 << true << false;
@@ -2092,7 +2437,7 @@ void tst_QDateTime::operator_eqeq_data()
QTest::newRow("data10") << dateTime3 << dateTime3c << true << false;
QTest::newRow("data11") << dateTime3 << dateTime3d << true << false;
QTest::newRow("data12") << dateTime3c << dateTime3d << true << false;
- if (localTimeType == LocalTimeIsUtc)
+ if (epochTimeType == LocalTimeIsUtc)
QTest::newRow("data13") << dateTime3 << dateTime3e << true << false;
// ... but a zone (sometimes) ahead of or behind UTC (e.g. Europe/London)
// might agree with UTC about the epoch, all the same.
@@ -2102,8 +2447,8 @@ void tst_QDateTime::operator_eqeq_data()
if (zoneIsCET) {
QTest::newRow("data14")
- << QDateTime(QDate(2004, 1, 2), QTime(2, 2, 3), Qt::LocalTime)
- << QDateTime(QDate(2004, 1, 2), QTime(1, 2, 3), Qt::UTC) << true << true;
+ << QDateTime(QDate(2004, 1, 2), QTime(2, 2, 3))
+ << QDateTime(QDate(2004, 1, 2), QTime(1, 2, 3), UTC) << true << true;
QTest::newRow("local-fall-back") // Sun, 31 Oct 2004, 02:30, both ways round:
<< QDateTime::fromMSecsSinceEpoch(Q_INT64_C(1099186200000))
<< QDateTime::fromMSecsSinceEpoch(Q_INT64_C(1099182600000))
@@ -2127,23 +2472,16 @@ void tst_QDateTime::operator_eqeq()
QFETCH(bool, expectEqual);
QFETCH(bool, checkEuro);
- QVERIFY(dt1 == dt1);
- QVERIFY(!(dt1 != dt1));
-
- QVERIFY(dt2 == dt2);
- QVERIFY(!(dt2 != dt2));
+ QT_TEST_EQUALITY_OPS(dt1, dt1, true);
+ QT_TEST_EQUALITY_OPS(dt2, dt2, true);
+ QT_TEST_EQUALITY_OPS(dt1, dt2, expectEqual);
QVERIFY(dt1 != QDateTime::currentDateTime());
QVERIFY(dt2 != QDateTime::currentDateTime());
QVERIFY(dt1.toUTC() == dt1.toUTC());
- bool equal = dt1 == dt2;
- QCOMPARE(equal, expectEqual);
- bool notEqual = dt1 != dt2;
- QCOMPARE(notEqual, !expectEqual);
-
- if (equal)
+ if (expectEqual)
QVERIFY(qHash(dt1) == qHash(dt2));
if (checkEuro && zoneIsCET) {
@@ -2152,6 +2490,64 @@ void tst_QDateTime::operator_eqeq()
}
}
+void tst_QDateTime::ordering_data()
+{
+ QTest::addColumn<QDateTime>("left");
+ QTest::addColumn<QDateTime>("right");
+ QTest::addColumn<Qt::weak_ordering>("expectedOrdering");
+
+ Q_CONSTINIT static const auto constructName = [](const QDateTime &dt) -> QByteArray {
+ if (dt.isNull())
+ return "null";
+ if (!dt.isValid())
+ return "invalid";
+ return dt.toString(Qt::ISODateWithMs).toLatin1();
+ };
+
+ Q_CONSTINIT static const auto generateRow =
+ [](const QDateTime &left, const QDateTime &right, Qt::weak_ordering ordering) {
+ const QByteArray leftStr = constructName(left);
+ const QByteArray rightStr = constructName(right);
+ QTest::addRow("%s_vs_%s", leftStr.constData(), rightStr.constData())
+ << left << right << ordering;
+ };
+
+ QDateTime june(QDate(2012, 6, 20), QTime(14, 33, 2, 500));
+ QDateTime juneLater = june.addMSecs(1);
+ QDateTime badDay(QDate(2012, 20, 6), QTime(14, 33, 2, 500)); // Invalid
+ QDateTime epoch(QDate(1970, 1, 1), QTime(0, 0), UTC); // UTC epoch
+ QDateTime nextDay = epoch.addDays(1);
+ QDateTime prevDay = epoch.addDays(-1);
+ // Ensure that different times may be equal when considering timezone.
+ QDateTime epochEast1h(epoch.addSecs(3600));
+ epochEast1h.setTimeZone(QTimeZone::fromSecondsAheadOfUtc(3600));
+ QDateTime epochWest1h(epoch.addSecs(-3600));
+ epochWest1h.setTimeZone(QTimeZone::fromSecondsAheadOfUtc(-3600));
+ QDateTime local1970(epoch.date(), epoch.time()); // Local time's epoch
+
+ generateRow(june, june, Qt::weak_ordering::equivalent);
+ generateRow(june, juneLater, Qt::weak_ordering::less);
+ generateRow(june, badDay, Qt::weak_ordering::greater);
+ generateRow(badDay, QDateTime(), Qt::weak_ordering::equivalent);
+ generateRow(june, QDateTime(), Qt::weak_ordering::greater);
+ generateRow(epoch, nextDay, Qt::weak_ordering::less);
+ generateRow(epoch, prevDay, Qt::weak_ordering::greater);
+ generateRow(epoch, epochEast1h, Qt::weak_ordering::equivalent);
+ generateRow(epoch, epochWest1h, Qt::weak_ordering::equivalent);
+ generateRow(epochEast1h, epochWest1h, Qt::weak_ordering::equivalent);
+ if (epochTimeType == LocalTimeIsUtc)
+ generateRow(epoch, local1970, Qt::weak_ordering::equivalent);
+}
+
+void tst_QDateTime::ordering()
+{
+ QFETCH(QDateTime, left);
+ QFETCH(QDateTime, right);
+ QFETCH(Qt::weak_ordering, expectedOrdering);
+
+ QT_TEST_ALL_COMPARISON_OPS(left, right, expectedOrdering);
+}
+
Q_DECLARE_METATYPE(QDataStream::Version)
void tst_QDateTime::operator_insert_extract_data()
@@ -2191,7 +2587,7 @@ void tst_QDateTime::operator_insert_extract()
TimeZoneRollback useZone(serialiseAs);
// It is important that dateTime is created after the time zone shift
- QDateTime dateTime(QDate(yearNumber, 8, 14), QTime(8, 0), Qt::LocalTime);
+ QDateTime dateTime(QDate(yearNumber, 8, 14), QTime(8, 0));
QDateTime dateTimeAsUTC(dateTime.toUTC());
QByteArray byteArray;
@@ -2217,7 +2613,8 @@ void tst_QDateTime::operator_insert_extract()
// Ensure that a change in timezone between serialisation and deserialisation
// still results in identical UTC-converted datetimes.
useZone.reset(deserialiseAs);
- QDateTime expectedLocalTime(dateTimeAsUTC.toLocalTime());
+ QDateTime expectedLocalTime(dateTimeAsUTC.toLocalTime()); // *After* resetting zone.
+ QCOMPARE(expectedLocalTime, dateTimeAsUTC); // Different description, same moment in time.
{
// Deserialise whole QDateTime at once.
QDataStream dataStream(&byteArray, QIODevice::ReadOnly);
@@ -2233,7 +2630,7 @@ void tst_QDateTime::operator_insert_extract()
if (dataStreamVersion < QDataStream::Qt_4_0) {
// Versions lower than Qt 4 don't serialise the timeSpec, instead
// assuming that everything is LocalTime.
- deserialised.setTimeSpec(Qt::UTC);
+ deserialised.setTimeZone(UTC);
}
// Qt 4.* versions do serialise the timeSpec, so we only need to convert from UTC here.
deserialised = deserialised.toLocalTime();
@@ -2251,9 +2648,17 @@ void tst_QDateTime::operator_insert_extract()
qint8 deserialisedSpec;
if (dataStreamVersion >= QDataStream::Qt_4_0)
dataStream >> deserialisedSpec;
- deserialised = QDateTime(deserialisedDate, deserialisedTime, Qt::UTC);
- if (dataStreamVersion >= QDataStream::Qt_4_0)
- deserialised = deserialised.toTimeSpec(static_cast<Qt::TimeSpec>(deserialisedSpec));
+ deserialised = QDateTime(deserialisedDate, deserialisedTime, UTC);
+ QCOMPARE(deserialised.toLocalTime(), deserialised);
+ const auto isLocalTime = [](qint8 spec) -> bool {
+ // The spec is in fact a QDateTimePrivate::Spec, not Qt::TimeSpec;
+ // and no offset or zone is stored, so only UTC and LocalTime are
+ // really supported. Fortunately this test only uses those.
+ const auto decoded = static_cast<QDateTimePrivate::Spec>(spec);
+ return decoded != QDateTimePrivate::UTC && decoded != QDateTimePrivate::OffsetFromUTC;
+ };
+ if (dataStreamVersion >= QDataStream::Qt_4_0 && isLocalTime(deserialisedSpec))
+ deserialised = deserialised.toTimeZone(QTimeZone::LocalTime);
// Ensure local time is still correct.
QCOMPARE(deserialised, expectedLocalTime);
// Sanity check UTC times.
@@ -2276,54 +2681,61 @@ void tst_QDateTime::fromStringDateFormat_data()
QTest::addColumn<Qt::DateFormat>("dateFormat");
QTest::addColumn<QDateTime>("expected");
+ // Fails 1970 start dates in western Mexico
+ // due to changing from PST to MST at the start of 1970.
+ const bool goodEpochStart = QDateTime(QDate(1970, 1, 1), QTime(0, 0)).isValid();
+
// Test Qt::TextDate format.
QTest::newRow("text date") << QString::fromLatin1("Tue Jun 17 08:00:10 2003")
- << Qt::TextDate << QDateTime(QDate(2003, 6, 17), QTime(8, 0, 10, 0), Qt::LocalTime);
+ << Qt::TextDate << QDateTime(QDate(2003, 6, 17), QTime(8, 0, 10));
QTest::newRow("text date Year 0999") << QString::fromLatin1("Tue Jun 17 08:00:10 0999")
- << Qt::TextDate << QDateTime(QDate(999, 6, 17), QTime(8, 0, 10, 0), Qt::LocalTime);
+ << Qt::TextDate << QDateTime(QDate(999, 6, 17), QTime(8, 0, 10));
QTest::newRow("text date Year 999") << QString::fromLatin1("Tue Jun 17 08:00:10 999")
- << Qt::TextDate << QDateTime(QDate(999, 6, 17), QTime(8, 0, 10, 0), Qt::LocalTime);
+ << Qt::TextDate << QDateTime(QDate(999, 6, 17), QTime(8, 0, 10));
QTest::newRow("text date Year 12345") << QString::fromLatin1("Tue Jun 17 08:00:10 12345")
- << Qt::TextDate << QDateTime(QDate(12345, 6, 17), QTime(8, 0, 10, 0), Qt::LocalTime);
+ << Qt::TextDate << QDateTime(QDate(12345, 6, 17), QTime(8, 0, 10));
QTest::newRow("text date Year -4712") << QString::fromLatin1("Tue Jan 1 00:01:02 -4712")
- << Qt::TextDate << QDateTime(QDate(-4712, 1, 1), QTime(0, 1, 2, 0), Qt::LocalTime);
- QTest::newRow("text epoch")
- << QString::fromLatin1("Thu Jan 1 00:00:00 1970") << Qt::TextDate
- << QDateTime(QDate(1970, 1, 1), QTime(0, 0), Qt::LocalTime);
+ << Qt::TextDate << QDateTime(QDate(-4712, 1, 1), QTime(0, 1, 2));
QTest::newRow("text data1") << QString::fromLatin1("Thu Jan 2 12:34 1970")
- << Qt::TextDate << QDateTime(QDate(1970, 1, 2), QTime(12, 34, 0), Qt::LocalTime);
+ << Qt::TextDate << QDateTime(QDate(1970, 1, 2), QTime(12, 34));
+ if (goodEpochStart) {
+ QTest::newRow("text epoch year after time")
+ << QString::fromLatin1("Thu Jan 1 00:00:00 1970") << Qt::TextDate
+ << QDate(1970, 1, 1).startOfDay();
+ QTest::newRow("text epoch spaced")
+ << QString::fromLatin1(" Thu Jan 1 00:00:00 1970 ")
+ << Qt::TextDate << QDate(1970, 1, 1).startOfDay();
+ QTest::newRow("text epoch time after year")
+ << QString::fromLatin1("Thu Jan 1 1970 00:00:00")
+ << Qt::TextDate << QDate(1970, 1, 1).startOfDay();
+ }
QTest::newRow("text epoch terse")
<< QString::fromLatin1("Thu Jan 1 00 1970") << Qt::TextDate << QDateTime();
QTest::newRow("text epoch stray :00")
<< QString::fromLatin1("Thu Jan 1 00:00:00:00 1970") << Qt::TextDate << QDateTime();
- QTest::newRow("text epoch spaced")
- << QString::fromLatin1(" Thu Jan 1 00:00:00 1970 ")
- << Qt::TextDate << QDateTime(QDate(1970, 1, 1), QTime(0, 0), Qt::LocalTime);
QTest::newRow("text data6") << QString::fromLatin1("Thu Jan 1 00:00:00")
<< Qt::TextDate << QDateTime();
- QTest::newRow("text data7") << QString::fromLatin1("Thu Jan 1 1970 00:00:00")
- << Qt::TextDate << QDateTime(QDate(1970, 1, 1), QTime(0, 0), Qt::LocalTime);
QTest::newRow("text bad offset") << QString::fromLatin1("Thu Jan 1 00:12:34 1970 UTC+foo")
<< Qt::TextDate << QDateTime();
QTest::newRow("text UTC early") << QString::fromLatin1("Thu Jan 1 00:12:34 1970 UTC")
- << Qt::TextDate << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ << Qt::TextDate << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), UTC);
QTest::newRow("text UTC-3 early") << QString::fromLatin1("Thu Jan 1 00:12:34 1970 UTC-0300")
- << Qt::TextDate << QDateTime(QDate(1970, 1, 1), QTime(3, 12, 34), Qt::UTC);
+ << Qt::TextDate << QDateTime(QDate(1970, 1, 1), QTime(3, 12, 34), UTC);
QTest::newRow("text UTC+3 early") << QString::fromLatin1("Thu Jan 1 00:12:34 1970 UTC+0300")
- << Qt::TextDate << QDateTime(QDate(1969, 12, 31), QTime(21, 12, 34), Qt::UTC);
+ << Qt::TextDate << QDateTime(QDate(1969, 12, 31), QTime(21, 12, 34), UTC);
QTest::newRow("text UTC+1 early") << QString::fromLatin1("Thu Jan 1 1970 00:12:34 UTC+0100")
- << Qt::TextDate << QDateTime(QDate(1969, 12, 31), QTime(23, 12, 34), Qt::UTC);
+ << Qt::TextDate << QDateTime(QDate(1969, 12, 31), QTime(23, 12, 34), UTC);
// We produce use GMT as prefix, so need to parse it:
QTest::newRow("text GMT early")
<< QString::fromLatin1("Thu Jan 1 00:12:34 1970 GMT") << Qt::TextDate
- << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), UTC);
QTest::newRow("text GMT+3 early")
<< QString::fromLatin1("Thu Jan 1 00:12:34 1970 GMT+0300") << Qt::TextDate
- << QDateTime(QDate(1969, 12, 31), QTime(21, 12, 34), Qt::UTC);
+ << QDateTime(QDate(1969, 12, 31), QTime(21, 12, 34), UTC);
// ... and we match (only) it case-insensitively:
QTest::newRow("text gmt early")
<< QString::fromLatin1("Thu Jan 1 00:12:34 1970 gmt") << Qt::TextDate
- << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), UTC);
QTest::newRow("text empty") << QString::fromLatin1("")
<< Qt::TextDate << QDateTime();
@@ -2419,83 +2831,95 @@ void tst_QDateTime::fromStringDateFormat_data()
// Normal usage:
QTest::newRow("ISO +01:00") << QString::fromLatin1("1987-02-13T13:24:51+01:00")
- << Qt::ISODate << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), Qt::UTC);
+ << Qt::ISODate << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), UTC);
QTest::newRow("ISO +00:01") << QString::fromLatin1("1987-02-13T13:24:51+00:01")
- << Qt::ISODate << QDateTime(QDate(1987, 2, 13), QTime(13, 23, 51), Qt::UTC);
+ << Qt::ISODate << QDateTime(QDate(1987, 2, 13), QTime(13, 23, 51), UTC);
QTest::newRow("ISO -01:00") << QString::fromLatin1("1987-02-13T13:24:51-01:00")
- << Qt::ISODate << QDateTime(QDate(1987, 2, 13), QTime(14, 24, 51), Qt::UTC);
+ << Qt::ISODate << QDateTime(QDate(1987, 2, 13), QTime(14, 24, 51), UTC);
QTest::newRow("ISO -00:01") << QString::fromLatin1("1987-02-13T13:24:51-00:01")
- << Qt::ISODate << QDateTime(QDate(1987, 2, 13), QTime(13, 25, 51), Qt::UTC);
+ << Qt::ISODate << QDateTime(QDate(1987, 2, 13), QTime(13, 25, 51), UTC);
QTest::newRow("ISO +0000") << QString::fromLatin1("1970-01-01T00:12:34+0000")
- << Qt::ISODate << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ << Qt::ISODate << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), UTC);
QTest::newRow("ISO +00:00") << QString::fromLatin1("1970-01-01T00:12:34+00:00")
- << Qt::ISODate << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ << Qt::ISODate << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), UTC);
QTest::newRow("ISO -03") << QString::fromLatin1("2014-12-15T12:37:09-03")
- << Qt::ISODate << QDateTime(QDate(2014, 12, 15), QTime(15, 37, 9), Qt::UTC);
+ << Qt::ISODate << QDateTime(QDate(2014, 12, 15), QTime(15, 37, 9), UTC);
QTest::newRow("ISO zzz-03") << QString::fromLatin1("2014-12-15T12:37:09.745-03")
- << Qt::ISODate << QDateTime(QDate(2014, 12, 15), QTime(15, 37, 9, 745), Qt::UTC);
+ << Qt::ISODate << QDateTime(QDate(2014, 12, 15), QTime(15, 37, 9, 745), UTC);
QTest::newRow("ISO -3") << QString::fromLatin1("2014-12-15T12:37:09-3")
- << Qt::ISODate << QDateTime(QDate(2014, 12, 15), QTime(15, 37, 9), Qt::UTC);
+ << Qt::ISODate << QDateTime(QDate(2014, 12, 15), QTime(15, 37, 9), UTC);
QTest::newRow("ISO zzz-3") << QString::fromLatin1("2014-12-15T12:37:09.745-3")
- << Qt::ISODate << QDateTime(QDate(2014, 12, 15), QTime(15, 37, 9, 745), Qt::UTC);
+ << Qt::ISODate << QDateTime(QDate(2014, 12, 15), QTime(15, 37, 9, 745), UTC);
QTest::newRow("ISO lower-case") << QString::fromLatin1("2005-06-28T07:57:30.002z")
- << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 2), Qt::UTC);
+ << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 2), UTC);
// No time specified - defaults to Qt::LocalTime.
QTest::newRow("ISO data3") << QString::fromLatin1("2002-10-01")
- << Qt::ISODate << QDateTime(QDate(2002, 10, 1), QTime(0, 0), Qt::LocalTime);
+ << Qt::ISODate << QDate(2002, 10, 1).startOfDay();
// Excess digits in milliseconds, round correctly:
QTest::newRow("ISO") << QString::fromLatin1("2005-06-28T07:57:30.0010000000Z")
- << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 1), Qt::UTC);
+ << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 1), UTC);
QTest::newRow("ISO rounding") << QString::fromLatin1("2005-06-28T07:57:30.0015Z")
- << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 2), Qt::UTC);
+ << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 2), UTC);
// ... and accept comma as separator:
QTest::newRow("ISO with comma 1") << QString::fromLatin1("2005-06-28T07:57:30,0040000000Z")
- << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 4), Qt::UTC);
+ << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 4), UTC);
QTest::newRow("ISO with comma 2") << QString::fromLatin1("2005-06-28T07:57:30,0015Z")
- << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 2), Qt::UTC);
+ << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 2), UTC);
QTest::newRow("ISO with comma 3") << QString::fromLatin1("2005-06-28T07:57:30,0014Z")
- << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 1), Qt::UTC);
+ << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 1), UTC);
QTest::newRow("ISO with comma 4") << QString::fromLatin1("2005-06-28T07:57:30,1Z")
- << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 100), Qt::UTC);
+ << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 100), UTC);
QTest::newRow("ISO with comma 5") << QString::fromLatin1("2005-06-28T07:57:30,11")
- << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 110), Qt::LocalTime);
+ << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 110));
// 24:00:00 Should be next day according to ISO 8601 section 4.2.3.
QTest::newRow("ISO 24:00") << QString::fromLatin1("2012-06-04T24:00:00")
- << Qt::ISODate << QDateTime(QDate(2012, 6, 5), QTime(0, 0), Qt::LocalTime);
- QTest::newRow("ISO 24:00 in DST") // Only special if TZ=America/Sao_Paulo
+ << Qt::ISODate << QDate(2012, 6, 5).startOfDay();
+#if QT_CONFIG(timezone)
+ const QByteArray sysId = QTimeZone::systemTimeZoneId();
+ const bool midnightSkip = sysId == "America/Sao_Paulo" || sysId == "America/Asuncion"
+ || sysId == "America/Cordoba" || sysId == "America/Argentina/Cordoba"
+ || sysId == "America/Campo_Grande"
+ || sysId == "America/Cuiaba" || sysId == "America/Buenos_Aires"
+ || sysId == "America/Argentina/Buenos_Aires"
+ || sysId == "America/Argentina/Tucuman" || sysId == "Brazil/East";
+ QTest::newRow("ISO 24:00 in DST") // Midnight spring forward in some of South America.
<< QString::fromLatin1("2008-10-18T24:00") << Qt::ISODate
- << QDateTime(QDate(2008, 10, 19),
- QTime(QTimeZone::systemTimeZoneId() == "America/Sao_Paulo" ? 1 : 0, 0),
- Qt::LocalTime);
- QTest::newRow("ISO 24:00 end of month") << QString::fromLatin1("2012-06-30T24:00:00")
- << Qt::ISODate << QDateTime(QDate(2012, 7, 1), QTime(0, 0), Qt::LocalTime);
- QTest::newRow("ISO 24:00 end of year") << QString::fromLatin1("2012-12-31T24:00:00")
- << Qt::ISODate << QDateTime(QDate(2013, 1, 1), QTime(0, 0), Qt::LocalTime);
- QTest::newRow("ISO 24:00, fract ms") << QString::fromLatin1("2012-01-01T24:00:00.000")
- << Qt::ISODate << QDateTime(QDate(2012, 1, 2), QTime(0, 0), Qt::LocalTime);
- QTest::newRow("ISO 24:00 end of year, fract ms") << QString::fromLatin1("2012-12-31T24:00:00.000")
- << Qt::ISODate << QDateTime(QDate(2013, 1, 1), QTime(0, 0), Qt::LocalTime);
+ << QDateTime(QDate(2008, 10, 19), QTime(midnightSkip ? 1 : 0, 0));
+#endif
+ QTest::newRow("ISO 24:00 end of month")
+ << QString::fromLatin1("2012-06-30T24:00:00")
+ << Qt::ISODate << QDate(2012, 7, 1).startOfDay();
+ QTest::newRow("ISO 24:00 end of year")
+ << QString::fromLatin1("2012-12-31T24:00:00")
+ << Qt::ISODate << QDate(2013, 1, 1).startOfDay();
+ QTest::newRow("ISO 24:00, fract ms")
+ << QString::fromLatin1("2012-01-01T24:00:00.000")
+ << Qt::ISODate << QDate(2012, 1, 2).startOfDay();
+ QTest::newRow("ISO 24:00 end of year, fract ms")
+ << QString::fromLatin1("2012-12-31T24:00:00.000")
+ << Qt::ISODate << QDate(2013, 1, 1).startOfDay();
// Test fractional seconds.
- QTest::newRow("ISO .0 of a second (period)") << QString::fromLatin1("2012-01-01T08:00:00.0")
- << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 0), Qt::LocalTime);
+ QTest::newRow("ISO .0 of a second (period)")
+ << QString::fromLatin1("2012-01-01T08:00:00.0")
+ << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0));
QTest::newRow("ISO .00 of a second (period)") << QString::fromLatin1("2012-01-01T08:00:00.00")
- << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 0), Qt::LocalTime);
+ << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0));
QTest::newRow("ISO .000 of a second (period)") << QString::fromLatin1("2012-01-01T08:00:00.000")
- << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 0), Qt::LocalTime);
+ << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0));
QTest::newRow("ISO .1 of a second (comma)") << QString::fromLatin1("2012-01-01T08:00:00,1")
- << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 100), Qt::LocalTime);
+ << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 100));
QTest::newRow("ISO .99 of a second (comma)") << QString::fromLatin1("2012-01-01T08:00:00,99")
- << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 990), Qt::LocalTime);
+ << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 990));
QTest::newRow("ISO .998 of a second (comma)") << QString::fromLatin1("2012-01-01T08:00:00,998")
- << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 998), Qt::LocalTime);
+ << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 998));
QTest::newRow("ISO .999 of a second (comma)") << QString::fromLatin1("2012-01-01T08:00:00,999")
- << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 999), Qt::LocalTime);
+ << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 999));
QTest::newRow("ISO .3335 of a second (comma)") << QString::fromLatin1("2012-01-01T08:00:00,3335")
- << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 334), Qt::LocalTime);
+ << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 334));
QTest::newRow("ISO .333333 of a second (comma)") << QString::fromLatin1("2012-01-01T08:00:00,333333")
- << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 333), Qt::LocalTime);
+ << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 333));
QTest::newRow("ISO .00009 of a second (period)") << QString::fromLatin1("2012-01-01T08:00:00.00009")
- << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 0), Qt::LocalTime);
+ << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0));
QTest::newRow("ISO second fraction") << QString::fromLatin1("2013-05-06T01:02:03.456")
<< Qt::ISODate << QDateTime(QDate(2013, 5, 6), QTime(1, 2, 3, 456));
QTest::newRow("ISO max milli")
@@ -2522,17 +2946,17 @@ void tst_QDateTime::fromStringDateFormat_data()
<< Qt::ISODate << QDateTime();
// Test fractional minutes.
QTest::newRow("ISO .0 of a minute (period)") << QString::fromLatin1("2012-01-01T08:00.0")
- << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 0), Qt::LocalTime);
+ << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0));
QTest::newRow("ISO .8 of a minute (period)") << QString::fromLatin1("2012-01-01T08:00.8")
- << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 48, 0), Qt::LocalTime);
+ << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 48));
QTest::newRow("ISO .99999 of a minute (period)") << QString::fromLatin1("2012-01-01T08:00.99999")
- << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 59, 999), Qt::LocalTime);
+ << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 59, 999));
QTest::newRow("ISO .0 of a minute (comma)") << QString::fromLatin1("2012-01-01T08:00,0")
- << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 0, 0), Qt::LocalTime);
+ << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0));
QTest::newRow("ISO .8 of a minute (comma)") << QString::fromLatin1("2012-01-01T08:00,8")
- << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 48, 0), Qt::LocalTime);
+ << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 48));
QTest::newRow("ISO .99999 of a minute (comma)") << QString::fromLatin1("2012-01-01T08:00,99999")
- << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 59, 999), Qt::LocalTime);
+ << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 59, 999));
QTest::newRow("ISO empty") << QString::fromLatin1("") << Qt::ISODate << QDateTime();
QTest::newRow("ISO short") << QString::fromLatin1("2017-07-01T") << Qt::ISODate << QDateTime();
QTest::newRow("ISO zoned date")
@@ -2544,32 +2968,28 @@ void tst_QDateTime::fromStringDateFormat_data()
// Test Qt::RFC2822Date format (RFC 2822).
QTest::newRow("RFC 2822 +0100") << QString::fromLatin1("13 Feb 1987 13:24:51 +0100")
- << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), Qt::UTC);
+ << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), UTC);
QTest::newRow("RFC 2822 after space +0100")
<< QString::fromLatin1(" 13 Feb 1987 13:24:51 +0100")
- << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), Qt::UTC);
+ << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), UTC);
QTest::newRow("RFC 2822 with day +0100") << QString::fromLatin1("Fri, 13 Feb 1987 13:24:51 +0100")
- << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), Qt::UTC);
+ << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), UTC);
QTest::newRow("RFC 2822 with day after space +0100")
<< QString::fromLatin1(" Fri, 13 Feb 1987 13:24:51 +0100")
- << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), Qt::UTC);
+ << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), UTC);
QTest::newRow("RFC 2822 -0100") << QString::fromLatin1("13 Feb 1987 13:24:51 -0100")
- << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(14, 24, 51), Qt::UTC);
+ << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(14, 24, 51), UTC);
QTest::newRow("RFC 2822 with day -0100") << QString::fromLatin1("Fri, 13 Feb 1987 13:24:51 -0100")
- << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(14, 24, 51), Qt::UTC);
- QTest::newRow("RFC 2822 +0000") << QString::fromLatin1("01 Jan 1970 00:12:34 +0000")
- << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
- QTest::newRow("RFC 2822 with day +0000") << QString::fromLatin1("Thu, 01 Jan 1970 00:12:34 +0000")
- << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(14, 24, 51), UTC);
QTest::newRow("RFC 2822 +0000") << QString::fromLatin1("01 Jan 1970 00:12:34 +0000")
- << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), UTC);
QTest::newRow("RFC 2822 with day +0000") << QString::fromLatin1("Thu, 01 Jan 1970 00:12:34 +0000")
- << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), UTC);
QTest::newRow("RFC 2822 missing space before +0100")
<< QString::fromLatin1("Thu, 01 Jan 1970 00:12:34+0100") << Qt::RFC2822Date << QDateTime();
// No timezone assume UTC
QTest::newRow("RFC 2822 no timezone") << QString::fromLatin1("01 Jan 1970 00:12:34")
- << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), UTC);
// No time specified
QTest::newRow("RFC 2822 date only") << QString::fromLatin1("01 Nov 2002")
<< Qt::RFC2822Date << QDateTime();
@@ -2614,23 +3034,21 @@ void tst_QDateTime::fromStringDateFormat_data()
// sure *it's* not what's invalid:
QTest::newRow("RFC 2822 (not invalid)")
<< QString::fromLatin1("01 Jan 2012 08:00:00 +0100")
- << Qt::RFC2822Date << QDateTime(QDate(2012, 1, 1), QTime(7, 0), Qt::UTC);
+ << Qt::RFC2822Date << QDateTime(QDate(2012, 1, 1), QTime(7, 0), UTC);
// Test Qt::RFC2822Date format (RFC 850 and 1036, permissive).
QTest::newRow("RFC 850 and 1036 +0100") << QString::fromLatin1("Fri Feb 13 13:24:51 1987 +0100")
- << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), Qt::UTC);
+ << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), UTC);
QTest::newRow("RFC 1036 after space +0100")
<< QString::fromLatin1(" Fri Feb 13 13:24:51 1987 +0100")
- << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), Qt::UTC);
+ << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), UTC);
QTest::newRow("RFC 850 and 1036 -0100") << QString::fromLatin1("Fri Feb 13 13:24:51 1987 -0100")
- << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(14, 24, 51), Qt::UTC);
- QTest::newRow("RFC 850 and 1036 +0000") << QString::fromLatin1("Thu Jan 01 00:12:34 1970 +0000")
- << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(14, 24, 51), UTC);
QTest::newRow("RFC 850 and 1036 +0000") << QString::fromLatin1("Thu Jan 01 00:12:34 1970 +0000")
- << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), UTC);
// No timezone assume UTC
QTest::newRow("RFC 850 and 1036 no timezone") << QString::fromLatin1("Thu Jan 01 00:12:34 1970")
- << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), UTC);
// No time specified
QTest::newRow("RFC 850 and 1036 date only")
<< QString::fromLatin1("Fri Nov 01 2002")
@@ -2654,7 +3072,7 @@ void tst_QDateTime::fromStringDateFormat_data()
// Again, check the text in the "invalid character" tests isn't the source of invalidity:
QTest::newRow("RFC 850 and 1036 (not invalid)")
<< QString::fromLatin1("Sun Jan 01 08:00:00 2012 +0100")
- << Qt::RFC2822Date << QDateTime(QDate(2012, 1, 1), QTime(7, 0), Qt::UTC);
+ << Qt::RFC2822Date << QDateTime(QDate(2012, 1, 1), QTime(7, 0), UTC);
QTest::newRow("RFC empty") << QString::fromLatin1("") << Qt::RFC2822Date << QDateTime();
}
@@ -2674,234 +3092,271 @@ void tst_QDateTime::fromStringStringFormat_data()
{
QTest::addColumn<QString>("string");
QTest::addColumn<QString>("format");
+ QTest::addColumn<int>("baseYear");
QTest::addColumn<QDateTime>("expected");
- const QDate defDate(1900, 1, 1);
- QTest::newRow("data0")
- << QString("101010") << QString("dMyy") << QDate(1910, 10, 10).startOfDay();
- QTest::newRow("data1") << QString("1020") << QString("sss") << QDateTime();
- QTest::newRow("data2")
- << QString("1010") << QString("sss") << QDateTime(defDate, QTime(0, 0, 10));
- QTest::newRow("data3") << QString("10hello20") << QString("ss'hello'ss") << QDateTime();
- QTest::newRow("data4") << QString("10") << QString("''") << QDateTime();
- QTest::newRow("data5") << QString("10") << QString("'") << QDateTime();
- QTest::newRow("data6") << QString("pm") << QString("ap") << QDateTime(defDate, QTime(12, 0));
- QTest::newRow("data7") << QString("foo") << QString("ap") << QDateTime();
+ // Indian/Cocos had a transition at the start of 1900, so its Jan 1st starts
+ // at 00:02:20 on that day; this leads to perverse results. QTBUG-77948.
+ if (const QDate defDate(1900, 1, 1); defDate.startOfDay().time() == QTime(0, 0)) {
+ QTest::newRow("dMyy-only:19")
+ << u"101010"_s << u"dMyy"_s << 1900 << QDate(1910, 10, 10).startOfDay();
+ QTest::newRow("dMyy-only:20")
+ << u"101010"_s << u"dMyy"_s << 1911 << QDate(2010, 10, 10).startOfDay();
+ QTest::newRow("secs-repeat-valid")
+ << u"1010"_s << u"sss"_s << 1900 << QDateTime(defDate, QTime(0, 0, 10));
+ QTest::newRow("pm-only")
+ << u"pm"_s << u"ap"_s << 1900 << QDateTime(defDate, QTime(12, 0));
+ QTest::newRow("date-only:19")
+ << u"10 Oct 10"_s << u"dd MMM yy"_s << 1900 << QDate(1910, 10, 10).startOfDay();
+ QTest::newRow("date-only:20")
+ << u"10 Oct 10"_s << u"dd MMM yy"_s << 1950 << QDate(2010, 10, 10).startOfDay();
+ QTest::newRow("dow-date-only")
+ << u"Fri December 3 2004"_s << u"ddd MMMM d yyyy"_s << 1900
+ << QDate(2004, 12, 3).startOfDay();
+ QTest::newRow("dow-mon-yr-only")
+ << u"Thu January 2004"_s << u"ddd MMMM yyyy"_s << 1900
+ << QDate(2004, 1, 1).startOfDay();
+ }
+ QTest::newRow("yy=24/Mar/20") // QTBUG-123579
+ << u"Wed, 20 Mar 24 16:17:00"_s << u"ddd, dd MMM yy HH:mm:ss"_s << 1900
+ << QDateTime(QDate(2024, 3, 20), QTime(16, 17));
+ QTest::newRow("secs-conflict") << u"1020"_s << u"sss"_s << 1900 << QDateTime();
+ QTest::newRow("secs-split-conflict")
+ << u"10hello20"_s << u"ss'hello'ss"_s << 1900 << QDateTime();
+ QTest::newRow("nomatch-quote-twice") << u"10"_s << u"''"_s << 1900 << QDateTime();
+ QTest::newRow("momatch-quote") << u"10"_s << u"'"_s << 1900 << QDateTime();
+ QTest::newRow("nomatch-am-pm") << u"foo"_s << u"ap"_s << 1900 << QDateTime();
// Day non-conflict should not hide earlier year conflict (1963-03-01 was a
// Friday; asking for Thursday moves this, without conflict, to the 7th):
- QTest::newRow("data8")
- << QString("77 03 1963 Thu") << QString("yy MM yyyy ddd") << QDateTime();
- QTest::newRow("data9")
- << QString("101010") << QString("dMyy") << QDate(1910, 10, 10).startOfDay();
- QTest::newRow("data10")
- << QString("101010") << QString("dMyy") << QDate(1910, 10, 10).startOfDay();
- QTest::newRow("data11")
- << QString("10 Oct 10") << QString("dd MMM yy") << QDate(1910, 10, 10).startOfDay();
- QTest::newRow("data12")
- << QString("Fri December 3 2004") << QString("ddd MMMM d yyyy")
- << QDate(2004, 12, 3).startOfDay();
- QTest::newRow("data13") << QString("30.02.2004") << QString("dd.MM.yyyy") << QDateTime();
- QTest::newRow("data14") << QString("32.01.2004") << QString("dd.MM.yyyy") << QDateTime();
- QTest::newRow("data15")
- << QString("Thu January 2004") << QString("ddd MMMM yyyy")
- << QDate(2004, 1, 1).startOfDay();
- QTest::newRow("data16") << QString("2005-06-28T07:57:30.001Z")
- << QString("yyyy-MM-ddThh:mm:ss.zt")
- << QDateTime(QDate(2005, 06, 28), QTime(07, 57, 30, 1), Qt::UTC);
+ QTest::newRow("year-conflict")
+ << u"77 03 1963 Thu"_s << u"yy MM yyyy ddd"_s << 1900 << QDateTime();
+ QTest::newRow("Feb-overflow") << u"30.02.2004"_s << u"dd.MM.yyyy"_s << 1900 << QDateTime();
+ QTest::newRow("Jan-overflow") << u"32.01.2004"_s << u"dd.MM.yyyy"_s << 1900 << QDateTime();
+ QTest::newRow("zulu-time-with-z-centisec")
+ << u"2005-06-28T07:57:30.01Z"_s << u"yyyy-MM-ddThh:mm:ss.zt"_s << 1900
+ << QDateTime(QDate(2005, 06, 28), QTime(07, 57, 30, 10), UTC);
+ QTest::newRow("zulu-time-with-zz-decisec")
+ << u"2005-06-28T07:57:30.1Z"_s << u"yyyy-MM-ddThh:mm:ss.zzt"_s << 1900
+ << QDateTime(QDate(2005, 06, 28), QTime(07, 57, 30, 100), UTC);
+ QTest::newRow("zulu-time-with-zzz-centisec")
+ << u"2005-06-28T07:57:30.01Z"_s << u"yyyy-MM-ddThh:mm:ss.zzzt"_s << 1900
+ << QDateTime(); // Invalid because too few digits for zzz
+ QTest::newRow("zulu-time-with-z-millisec")
+ << u"2005-06-28T07:57:30.001Z"_s << u"yyyy-MM-ddThh:mm:ss.zt"_s << 1900
+ << QDateTime(QDate(2005, 06, 28), QTime(07, 57, 30, 1), UTC);
QTest::newRow("utc-time-spec-as:UTC+0")
- << QString("2005-06-28T07:57:30.001UTC+0") << QString("yyyy-MM-ddThh:mm:ss.zt")
- << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 1), Qt::UTC);
+ << u"2005-06-28T07:57:30.001UTC+0"_s << u"yyyy-MM-ddThh:mm:ss.zt"_s << 1900
+ << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 1), UTC);
QTest::newRow("utc-time-spec-as:UTC-0")
- << QString("2005-06-28T07:57:30.001UTC-0") << QString("yyyy-MM-ddThh:mm:ss.zt")
- << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 1), Qt::UTC);
+ << u"2005-06-28T07:57:30.001UTC-0"_s << u"yyyy-MM-ddThh:mm:ss.zt"_s << 1900
+ << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 1), UTC);
QTest::newRow("offset-from-utc:UTC+1")
- << QString("2001-09-13T07:33:01.001 UTC+1") << QString("yyyy-MM-ddThh:mm:ss.z t")
- << QDateTime(QDate(2001, 9, 13), QTime(7, 33, 1, 1), Qt::OffsetFromUTC, 3600);
+ << u"2001-09-13T07:33:01.001 UTC+1"_s << u"yyyy-MM-ddThh:mm:ss.z t"_s << 1900
+ << QDateTime(QDate(2001, 9, 13), QTime(7, 33, 1, 1),
+ QTimeZone::fromSecondsAheadOfUtc(3600));
QTest::newRow("offset-from-utc:UTC-11:01")
- << QString("2008-09-13T07:33:01.001 UTC-11:01") << QString("yyyy-MM-ddThh:mm:ss.z t")
- << QDateTime(QDate(2008, 9, 13), QTime(7, 33, 1, 1), Qt::OffsetFromUTC, -39660);
+ << u"2008-09-13T07:33:01.001 UTC-11:01"_s << u"yyyy-MM-ddThh:mm:ss.z t"_s << 1900
+ << QDateTime(QDate(2008, 9, 13), QTime(7, 33, 1, 1),
+ QTimeZone::fromSecondsAheadOfUtc(-39660));
QTest::newRow("offset-from-utc:UTC+02:57")
- << QString("2001-09-15T09:33:01.001UTC+02:57") << QString("yyyy-MM-ddThh:mm:ss.zt")
- << QDateTime(QDate(2001, 9, 15), QTime(9, 33, 1, 1), Qt::OffsetFromUTC, 10620);
+ << u"2001-09-15T09:33:01.001UTC+02:57"_s << u"yyyy-MM-ddThh:mm:ss.zt"_s << 1900
+ << QDateTime(QDate(2001, 9, 15), QTime(9, 33, 1, 1),
+ QTimeZone::fromSecondsAheadOfUtc(10620));
QTest::newRow("offset-from-utc:-03:00") // RFC 3339 offset format
- << QString("2001-09-15T09:33:01.001-03:00") << QString("yyyy-MM-ddThh:mm:ss.zt")
- << QDateTime(QDate(2001, 9, 15), QTime(9, 33, 1, 1), Qt::OffsetFromUTC, -10800);
+ << u"2001-09-15T09:33:01.001-03:00"_s << u"yyyy-MM-ddThh:mm:ss.zt"_s << 1900
+ << QDateTime(QDate(2001, 9, 15), QTime(9, 33, 1, 1),
+ QTimeZone::fromSecondsAheadOfUtc(-10800));
QTest::newRow("offset-from-utc:+0205") // ISO 8601 basic offset format
- << QString("2001-09-15T09:33:01.001+0205") << QString("yyyy-MM-ddThh:mm:ss.zt")
- << QDateTime(QDate(2001, 9, 15), QTime(9, 33, 1, 1), Qt::OffsetFromUTC, 7500);
+ << u"2001-09-15T09:33:01.001+0205"_s << u"yyyy-MM-ddThh:mm:ss.zt"_s << 1900
+ << QDateTime(QDate(2001, 9, 15), QTime(9, 33, 1, 1),
+ QTimeZone::fromSecondsAheadOfUtc(7500));
QTest::newRow("offset-from-utc:-0401") // ISO 8601 basic offset format
- << QString("2001-09-15T09:33:01.001-0401") << QString("yyyy-MM-ddThh:mm:ss.zt")
- << QDateTime(QDate(2001, 9, 15), QTime(9, 33, 1, 1), Qt::OffsetFromUTC, -14460);
+ << u"2001-09-15T09:33:01.001-0401"_s << u"yyyy-MM-ddThh:mm:ss.zt"_s << 1900
+ << QDateTime(QDate(2001, 9, 15), QTime(9, 33, 1, 1),
+ QTimeZone::fromSecondsAheadOfUtc(-14460));
QTest::newRow("offset-from-utc:+10") // ISO 8601 basic (hour-only) offset format
- << QString("2001-09-15T09:33:01.001 +10") << QString("yyyy-MM-ddThh:mm:ss.z t")
- << QDateTime(QDate(2001, 9, 15), QTime(9, 33, 1, 1), Qt::OffsetFromUTC, 36000);
+ << u"2001-09-15T09:33:01.001 +10"_s << u"yyyy-MM-ddThh:mm:ss.z t"_s << 1900
+ << QDateTime(QDate(2001, 9, 15), QTime(9, 33, 1, 1),
+ QTimeZone::fromSecondsAheadOfUtc(36000));
QTest::newRow("offset-from-utc:UTC+10:00") // Time-spec specifier at the beginning
- << QString("UTC+10:00 2008-10-13T07:33") << QString("t yyyy-MM-ddThh:mm")
- << QDateTime(QDate(2008, 10, 13), QTime(7, 33), Qt::OffsetFromUTC, 36000);
+ << u"UTC+10:00 2008-10-13T07:33"_s << u"t yyyy-MM-ddThh:mm"_s << 1900
+ << QDateTime(QDate(2008, 10, 13), QTime(7, 33),
+ QTimeZone::fromSecondsAheadOfUtc(36000));
QTest::newRow("offset-from-utc:UTC-03:30") // Time-spec specifier in the middle
- << QString("2008-10-13 UTC-03:30 11.50") << QString("yyyy-MM-dd t hh.mm")
- << QDateTime(QDate(2008, 10, 13), QTime(11, 50), Qt::OffsetFromUTC, -12600);
+ << u"2008-10-13 UTC-03:30 11.50"_s << u"yyyy-MM-dd t hh.mm"_s << 1900
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50),
+ QTimeZone::fromSecondsAheadOfUtc(-12600));
QTest::newRow("offset-from-utc:UTC-2") // Time-spec specifier joined with text/time
- << QString("2008-10-13 UTC-2Z11.50") << QString("yyyy-MM-dd tZhh.mm")
- << QDateTime(QDate(2008, 10, 13), QTime(11, 50), Qt::OffsetFromUTC, -7200);
+ << u"2008-10-13 UTC-2Z11.50"_s << u"yyyy-MM-dd tZhh.mm"_s << 1900
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50),
+ QTimeZone::fromSecondsAheadOfUtc(-7200));
QTest::newRow("offset-from-utc:followed-by-colon")
- << QString("2008-10-13 UTC-0100:11.50") << QString("yyyy-MM-dd t:hh.mm")
- << QDateTime(QDate(2008, 10, 13), QTime(11, 50), Qt::OffsetFromUTC, -3600);
+ << u"2008-10-13 UTC-0100:11.50"_s << u"yyyy-MM-dd t:hh.mm"_s << 1900
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50),
+ QTimeZone::fromSecondsAheadOfUtc(-3600));
QTest::newRow("offset-from-utc:late-colon")
- << QString("2008-10-13 UTC+05T:11.50") << QString("yyyy-MM-dd tT:hh.mm")
- << QDateTime(QDate(2008, 10, 13), QTime(11, 50), Qt::OffsetFromUTC, 18000);
+ << u"2008-10-13 UTC+05T:11.50"_s << u"yyyy-MM-dd tT:hh.mm"_s << 1900
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50),
+ QTimeZone::fromSecondsAheadOfUtc(18000));
QTest::newRow("offset-from-utc:merged-with-time")
- << QString("2008-10-13 UTC+010011.50") << QString("yyyy-MM-dd thh.mm")
- << QDateTime(QDate(2008, 10, 13), QTime(11, 50), Qt::OffsetFromUTC, 3600);
+ << u"2008-10-13 UTC+010011.50"_s << u"yyyy-MM-dd thh.mm"_s << 1900
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50),
+ QTimeZone::fromSecondsAheadOfUtc(3600));
QTest::newRow("offset-from-utc:double-colon-delimiter")
- << QString("2008-10-13 UTC+12::11.50") << QString("yyyy-MM-dd t::hh.mm")
- << QDateTime(QDate(2008, 10, 13), QTime(11, 50), Qt::OffsetFromUTC, 43200);
+ << u"2008-10-13 UTC+12::11.50"_s << u"yyyy-MM-dd t::hh.mm"_s << 1900
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50),
+ QTimeZone::fromSecondsAheadOfUtc(43200));
QTest::newRow("offset-from-utc:3-digit-with-colon")
- << QString("2008-10-13 -4:30 11.50") << QString("yyyy-MM-dd t hh.mm")
- << QDateTime(QDate(2008, 10, 13), QTime(11, 50), Qt::OffsetFromUTC, -16200);
- QTest::newRow("offset-from-utc:merged-with-time")
- << QString("2008-10-13 UTC+010011.50") << QString("yyyy-MM-dd thh.mm")
- << QDateTime(QDate(2008, 10, 13), QTime(11, 50), Qt::OffsetFromUTC, 3600);
+ << u"2008-10-13 -4:30 11.50"_s << u"yyyy-MM-dd t hh.mm"_s << 1900
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50),
+ QTimeZone::fromSecondsAheadOfUtc(-16200));
QTest::newRow("offset-from-utc:with-colon-merged-with-time")
- << QString("2008-10-13 UTC+01:0011.50") << QString("yyyy-MM-dd thh.mm")
- << QDateTime(QDate(2008, 10, 13), QTime(11, 50), Qt::OffsetFromUTC, 3600);
+ << u"2008-10-13 UTC+01:0011.50"_s << u"yyyy-MM-dd thh.mm"_s << 1900
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50),
+ QTimeZone::fromSecondsAheadOfUtc(3600));
QTest::newRow("invalid-offset-from-utc:out-of-range")
- << QString("2001-09-15T09:33:01.001-50") << QString("yyyy-MM-ddThh:mm:ss.zt")
- << QDateTime();
+ << u"2001-09-15T09:33:01.001-50"_s << u"yyyy-MM-ddThh:mm:ss.zt"_s << 1900
+ << QDateTime();
QTest::newRow("invalid-offset-from-utc:single-digit-format")
- << QString("2001-09-15T09:33:01.001+5") << QString("yyyy-MM-ddThh:mm:ss.zt")
- << QDateTime();
+ << u"2001-09-15T09:33:01.001+5"_s << u"yyyy-MM-ddThh:mm:ss.zt"_s << 1900 << QDateTime();
QTest::newRow("invalid-offset-from-utc:three-digit-format")
- << QString("2001-09-15T09:33:01.001-701") << QString("yyyy-MM-ddThh:mm:ss.zt")
- << QDateTime();
+ << u"2001-09-15T09:33:01.001-701"_s << u"yyyy-MM-ddThh:mm:ss.zt"_s << 1900
+ << QDateTime();
QTest::newRow("invalid-offset-from-utc:three-digit-minutes")
- << QString("2001-09-15T09:33:01.001+11:570") << QString("yyyy-MM-ddThh:mm:ss.zt")
- << QDateTime();
+ << u"2001-09-15T09:33:01.001+11:570"_s << u"yyyy-MM-ddThh:mm:ss.zt"_s << 1900
+ << QDateTime();
QTest::newRow("invalid-offset-from-utc:single-digit-minutes")
- << QString("2001-09-15T09:33:01.001+11:5") << QString("yyyy-MM-ddThh:mm:ss.zt")
- << QDateTime();
+ << u"2001-09-15T09:33:01.001+11:5"_s << u"yyyy-MM-ddThh:mm:ss.zt"_s << 1900
+ << QDateTime();
QTest::newRow("invalid-offset-from-utc:invalid-sign-symbol")
- << QString("2001-09-15T09:33:01.001 ~11:30") << QString("yyyy-MM-ddThh:mm:ss.z t")
- << QDateTime();
+ << u"2001-09-15T09:33:01.001 ~11:30"_s << u"yyyy-MM-ddThh:mm:ss.z t"_s << 1900
+ << QDateTime();
QTest::newRow("invalid-offset-from-utc:symbol-in-hours")
- << QString("2001-09-15T09:33:01.001 UTC+o8:30") << QString("yyyy-MM-ddThh:mm:ss.z t")
- << QDateTime();
+ << u"2001-09-15T09:33:01.001 UTC+o8:30"_s << u"yyyy-MM-ddThh:mm:ss.z t"_s << 1900
+ << QDateTime();
QTest::newRow("invalid-offset-from-utc:symbol-in-minutes")
- << QString("2001-09-15T09:33:01.001 UTC+08:3i") << QString("yyyy-MM-ddThh:mm:ss.z t")
- << QDateTime();
+ << u"2001-09-15T09:33:01.001 UTC+08:3i"_s << u"yyyy-MM-ddThh:mm:ss.z t"_s << 1900
+ << QDateTime();
QTest::newRow("invalid-offset-from-utc:UTC+123") // Invalid offset (UTC and 3 digit format)
- << QString("2001-09-15T09:33:01.001 UTC+123") << QString("yyyy-MM-ddThh:mm:ss.z t")
- << QDateTime();
+ << u"2001-09-15T09:33:01.001 UTC+123"_s << u"yyyy-MM-ddThh:mm:ss.z t"_s << 1900
+ << QDateTime();
QTest::newRow("invalid-offset-from-utc:UTC+00005") // Invalid offset with leading zeroes
- << QString("2001-09-15T09:33:01.001 UTC+00005") << QString("yyyy-MM-ddThh:mm:ss.z t")
- << QDateTime();
+ << u"2001-09-15T09:33:01.001 UTC+00005"_s << u"yyyy-MM-ddThh:mm:ss.z t"_s << 1900
+ << QDateTime();
QTest::newRow("invalid-offset-from-utc:three-digit-with-colon-delimiter")
- << QString("2008-10-13 +123:11.50") << QString("yyyy-MM-dd t:hh.mm")
- << QDateTime();
+ << u"2008-10-13 +123:11.50"_s << u"yyyy-MM-dd t:hh.mm"_s << 1900 << QDateTime();
QTest::newRow("invalid-offset-from-utc:double-colon-as-part-of-offset")
- << QString("2008-10-13 UTC+12::11.50") << QString("yyyy-MM-dd thh.mm")
- << QDateTime();
+ << u"2008-10-13 UTC+12::11.50"_s << u"yyyy-MM-dd thh.mm"_s << 1900 << QDateTime();
QTest::newRow("invalid-offset-from-utc:single-colon-as-part-of-offset")
- << QString("2008-10-13 UTC+12::11.50") << QString("yyyy-MM-dd t:hh.mm")
- << QDateTime();
+ << u"2008-10-13 UTC+12::11.50"_s << u"yyyy-MM-dd t:hh.mm"_s << 1900 << QDateTime();
QTest::newRow("invalid-offset-from-utc:starts-with-colon")
- << QString("2008-10-13 UTC+:59 11.50") << QString("yyyy-MM-dd t hh.mm")
- << QDateTime();
+ << u"2008-10-13 UTC+:59 11.50"_s << u"yyyy-MM-dd t hh.mm"_s << 1900 << QDateTime();
QTest::newRow("invalid-offset-from-utc:empty-offset")
- << QString("2008-10-13 UTC+ 11.50") << QString("yyyy-MM-dd t hh.mm")
- << QDateTime();
+ << u"2008-10-13 UTC+ 11.50"_s << u"yyyy-MM-dd t hh.mm"_s << 1900 << QDateTime();
QTest::newRow("invalid-offset-from-utc:time-section-instead-of-offset")
- << QString("2008-10-13 UTC+11.50") << QString("yyyy-MM-dd thh.mm")
- << QDateTime();
+ << u"2008-10-13 UTC+11.50"_s << u"yyyy-MM-dd thh.mm"_s << 1900 << QDateTime();
QTest::newRow("invalid-offset-from-utc:missing-minutes-if-colon")
- << QString("2008-10-13 +05: 11.50") << QString("yyyy-MM-dd t hh.mm")
- << QDateTime();
+ << u"2008-10-13 +05: 11.50"_s << u"yyyy-MM-dd t hh.mm"_s << 1900 << QDateTime();
QTest::newRow("invalid-offset-from-utc:1-digit-minutes-if-colon")
- << QString("2008-10-13 UTC+05:1 11.50") << QString("yyyy-MM-dd t hh.mm")
- << QDateTime();
+ << u"2008-10-13 UTC+05:1 11.50"_s << u"yyyy-MM-dd t hh.mm"_s << 1900 << QDateTime();
QTest::newRow("invalid-time-spec:random-symbol")
- << QString("2001-09-15T09:33:01.001 $") << QString("yyyy-MM-ddThh:mm:ss.z t")
- << QDateTime();
+ << u"2001-09-15T09:33:01.001 $"_s << u"yyyy-MM-ddThh:mm:ss.z t"_s << 1900
+ << QDateTime();
QTest::newRow("invalid-time-spec:random-digit")
- << QString("2001-09-15T09:33:01.001 1") << QString("yyyy-MM-ddThh:mm:ss.z t")
- << QDateTime();
+ << u"2001-09-15T09:33:01.001 1"_s << u"yyyy-MM-ddThh:mm:ss.z t"_s << 1900
+ << QDateTime();
QTest::newRow("invalid-offset-from-utc:merged-with-time")
- << QString("2008-10-13 UTC+0111.50") << QString("yyyy-MM-dd thh.mm")
- << QDateTime();
+ << u"2008-10-13 UTC+0111.50"_s << u"yyyy-MM-dd thh.mm"_s << 1900 << QDateTime();
QTest::newRow("invalid-offset-from-utc:with-colon-3-digit-merged-with-time")
- << QString("2008-10-13 UTC+01:011.50") << QString("yyyy-MM-dd thh.mm")
- << QDateTime();
+ << u"2008-10-13 UTC+01:011.50"_s << u"yyyy-MM-dd thh.mm"_s << 1900 << QDateTime();
QTest::newRow("invalid-time-spec:empty")
- << QString("2001-09-15T09:33:01.001 ") << QString("yyyy-MM-ddThh:mm:ss.z t")
- << QDateTime();
+ << u"2001-09-15T09:33:01.001 "_s << u"yyyy-MM-ddThh:mm:ss.z t"_s << 1900 << QDateTime();
#if QT_CONFIG(timezone)
QTimeZone southBrazil("America/Sao_Paulo");
if (southBrazil.isValid()) {
QTest::newRow("spring-forward-midnight")
- << QString("2008-10-19 23:45.678 America/Sao_Paulo") << QString("yyyy-MM-dd mm:ss.zzz t")
- // That's in the hour skipped - expect the matching time after the spring-forward, in DST:
- << QDateTime(QDate(2008, 10, 19), QTime(1, 23, 45, 678), southBrazil);
+ // NB: no hour field, so hour takes its default, 0, so that
+ // default can be over-ridden:
+ << u"2008-10-19 23:45.678 America/Sao_Paulo"_s << u"yyyy-MM-dd mm:ss.zzz t"_s << 1900
+ // That's in the hour skipped - expect the matching time after
+ // the spring-forward, in DST:
+ << QDateTime(QDate(2008, 10, 19), QTime(1, 23, 45, 678), southBrazil);
}
QTimeZone berlintz("Europe/Berlin");
if (berlintz.isValid()) {
QTest::newRow("begin-of-high-summer-time-with-tz")
- << QString("1947-05-11 03:23:45.678 Europe/Berlin")
- << QString("yyyy-MM-dd hh:mm:ss.zzz t")
- // That's in the hour skipped - expecting an invalid DateTime
- << QDateTime(QDate(1947, 5, 11), QTime(3, 23, 45, 678), berlintz);
+ << u"1947-05-11 03:23:45.678 Europe/Berlin"_s << u"yyyy-MM-dd hh:mm:ss.zzz t"_s
+ // That's in the hour skipped - expecting an invalid DateTime
+ << 1900 << QDateTime(QDate(1947, 5, 11), QTime(3, 23, 45, 678), berlintz);
}
#endif
- QTest::newRow("late") << QString("9999-12-31T23:59:59.999Z")
- << QString("yyyy-MM-ddThh:mm:ss.zZ")
- << QDateTime(QDate(9999, 12, 31), QTime(23, 59, 59, 999));
+ QTest::newRow("late")
+ << u"9999-12-31T23:59:59.999Z"_s << u"yyyy-MM-ddThh:mm:ss.zZ"_s << 1900
+ << QDateTime(QDate(9999, 12, 31), QTime(23, 59, 59, 999));
// Separators match /([^aAdhHMmstyz]*)/
QTest::newRow("oddly-separated") // To show broken-separator's format is valid.
- << QStringLiteral("2018 wilful long working block relief 12-19T21:09 cruel blurb encore flux")
- << QStringLiteral("yyyy wilful long working block relief MM-ddThh:mm cruel blurb encore flux")
- << QDateTime(QDate(2018, 12, 19), QTime(21, 9));
+ << u"2018 wilful long working block relief 12-19T21:09 cruel blurb encore flux"_s
+ << u"yyyy wilful long working block relief MM-ddThh:mm cruel blurb encore flux"_s
+ << 1900 << QDateTime(QDate(2018, 12, 19), QTime(21, 9));
QTest::newRow("broken-separator")
- << QStringLiteral("2018 wilful")
- << QStringLiteral("yyyy wilful long working block relief MM-ddThh:mm cruel blurb encore flux")
- << QDateTime();
+ << u"2018 wilful"_s
+ << u"yyyy wilful long working block relief MM-ddThh:mm cruel blurb encore flux"_s
+ << 1900 << QDateTime();
QTest::newRow("broken-terminator")
- << QStringLiteral("2018 wilful long working block relief 12-19T21:09 cruel")
- << QStringLiteral("yyyy wilful long working block relief MM-ddThh:mm cruel blurb encore flux")
- << QDateTime();
+ << u"2018 wilful long working block relief 12-19T21:09 cruel"_s
+ << u"yyyy wilful long working block relief MM-ddThh:mm cruel blurb encore flux"_s
+ << 1900 << QDateTime();
// test unicode
- QTest::newRow("unicode handling") << QString(u8"2005🤣06🤣28T07🤣57🤣30.001Z")
- << QString(u8"yyyy🤣MM🤣ddThh🤣mm🤣ss.zt")
- << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 1), Qt::UTC);
-
- // QTBUG-84349
- QTest::newRow("QTBUG-84349: positive sign in month")
- << QStringLiteral("9922+221102233Z") << QStringLiteral("yyyyMMddHHmmsst")
- << QDateTime();
+ QTest::newRow("unicode handling")
+ << QString(u8"2005🤣06🤣28T07🤣57🤣30.001Z")
+ << QString(u8"yyyy🤣MM🤣ddThh🤣mm🤣ss.zt") << 1900
+ << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 1), UTC);
+
+ // Two tests derived from malformed ASN.1 strings (QTBUG-84349):
+ QTest::newRow("curft+ASN.1:UTC")
+ << u"22+221102233Z"_s << u"yyMMddHHmmsst"_s << 1900 << QDateTime();
+ QTest::newRow("curft+ASN.1:Generalized")
+ << u"9922+221102233Z"_s << u"yyyyMMddHHmmsst"_s << 1900 << QDateTime();
+ // Verify baseYear needed by plain ASN.1 works:
+ QTest::newRow("ASN.1:UTC-start")
+ << u"500101000000Z"_s << u"yyMMddHHmmsst"_s << 1950
+ << QDate(1950, 1, 1).startOfDay(QTimeZone::UTC);
+ QTest::newRow("ASN.1:UTC-end")
+ << u"491231235959Z"_s << u"yyMMddHHmmsst"_s << 1950
+ << QDate(2049, 12, 31).endOfDay(QTimeZone::UTC).addMSecs(-999);
// fuzzer test
QTest::newRow("integer overflow found by fuzzer")
- << QStringLiteral("EEE1200000MUB") << QStringLiteral("t")
- << QDateTime();
+ << u"EEE1200000MUB"_s << u"t"_s << 1900 << QDateTime();
+
+ // Rich time-zone specifiers (QTBUG-95966):
+ const auto east3hours = QTimeZone::fromSecondsAheadOfUtc(10800);
+ QTest::newRow("timezone-tt-with-offset:+0300")
+ << u"2008-10-13 +0300 11.50"_s << u"yyyy-MM-dd tt hh.mm"_s
+ << 1900 << QDateTime(QDate(2008, 10, 13), QTime(11, 50), east3hours);
+ QTest::newRow("timezone-ttt-with-offset:+03:00")
+ << u"2008-10-13 +03:00 11.50"_s << u"yyyy-MM-dd ttt hh.mm"_s
+ << 1900 << QDateTime(QDate(2008, 10, 13), QTime(11, 50), east3hours);
+ QTest::newRow("timezone-tttt-with-offset:+03:00")
+ << u"2008-10-13 +03:00 11.50"_s << u"yyyy-MM-dd tttt hh.mm"_s
+ << 1900 << QDateTime(); // Offset not valid when zone name expected.
}
void tst_QDateTime::fromStringStringFormat()
{
QFETCH(QString, string);
QFETCH(QString, format);
+ QFETCH(int, baseYear);
QFETCH(QDateTime, expected);
- QDateTime dt = QDateTime::fromString(string, format);
+ QDateTime dt = QDateTime::fromString(string, format, baseYear);
QCOMPARE(dt, expected);
if (expected.isValid()) {
QCOMPARE(dt.timeSpec(), expected.timeSpec());
-#if QT_CONFIG(timezone)
- if (expected.timeSpec() == Qt::TimeZone)
- QCOMPARE(dt.timeZone(), expected.timeZone());
-#endif
- // OffsetFromUTC needs an offset check - we may as well do it for all:
- QCOMPARE(dt.offsetFromUtc(), expected.offsetFromUtc());
+ QCOMPARE(dt.timeRepresentation(), dt.timeRepresentation());
} else {
QCOMPARE(dt.isValid(), expected.isValid());
QCOMPARE(dt.toMSecsSinceEpoch(), expected.toMSecsSinceEpoch());
@@ -2913,10 +3368,11 @@ void tst_QDateTime::fromStringStringFormat_localTimeZone_data()
QTest::addColumn<QByteArray>("localTimeZone");
QTest::addColumn<QString>("string");
QTest::addColumn<QString>("format");
+ QTest::addColumn<int>("baseYear");
QTest::addColumn<QDateTime>("expected");
- bool lacksRows = true;
#if QT_CONFIG(timezone)
+ bool lacksRows = true;
// Note that the localTimeZone needn't match the zone used in the string and
// expected date-time; indeed, having them different is probably best.
// Both zones need to be valid; GMT always is, so is a safe one to use for
@@ -2924,44 +3380,62 @@ void tst_QDateTime::fromStringStringFormat_localTimeZone_data()
QTimeZone etcGmtWithOffset("Etc/GMT+3");
if (etcGmtWithOffset.isValid()) {
lacksRows = false;
- QTest::newRow("local-timezone-with-offset:Etc/GMT+3") << QByteArrayLiteral("GMT")
- << QString("2008-10-13 Etc/GMT+3 11.50") << QString("yyyy-MM-dd t hh.mm")
- << QDateTime(QDate(2008, 10, 13), QTime(11, 50), etcGmtWithOffset);
- // TODO QTBUG-95966: find better ways to use repeated 't'
- QTest::newRow("double-timezone-with-offset:Etc/GMT+3") << QByteArrayLiteral("GMT")
- << QString("2008-10-13 Etc/GMT+3Etc/GMT+3 11.50") << QString("yyyy-MM-dd tt hh.mm")
- << QDateTime(QDate(2008, 10, 13), QTime(11, 50), etcGmtWithOffset);
+ QTest::newRow("local-timezone-t-with-zone:Etc/GMT+3")
+ << "GMT"_ba << u"2008-10-13 Etc/GMT+3 11.50"_s << u"yyyy-MM-dd t hh.mm"_s << 1900
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50), etcGmtWithOffset);
+ QTest::newRow("local-timezone-tttt-with-zone:Etc/GMT+3")
+ << "GMT"_ba << u"2008-10-13 Etc/GMT+3 11.50"_s << u"yyyy-MM-dd tttt hh.mm"_s << 1900
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50), etcGmtWithOffset);
}
+ QTest::newRow("local-timezone-tt-with-zone:Etc/GMT+3")
+ << "GMT"_ba << u"2008-10-13 Etc/GMT+3 11.50"_s << u"yyyy-MM-dd tt hh.mm"_s << 1900
+ << QDateTime(); // Zone name not valid when offset expected
+ QTest::newRow("local-timezone-ttt-with-zone:Etc/GMT+3")
+ << "GMT"_ba << u"2008-10-13 Etc/GMT+3 11.50"_s << u"yyyy-MM-dd ttt hh.mm"_s << 1900
+ << QDateTime(); // Zone name not valid when offset expected
QTimeZone gmtWithOffset("GMT-2");
if (gmtWithOffset.isValid()) {
lacksRows = false;
- QTest::newRow("local-timezone-with-offset:GMT-2") << QByteArrayLiteral("GMT")
- << QString("2008-10-13 GMT-2 11.50") << QString("yyyy-MM-dd t hh.mm")
- << QDateTime(QDate(2008, 10, 13), QTime(11, 50), gmtWithOffset);
+ QTest::newRow("local-timezone-with-offset:GMT-2")
+ << "GMT"_ba << u"2008-10-13 GMT-2 11.50"_s << u"yyyy-MM-dd t hh.mm"_s << 1900
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50), gmtWithOffset);
}
QTimeZone gmt("GMT");
if (gmt.isValid()) {
lacksRows = false;
- QTest::newRow("local-timezone-with-offset:GMT") << QByteArrayLiteral("GMT")
- << QString("2008-10-13 GMT 11.50") << QString("yyyy-MM-dd t hh.mm")
- << QDateTime(QDate(2008, 10, 13), QTime(11, 50), gmt);
+ const bool fullyLocal = ([]() {
+ TimeZoneRollback useZone("GMT");
+ return qTzName(0) == u"GMT"_s;
+ })();
+ QTest::newRow("local-timezone-with-offset:GMT")
+ << "GMT"_ba << u"2008-10-13 GMT 11.50"_s << u"yyyy-MM-dd t hh.mm"_s << 1900
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50),
+ fullyLocal ? QTimeZone(QTimeZone::LocalTime) : gmt);
}
QTimeZone helsinki("Europe/Helsinki");
if (helsinki.isValid()) {
lacksRows = false;
- // QTBUG-96861: QAsn1Element::toDateTime() tripped over an assert in
- // QTimeZonePrivate::dataForLocalTime() on macOS and iOS.
- // The first 20m 11s of 1921-05-01 were skipped, so the parser's attempt
- // to construct a local time after scanning yyMM tripped up on the start
- // of the day, when the zone backend lacked transition data.
- QTest::newRow("Helsinki-joins-EET")
- << QByteArrayLiteral("Europe/Helsinki")
- << QString("210506000000Z") << QString("yyMMddHHmmsst")
- << QDateTime(QDate(1921, 5, 6), QTime(0, 0), Qt::UTC);
+ // QTBUG-96861: QAsn1Element::toDateTime() tripped over an assert due to
+ // the first 20m 11s of 1921-05-01 being skipped, so the parser's
+ // attempt to construct a local time after scanning yyMM tripped up on
+ // the start of the day, when the zone backend lacked transition data.
+ // (Because QDTP tries to use local time until it reads the final zone
+ // field, constructing a new QDT after reading each field, hence
+ // transiently wanting 1921-05-01 00:00:00 before reading the dd field.)
+ QTest::newRow("Helsinki-joins-EET:19")
+ << "Europe/Helsinki"_ba << u"210506000000Z"_s << u"yyMMddHHmmsst"_s << 1900
+ << QDateTime(QDate(1921, 5, 6), QTime(0, 0), UTC);
+ // Strictly, ASN.1 wants us to parse that with a different baseYear, so
+ // check that, too, but tweak to match the 1921 transition's mid-point:
+ QTest::newRow("Helsinki-joins-EET:20")
+ << "Europe/Helsinki"_ba << u"210501001006Z"_s << u"yyMMddHHmmsst"_s << 1950
+ << QDateTime(QDate(2021, 5, 1), QTime(0, 10, 6), UTC);
}
-#endif
if (lacksRows)
QSKIP("Testcases all use zones unsupported on this platform");
+#else
+ QSKIP("Test only possible with timezone support enabled");
+#endif
}
void tst_QDateTime::fromStringStringFormat_localTimeZone()
@@ -2979,25 +3453,26 @@ void tst_QDateTime::offsetFromUtc()
QCOMPARE(QDateTime().offsetFromUtc(), 0);
// Offset constructor
- QDateTime dt1(QDate(2013, 1, 1), QTime(1, 0), Qt::OffsetFromUTC, 60 * 60);
+ QDateTime dt1(QDate(2013, 1, 1), QTime(1, 0), QTimeZone::fromSecondsAheadOfUtc(60 * 60));
QCOMPARE(dt1.offsetFromUtc(), 60 * 60);
+ QVERIFY(dt1.timeRepresentation().isValid());
#if QT_CONFIG(timezone)
QVERIFY(dt1.timeZone().isValid());
#endif
- dt1 = QDateTime(QDate(2013, 1, 1), QTime(1, 0), Qt::OffsetFromUTC, -60 * 60);
+ dt1 = QDateTime(QDate(2013, 1, 1), QTime(1, 0), QTimeZone::fromSecondsAheadOfUtc(-60 * 60));
QCOMPARE(dt1.offsetFromUtc(), -60 * 60);
// UTC should be 0 offset
- QDateTime dt2(QDate(2013, 1, 1), QTime(0, 0), Qt::UTC);
+ QDateTime dt2(QDate(2013, 1, 1), QTime(0, 0), UTC);
QCOMPARE(dt2.offsetFromUtc(), 0);
// LocalTime should vary
if (zoneIsCET) {
// Time definitely in Standard Time so 1 hour ahead
- QDateTime dt3(QDate(2013, 1, 1), QTime(0, 0), Qt::LocalTime);
+ QDateTime dt3 = QDate(2013, 1, 1).startOfDay();
QCOMPARE(dt3.offsetFromUtc(), 1 * 60 * 60);
// Time definitely in Daylight Time so 2 hours ahead
- QDateTime dt4(QDate(2013, 6, 1), QTime(0, 0), Qt::LocalTime);
+ QDateTime dt4 = QDate(2013, 6, 1).startOfDay();
QCOMPARE(dt4.offsetFromUtc(), 2 * 60 * 60);
} else {
qDebug("Skipped some tests specific to Central European Time "
@@ -3013,6 +3488,9 @@ void tst_QDateTime::offsetFromUtc()
#endif
}
+#if QT_DEPRECATED_SINCE(6, 9)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
void tst_QDateTime::setOffsetFromUtc()
{
/* Basic tests. */
@@ -3088,7 +3566,7 @@ void tst_QDateTime::setOffsetFromUtc()
void tst_QDateTime::toOffsetFromUtc()
{
- QDateTime dt1(QDate(2013, 1, 1), QTime(0, 0), Qt::UTC);
+ QDateTime dt1(QDate(2013, 1, 1), QTime(0, 0), QTimeZone::UTC);
QDateTime dt2 = dt1.toOffsetFromUtc(60 * 60);
QCOMPARE(dt2, dt1);
@@ -3108,6 +3586,8 @@ void tst_QDateTime::toOffsetFromUtc()
QCOMPARE(dt2.date(), QDate(2013, 1, 1));
QCOMPARE(dt2.time(), QTime(0, 0));
}
+QT_WARNING_POP
+#endif // 6.9 deprecation
void tst_QDateTime::zoneAtTime_data()
{
@@ -3183,28 +3663,46 @@ void tst_QDateTime::zoneAtTime()
void tst_QDateTime::timeZoneAbbreviation()
{
- QDateTime dt1(QDate(2013, 1, 1), QTime(1, 0), Qt::OffsetFromUTC, 60 * 60);
+ QDateTime dt1(QDate(2013, 1, 1), QTime(1, 0), QTimeZone::fromSecondsAheadOfUtc(60 * 60));
QCOMPARE(dt1.timeZoneAbbreviation(), QString("UTC+01:00"));
- QDateTime dt2(QDate(2013, 1, 1), QTime(1, 0), Qt::OffsetFromUTC, -60 * 60);
+ QDateTime dt2(QDate(2013, 1, 1), QTime(1, 0), QTimeZone::fromSecondsAheadOfUtc(-60 * 60));
QCOMPARE(dt2.timeZoneAbbreviation(), QString("UTC-01:00"));
- QDateTime dt3(QDate(2013, 1, 1), QTime(0, 0), Qt::UTC);
+ QDateTime dt3(QDate(2013, 1, 1), QTime(0, 0), UTC);
QCOMPARE(dt3.timeZoneAbbreviation(), QString("UTC"));
// LocalTime should vary
if (zoneIsCET) {
// Time definitely in Standard Time
- QDateTime dt4(QDate(2013, 1, 1), QTime(0, 0), Qt::LocalTime);
+ QDateTime dt4 = QDate(2013, 1, 1).startOfDay();
+ /* Note that MET is functionally an alias for CET (their zoneinfo files
+ differ only in the first letter of the abbreviations), unlike the
+ various zones that give CET as their abbreviation.
+ */
+ {
+ const auto abbrev = dt4.timeZoneAbbreviation();
+ auto reporter = qScopeGuard([abbrev]() {
+ qDebug() << "Unexpected abbreviation" << abbrev;
+ });
#ifdef Q_OS_WIN
- QEXPECT_FAIL("", "Windows only reports long name (QTBUG-32759)", Continue);
+ QEXPECT_FAIL("", "Windows only reports long name (QTBUG-32759)", Continue);
#endif
- QCOMPARE(dt4.timeZoneAbbreviation(), QStringLiteral("CET"));
+ QVERIFY(abbrev == u"CET"_s || abbrev == u"MET"_s);
+ reporter.dismiss();
+ }
// Time definitely in Daylight Time
- QDateTime dt5(QDate(2013, 6, 1), QTime(0, 0), Qt::LocalTime);
+ QDateTime dt5 = QDate(2013, 6, 1).startOfDay();
+ {
+ const auto abbrev = dt5.timeZoneAbbreviation();
+ auto reporter = qScopeGuard([abbrev]() {
+ qDebug() << "Unexpected abbreviation" << abbrev;
+ });
#ifdef Q_OS_WIN
- QEXPECT_FAIL("", "Windows only reports long name (QTBUG-32759)", Continue);
+ QEXPECT_FAIL("", "Windows only reports long name (QTBUG-32759)", Continue);
#endif
- QCOMPARE(dt5.timeZoneAbbreviation(), QStringLiteral("CEST"));
+ QVERIFY(abbrev == u"CEST"_s || abbrev == u"MEST"_s);
+ reporter.dismiss();
+ }
} else {
qDebug("(Skipped some CET-only tests)");
}
@@ -3297,8 +3795,8 @@ void tst_QDateTime::utcOffsetLessThan() const
QDateTime dt1(QDate(2002, 10, 10), QTime(0, 0));
QDateTime dt2(dt1);
- dt1.setOffsetFromUtc(-(2 * 60 * 60)); // Minus two hours.
- dt2.setOffsetFromUtc(-(3 * 60 * 60)); // Minus three hours.
+ dt1.setTimeZone(QTimeZone::fromSecondsAheadOfUtc(-(2 * 60 * 60))); // Minus two hours.
+ dt2.setTimeZone(QTimeZone::fromSecondsAheadOfUtc(-(3 * 60 * 60))); // Minus three hours.
QVERIFY(dt1 != dt2);
QVERIFY(!(dt1 == dt2));
@@ -3308,14 +3806,14 @@ void tst_QDateTime::utcOffsetLessThan() const
void tst_QDateTime::isDaylightTime() const
{
- QDateTime utc1(QDate(2012, 1, 1), QTime(0, 0), Qt::UTC);
+ QDateTime utc1(QDate(2012, 1, 1), QTime(0, 0), UTC);
QVERIFY(!utc1.isDaylightTime());
- QDateTime utc2(QDate(2012, 6, 1), QTime(0, 0), Qt::UTC);
+ QDateTime utc2(QDate(2012, 6, 1), QTime(0, 0), UTC);
QVERIFY(!utc2.isDaylightTime());
- QDateTime offset1(QDate(2012, 1, 1), QTime(0, 0), Qt::OffsetFromUTC, 1 * 60 * 60);
+ QDateTime offset1(QDate(2012, 1, 1), QTime(0, 0), QTimeZone::fromSecondsAheadOfUtc(60 * 60));
QVERIFY(!offset1.isDaylightTime());
- QDateTime offset2(QDate(2012, 6, 1), QTime(0, 0), Qt::OffsetFromUTC, 1 * 60 * 60);
+ QDateTime offset2(QDate(2012, 6, 1), QTime(0, 0), QTimeZone::fromSecondsAheadOfUtc(60 * 60));
QVERIFY(!offset2.isDaylightTime());
if (zoneIsCET) {
@@ -3344,8 +3842,8 @@ void tst_QDateTime::daylightTransitions() const
const qint64 spring2012 = 1332637200000;
const qint64 autumn2012 = 1351386000000;
const qint64 msecsOneHour = 3600000;
- QCOMPARE(spring2012, QDateTime(QDate(2012, 3, 25), QTime(1, 0), Qt::UTC).toMSecsSinceEpoch());
- QCOMPARE(autumn2012, QDateTime(QDate(2012, 10, 28), QTime(1, 0), Qt::UTC).toMSecsSinceEpoch());
+ QCOMPARE(spring2012, QDateTime(QDate(2012, 3, 25), QTime(1, 0), UTC).toMSecsSinceEpoch());
+ QCOMPARE(autumn2012, QDateTime(QDate(2012, 10, 28), QTime(1, 0), UTC).toMSecsSinceEpoch());
// Test for correct behviour for StandardTime -> DaylightTime transition, i.e. missing hour
@@ -3353,19 +3851,32 @@ void tst_QDateTime::daylightTransitions() const
QDateTime before(QDate(2012, 3, 25), QTime(1, 59, 59, 999));
QVERIFY(before.isValid());
+ QVERIFY(!before.isDaylightTime());
QCOMPARE(before.date(), QDate(2012, 3, 25));
QCOMPARE(before.time(), QTime(1, 59, 59, 999));
QCOMPARE(before.toMSecsSinceEpoch(), spring2012 - 1);
- QDateTime missing(QDate(2012, 3, 25), QTime(2, 0));
- QVERIFY(!missing.isValid());
- QCOMPARE(missing.date(), QDate(2012, 3, 25));
- QCOMPARE(missing.time(), QTime(2, 0));
- // datetimeparser relies on toMSecsSinceEpoch to still work:
- QCOMPARE(missing.toMSecsSinceEpoch(), spring2012);
+ QDateTime entering(QDate(2012, 3, 25), QTime(2, 0),
+ QDateTime::TransitionResolution::PreferBefore);
+ QVERIFY(entering.isValid());
+ QVERIFY(!entering.isDaylightTime());
+ QCOMPARE(entering.date(), QDate(2012, 3, 25));
+ QCOMPARE(entering.time(), QTime(1, 0));
+ // QDateTimeParser relies on toMSecsSinceEpoch() to still work:
+ QCOMPARE(entering.toMSecsSinceEpoch(), spring2012 - msecsOneHour);
+
+ QDateTime leaving(QDate(2012, 3, 25), QTime(2, 0),
+ QDateTime::TransitionResolution::PreferAfter);
+ QVERIFY(leaving.isValid());
+ QVERIFY(leaving.isDaylightTime());
+ QCOMPARE(leaving.date(), QDate(2012, 3, 25));
+ QCOMPARE(leaving.time(), QTime(3, 0));
+ // QDateTimeParser relies on toMSecsSinceEpoch to still work:
+ QCOMPARE(leaving.toMSecsSinceEpoch(), spring2012);
QDateTime after(QDate(2012, 3, 25), QTime(3, 0));
QVERIFY(after.isValid());
+ QVERIFY(after.isDaylightTime());
QCOMPARE(after.date(), QDate(2012, 3, 25));
QCOMPARE(after.time(), QTime(3, 0));
QCOMPARE(after.toMSecsSinceEpoch(), spring2012);
@@ -3385,19 +3896,18 @@ void tst_QDateTime::daylightTransitions() const
QCOMPARE(after.toMSecsSinceEpoch(), spring2012);
// Test changing time spec re-validates the date/time
-
- QDateTime utc(QDate(2012, 3, 25), QTime(2, 0), Qt::UTC);
+ QDateTime utc(QDate(2012, 3, 25), QTime(2, 0), UTC);
QVERIFY(utc.isValid());
QCOMPARE(utc.date(), QDate(2012, 3, 25));
QCOMPARE(utc.time(), QTime(2, 0));
- utc.setTimeSpec(Qt::LocalTime);
- QVERIFY(!utc.isValid());
+ utc.setTimeZone(QTimeZone::LocalTime); // Resolved to RelativeToBefore.
+ QVERIFY(utc.isValid());
QCOMPARE(utc.date(), QDate(2012, 3, 25));
- QCOMPARE(utc.time(), QTime(2, 0));
- utc.setTimeSpec(Qt::UTC);
+ QCOMPARE(utc.time(), QTime(3, 0));
+ utc.setTimeZone(UTC); // Preserves the changed time().
QVERIFY(utc.isValid());
QCOMPARE(utc.date(), QDate(2012, 3, 25));
- QCOMPARE(utc.time(), QTime(2, 0));
+ QCOMPARE(utc.time(), QTime(3, 0));
// Test date maths, if result falls in missing hour then becomes next
// hour (or is always invalid; mktime() may reject gap-times).
@@ -3435,19 +3945,17 @@ void tst_QDateTime::daylightTransitions() const
#undef CHECK_SPRING_FORWARD
// Test for correct behviour for DaylightTime -> StandardTime transition, fall-back
- // TODO (QTBUG-79923): Compare to results of direct QDateTime(date, time, fold)
- // construction; see Prior/Post commented-out tests.
QDateTime autumnMidnight = QDate(2012, 10, 28).startOfDay();
QVERIFY(autumnMidnight.isValid());
- // QCOMPARE(autumnMidnight, QDateTime(QDate(2012, 10, 28), QTime(2, 0), Prior));
QCOMPARE(autumnMidnight.date(), QDate(2012, 10, 28));
QCOMPARE(autumnMidnight.time(), QTime(0, 0));
QCOMPARE(autumnMidnight.toMSecsSinceEpoch(), autumn2012 - 3 * msecsOneHour);
QDateTime startFirst = autumnMidnight.addMSecs(2 * msecsOneHour);
QVERIFY(startFirst.isValid());
- // QCOMPARE(startFirst, QDateTime(QDate(2012, 10, 28), QTime(2, 0), Prior));
+ QCOMPARE(startFirst, QDateTime(QDate(2012, 10, 28), QTime(2, 0),
+ QDateTime::TransitionResolution::PreferBefore));
QCOMPARE(startFirst.date(), QDate(2012, 10, 28));
QCOMPARE(startFirst.time(), QTime(2, 0));
QCOMPARE(startFirst.toMSecsSinceEpoch(), autumn2012 - msecsOneHour);
@@ -3455,7 +3963,9 @@ void tst_QDateTime::daylightTransitions() const
// 1 msec before transition is 2:59:59.999 FirstOccurrence
QDateTime endFirst = startFirst.addMSecs(msecsOneHour - 1);
QVERIFY(endFirst.isValid());
- // QCOMPARE(endFirst, QDateTime(QDate(2012, 10, 28), QTime(2, 59, 59, 999), Prior));
+ QCOMPARE(endFirst,
+ QDateTime(QDate(2012, 10, 28), QTime(2, 59, 59, 999),
+ QDateTime::TransitionResolution::PreferBefore));
QCOMPARE(endFirst.date(), QDate(2012, 10, 28));
QCOMPARE(endFirst.time(), QTime(2, 59, 59, 999));
QCOMPARE(endFirst.toMSecsSinceEpoch(), autumn2012 - 1);
@@ -3463,7 +3973,8 @@ void tst_QDateTime::daylightTransitions() const
// At the transition, starting the second pass
QDateTime startRepeat = endFirst.addMSecs(1);
QVERIFY(startRepeat.isValid());
- // QCOMPARE(startRepeat, QDateTime(QDate(2012, 10, 28), QTime(2, 0), Post));
+ QCOMPARE(startRepeat, QDateTime(QDate(2012, 10, 28), QTime(2, 0),
+ QDateTime::TransitionResolution::PreferAfter));
QCOMPARE(startRepeat.date(), QDate(2012, 10, 28));
QCOMPARE(startRepeat.time(), QTime(2, 0));
QCOMPARE(startRepeat.toMSecsSinceEpoch(), autumn2012);
@@ -3471,7 +3982,9 @@ void tst_QDateTime::daylightTransitions() const
// 59:59.999 after transition is 2:59:59.999 SecondOccurrence
QDateTime endRepeat = endFirst.addMSecs(msecsOneHour);
QVERIFY(endRepeat.isValid());
- // QCOMPARE(endRepeat, QDateTime(QDate(2012, 10, 28), QTime(2, 59, 59, 999), Post));
+ QCOMPARE(endRepeat,
+ QDateTime(QDate(2012, 10, 28), QTime(2, 59, 59, 999),
+ QDateTime::TransitionResolution::PreferAfter));
QCOMPARE(endRepeat.date(), QDate(2012, 10, 28));
QCOMPARE(endRepeat.time(), QTime(2, 59, 59, 999));
QCOMPARE(endRepeat.toMSecsSinceEpoch(), autumn2012 + msecsOneHour - 1);
@@ -3727,9 +4240,9 @@ void tst_QDateTime::timeZones() const
{
#if QT_CONFIG(timezone)
QTimeZone invalidTz = QTimeZone("Vulcan/ShiKahr");
- QCOMPARE(invalidTz.isValid(), false);
+ QVERIFY(!invalidTz.isValid());
QDateTime invalidDateTime = QDateTime(QDate(2000, 1, 1), QTime(0, 0), invalidTz);
- QCOMPARE(invalidDateTime.isValid(), false);
+ QVERIFY(!invalidDateTime.isValid());
QCOMPARE(invalidDateTime.date(), QDate(2000, 1, 1));
QCOMPARE(invalidDateTime.time(), QTime(0, 0));
@@ -3737,39 +4250,39 @@ void tst_QDateTime::timeZones() const
QTimeZone nzTzOffset = QTimeZone(12 * 3600);
// During Standard Time NZ is +12:00
- QDateTime utcStd(QDate(2012, 6, 1), QTime(0, 0), Qt::UTC);
+ QDateTime utcStd(QDate(2012, 6, 1), QTime(0, 0), UTC);
QDateTime nzStd(QDate(2012, 6, 1), QTime(12, 0), nzTz);
QDateTime nzStdOffset(QDate(2012, 6, 1), QTime(12, 0), nzTzOffset);
- QCOMPARE(nzStd.isValid(), true);
+ QVERIFY(nzStd.isValid());
QCOMPARE(nzStd.timeSpec(), Qt::TimeZone);
QCOMPARE(nzStd.date(), QDate(2012, 6, 1));
QCOMPARE(nzStd.time(), QTime(12, 0));
QVERIFY(nzStd.timeZone() == nzTz);
QCOMPARE(nzStd.timeZone().id(), QByteArray("Pacific/Auckland"));
QCOMPARE(nzStd.offsetFromUtc(), 43200);
- QCOMPARE(nzStd.isDaylightTime(), false);
+ QVERIFY(!nzStd.isDaylightTime());
QCOMPARE(nzStd.toMSecsSinceEpoch(), utcStd.toMSecsSinceEpoch());
- QCOMPARE(nzStdOffset.isValid(), true);
+ QVERIFY(nzStdOffset.isValid());
QCOMPARE(nzStdOffset.timeSpec(), Qt::TimeZone);
QCOMPARE(nzStdOffset.date(), QDate(2012, 6, 1));
QCOMPARE(nzStdOffset.time(), QTime(12, 0));
QVERIFY(nzStdOffset.timeZone() == nzTzOffset);
- QCOMPARE(nzStdOffset.timeZone().id(), QByteArray("UTC+12"));
+ QCOMPARE(nzStdOffset.timeZone().id(), QByteArray("UTC+12:00"));
QCOMPARE(nzStdOffset.offsetFromUtc(), 43200);
- QCOMPARE(nzStdOffset.isDaylightTime(), false);
+ QVERIFY(!nzStdOffset.isDaylightTime());
QCOMPARE(nzStdOffset.toMSecsSinceEpoch(), utcStd.toMSecsSinceEpoch());
// During Daylight Time NZ is +13:00
- QDateTime utcDst(QDate(2012, 1, 1), QTime(0, 0), Qt::UTC);
+ QDateTime utcDst(QDate(2012, 1, 1), QTime(0, 0), UTC);
QDateTime nzDst(QDate(2012, 1, 1), QTime(13, 0), nzTz);
- QCOMPARE(nzDst.isValid(), true);
+ QVERIFY(nzDst.isValid());
QCOMPARE(nzDst.date(), QDate(2012, 1, 1));
QCOMPARE(nzDst.time(), QTime(13, 0));
QCOMPARE(nzDst.offsetFromUtc(), 46800);
- QCOMPARE(nzDst.isDaylightTime(), true);
+ QVERIFY(nzDst.isDaylightTime());
QCOMPARE(nzDst.toMSecsSinceEpoch(), utcDst.toMSecsSinceEpoch());
QDateTime utc = nzStd.toUTC();
@@ -3789,7 +4302,7 @@ void tst_QDateTime::timeZones() const
QCOMPARE(aus.date(), QDate(2012, 6, 1));
QCOMPARE(aus.time(), QTime(10, 0));
- QDateTime dt1(QDate(2012, 6, 1), QTime(0, 0), Qt::UTC);
+ QDateTime dt1(QDate(2012, 6, 1), QTime(0, 0), UTC);
QCOMPARE(dt1.timeSpec(), Qt::UTC);
dt1.setTimeZone(nzTz);
QCOMPARE(dt1.timeSpec(), Qt::TimeZone);
@@ -3801,13 +4314,13 @@ void tst_QDateTime::timeZones() const
QCOMPARE(dt2.date(), dt1.date());
QCOMPARE(dt2.time(), dt1.time());
QCOMPARE(dt2.timeSpec(), dt1.timeSpec());
- QCOMPARE(dt2.timeZone(), dt1.timeZone());
+ QCOMPARE(dt2.timeRepresentation(), dt1.timeRepresentation());
QDateTime dt3 = QDateTime::fromMSecsSinceEpoch(1338465600000, nzTz);
QCOMPARE(dt3.date(), dt1.date());
QCOMPARE(dt3.time(), dt1.time());
QCOMPARE(dt3.timeSpec(), dt1.timeSpec());
- QCOMPARE(dt3.timeZone(), dt1.timeZone());
+ QCOMPARE(dt3.timeRepresentation(), dt1.timeRepresentation());
// The start of year 1 should be *describable* in any zone (QTBUG-78051)
dt3 = QDateTime(QDate(1, 1, 1), QTime(0, 0), ausTz);
@@ -3837,7 +4350,7 @@ void tst_QDateTime::timeZones() const
// Standard Time to Daylight Time 2013 on 2013-03-31 is 2:00 local time / 1:00 UTC
const qint64 gapMSecs = 1364691600000;
- QCOMPARE(gapMSecs, QDateTime(QDate(2013, 3, 31), QTime(1, 0), Qt::UTC).toMSecsSinceEpoch());
+ QCOMPARE(gapMSecs, QDateTime(QDate(2013, 3, 31), QTime(1, 0), UTC).toMSecsSinceEpoch());
// Test MSecs to local
// - Test 1 msec before tran = 01:59:59.999
@@ -3864,18 +4377,57 @@ void tst_QDateTime::timeZones() const
QCOMPARE(atGap.toMSecsSinceEpoch(), gapMSecs);
// - Test transition hole, setting 02:00:00 is invalid
QDateTime inGap = QDateTime(QDate(2013, 3, 31), QTime(2, 0), cet);
- QVERIFY(!inGap.isValid());
+ QVERIFY(inGap.isValid());
QCOMPARE(inGap.date(), QDate(2013, 3, 31));
- QCOMPARE(inGap.time(), QTime(2, 0));
- // - Test transition hole, setting 02:59:59.999 is invalid
+ QCOMPARE(inGap.time(), QTime(3, 0));
+ QCOMPARE(inGap.offsetFromUtc(), 7200);
+ // - Test transition hole, 02:59:59.999 was skipped:
inGap = QDateTime(QDate(2013, 3, 31), QTime(2, 59, 59, 999), cet);
- QVERIFY(!inGap.isValid());
+ QVERIFY(inGap.isValid());
QCOMPARE(inGap.date(), QDate(2013, 3, 31));
- QCOMPARE(inGap.time(), QTime(2, 59, 59, 999));
+ QCOMPARE(inGap.time(), QTime(3, 59, 59, 999));
+ QCOMPARE(inGap.offsetFromUtc(), 7200);
+ // Test similar for local time, if it's CET:
+ if (zoneIsCET) {
+ inGap = QDateTime(QDate(2013, 3, 31), QTime(2, 30));
+ QVERIFY(inGap.isValid());
+ QCOMPARE(inGap.date(), QDate(2013, 3, 31));
+ QCOMPARE(inGap.offsetFromUtc(), 7200);
+ QCOMPARE(inGap.time(), QTime(3, 30));
+ }
+
+ // Test a gap more than 1'141'707.91-years from 1970, outside ShortData's range,
+ // The zone version is non-short in any case, but check it anyway.
+ // However, we can only test this if the underlying OS believes CET continues
+ // exercising DST indefinitely; Darwin, for example, assumes we'll have all
+ // kicked the habit by the end of 2100.
+ constexpr int longYear = 1'143'678;
+ constexpr qint64 millisInWeek = qint64(7) * 24 * 60 * 60 * 1000;
+ if (QDateTime(QDate(longYear, 3, 24), QTime(12, 0), cet).msecsTo(
+ QDateTime(QDate(longYear, 3, 31), QTime(12, 0), cet)) < millisInWeek) {
+ inGap = QDateTime(QDate(longYear, 3, 27), QTime(2, 30), cet);
+ QVERIFY(inGap.isValid());
+ QCOMPARE(inGap.date(), QDate(longYear, 3, 27));
+ QCOMPARE(inGap.time(), QTime(3, 30));
+ QCOMPARE(inGap.offsetFromUtc(), 7200);
+ } else {
+ qDebug("Skipping far-future check beyond zoned end of DST");
+ }
+ if (zoneIsCET && QDateTime(QDate(longYear, 3, 24), QTime(12, 0)).msecsTo(
+ QDateTime(QDate(longYear, 3, 31), QTime(12, 0))) < millisInWeek) {
+ inGap = QDateTime(QDate(longYear, 3, 27), QTime(2, 30));
+ QVERIFY(inGap.isValid());
+ QCOMPARE(inGap.date(), QDate(longYear, 3, 27));
+ QCOMPARE(inGap.offsetFromUtc(), 7200);
+ QCOMPARE(inGap.time(), QTime(3, 30));
+ } else {
+ qDebug(zoneIsCET ? "Skipping far-future check beyond local end of DST"
+ : "Skipping CET-specific test");
+ }
// Standard Time to Daylight Time 2013 on 2013-10-27 is 3:00 local time / 1:00 UTC
const qint64 replayMSecs = 1382835600000;
- QCOMPARE(replayMSecs, QDateTime(QDate(2013, 10, 27), QTime(1, 0), Qt::UTC).toMSecsSinceEpoch());
+ QCOMPARE(replayMSecs, QDateTime(QDate(2013, 10, 27), QTime(1, 0), UTC).toMSecsSinceEpoch());
// Test MSecs to local
// - Test 1 hour before tran = 02:00:00 local first occurrence
@@ -3897,7 +4449,7 @@ void tst_QDateTime::timeZones() const
// - Test 1 hour after tran = 03:00:00 local
QDateTime hourAfter = QDateTime::fromMSecsSinceEpoch(replayMSecs + 3600000, cet);
QCOMPARE(hourAfter.date(), QDate(2013, 10, 27));
- QCOMPARE(hourAfter.time(), QTime(3, 0, 0));
+ QCOMPARE(hourAfter.time(), QTime(3, 0));
// TODO (QTBUG-79923): Compare to results of direct QDateTime(date, time, cet, fold)
// construction; see Prior/Post commented-out tests.
@@ -3949,14 +4501,14 @@ void tst_QDateTime::systemTimeZoneChange() const
// Start out in Brisbane time:
TimeZoneRollback useZone(QByteArray("AEST-10:00"));
- if (QDateTime(date, early, Qt::LocalTime).offsetFromUtc() != 600 * 60)
+ if (QDateTime(date, early).offsetFromUtc() != 600 * 60)
QSKIP("Test depends on system support for changing zone to AEST-10:00");
#if QT_CONFIG(timezone)
QVERIFY(QTimeZone::systemTimeZone().isValid());
#endif
- const QDateTime localDate = QDateTime(date, early, Qt::LocalTime);
- const QDateTime utcDate = QDateTime(date, early, Qt::UTC);
+ const QDateTime localDate = QDateTime(date, early);
+ const QDateTime utcDate = QDateTime(date, early, UTC);
const qint64 localMsecs = localDate.toMSecsSinceEpoch();
const qint64 utcMsecs = utcDate.toMSecsSinceEpoch();
#if QT_CONFIG(timezone)
@@ -3973,16 +4525,16 @@ void tst_QDateTime::systemTimeZoneChange() const
// Change to Indian time
useZone.reset(QByteArray("IST-05:30"));
- if (QDateTime(date, early, Qt::LocalTime).offsetFromUtc() != 330 * 60)
+ if (QDateTime(date, early).offsetFromUtc() != 330 * 60)
QSKIP("Test depends on system support for changing zone to IST-05:30");
#if QT_CONFIG(timezone)
QVERIFY(QTimeZone::systemTimeZone().isValid());
#endif
- QCOMPARE(localDate, QDateTime(date, early, Qt::LocalTime));
+ QCOMPARE(localDate, QDateTime(date, early));
// Note: localDate.toMSecsSinceEpoch == localMsecs, unchanged, iff localDate is pimpled.
- QVERIFY(localMsecs != QDateTime(date, early, Qt::LocalTime).toMSecsSinceEpoch());
- QCOMPARE(utcDate, QDateTime(date, early, Qt::UTC));
+ QVERIFY(localMsecs != QDateTime(date, early).toMSecsSinceEpoch());
+ QCOMPARE(utcDate, QDateTime(date, early, UTC));
QCOMPARE(utcDate.toMSecsSinceEpoch(), utcMsecs);
#if QT_CONFIG(timezone)
QCOMPARE(tzDate.toMSecsSinceEpoch(), tzMsecs);
@@ -4002,17 +4554,19 @@ void tst_QDateTime::invalid_data() const
QTest::newRow("simple") << invalidDate << Qt::LocalTime << true;
QTest::newRow("UTC") << invalidDate.toUTC() << Qt::UTC << true;
QTest::newRow("offset")
- << invalidDate.toOffsetFromUtc(3600) << Qt::OffsetFromUTC << true;
+ << invalidDate.toTimeZone(QTimeZone::fromSecondsAheadOfUtc(3600)) << Qt::OffsetFromUTC
+ << true;
#if QT_CONFIG(timezone)
QTest::newRow("CET")
<< invalidDate.toTimeZone(QTimeZone("Europe/Oslo")) << Qt::TimeZone << true;
// Crash tests, QTBUG-80146:
QTest::newRow("nozone+construct")
- << QDateTime(QDate(1970, 1, 1), QTime(12, 0), QTimeZone()) << Qt::TimeZone << false;
+ << QDateTime(QDate(1970, 1, 1), QTime(12, 0), QTimeZone())
+ << Qt::TimeZone << false;
QTest::newRow("nozone+fromMSecs")
<< QDateTime::fromMSecsSinceEpoch(42, QTimeZone()) << Qt::TimeZone << false;
- QDateTime valid(QDate(1970, 1, 1), QTime(12, 0), Qt::UTC);
+ QDateTime valid(QDate(1970, 1, 1), QTime(12, 0), UTC);
QTest::newRow("tonozone") << valid.toTimeZone(QTimeZone()) << Qt::TimeZone << false;
#endif
}
@@ -4028,38 +4582,36 @@ void tst_QDateTime::invalid() const
if (!goodZone)
QCOMPARE(when.toMSecsSinceEpoch(), 0);
QVERIFY(!when.isDaylightTime());
-#if QT_CONFIG(timezone)
- QCOMPARE(when.timeZone().isValid(), goodZone);
-#endif
+ QCOMPARE(when.timeRepresentation().isValid(), goodZone);
}
void tst_QDateTime::range() const
{
using Bounds = std::numeric_limits<qint64>;
- QCOMPARE(QDateTime::fromMSecsSinceEpoch(Bounds::min() + 1, Qt::UTC).date().year(),
+ QCOMPARE(QDateTime::fromMSecsSinceEpoch(Bounds::min() + 1, UTC).date().year(),
int(QDateTime::YearRange::First));
- QCOMPARE(QDateTime::fromMSecsSinceEpoch(Bounds::max() - 1, Qt::UTC).date().year(),
+ QCOMPARE(QDateTime::fromMSecsSinceEpoch(Bounds::max() - 1, UTC).date().year(),
int(QDateTime::YearRange::Last));
constexpr qint64 millisPerDay = 24 * 3600 * 1000;
constexpr qint64 wholeDays = Bounds::max() / millisPerDay;
constexpr qint64 millisRemainder = Bounds::max() % millisPerDay;
QVERIFY(QDateTime(QDate(1970, 1, 1).addDays(wholeDays),
QTime::fromMSecsSinceStartOfDay(millisRemainder),
- Qt::UTC).isValid());
+ UTC).isValid());
QVERIFY(!QDateTime(QDate(1970, 1, 1).addDays(wholeDays),
QTime::fromMSecsSinceStartOfDay(millisRemainder + 1),
- Qt::UTC).isValid());
+ UTC).isValid());
QVERIFY(QDateTime(QDate(1970, 1, 1).addDays(-wholeDays - 1),
QTime::fromMSecsSinceStartOfDay(3600 * 24000 - millisRemainder - 1),
- Qt::UTC).isValid());
+ UTC).isValid());
QVERIFY(!QDateTime(QDate(1970, 1, 1).addDays(-wholeDays - 1),
QTime::fromMSecsSinceStartOfDay(3600 * 24000 - millisRemainder - 2),
- Qt::UTC).isValid());
+ UTC).isValid());
}
void tst_QDateTime::macTypes()
{
-#ifndef Q_OS_MAC
+#ifndef Q_OS_DARWIN
QSKIP("This is a Apple-only test");
#else
extern void tst_QDateTime_macTypes(); // in qdatetime_mac.mm
@@ -4067,5 +4619,223 @@ void tst_QDateTime::macTypes()
#endif
}
+#if __cpp_lib_chrono >= 201907L
+using StdSysMillis = std::chrono::sys_time<std::chrono::milliseconds>;
+Q_DECLARE_METATYPE(StdSysMillis);
+#endif
+
+void tst_QDateTime::stdCompatibilitySysTime_data()
+{
+#if __cpp_lib_chrono >= 201907L
+ QTest::addColumn<StdSysMillis>("sysTime");
+ QTest::addColumn<QDateTime>("expected");
+
+ using namespace std::chrono;
+
+ QTest::newRow("zero")
+ << StdSysMillis(0s)
+ << QDateTime(QDate(1970, 1, 1), QTime(0, 0), UTC);
+ QTest::newRow("1s")
+ << StdSysMillis(1s)
+ << QDateTime(QDate(1970, 1, 1), QTime(0, 0, 1), UTC);
+ QTest::newRow("1ms")
+ << StdSysMillis(1ms)
+ << QDateTime(QDate(1970, 1, 1), QTime(0, 0, 0, 1), UTC);
+ QTest::newRow("365d")
+ << StdSysMillis(days(365))
+ << QDateTime(QDate(1971, 1, 1), QTime(0, 0), UTC);
+ QTest::newRow("-1s")
+ << StdSysMillis(-1s)
+ << QDateTime(QDate(1969, 12, 31), QTime(23, 59, 59), UTC);
+ QTest::newRow("-1ms")
+ << StdSysMillis(-1ms)
+ << QDateTime(QDate(1969, 12, 31), QTime(23, 59, 59, 999), UTC);
+
+ {
+ // The first leap second occurred on 30 June 1972 at 23:59:60.
+ // Check that QDateTime does not take that leap second into account (like sys_time)
+ const year_month_day firstLeapSecondDate = 1972y/July/1;
+ const sys_days firstLeapSecondDateAsSysDays = firstLeapSecondDate;
+ QTest::newRow("first_leap_second")
+ << StdSysMillis(firstLeapSecondDateAsSysDays)
+ << QDateTime(QDate(1972, 7, 1), QTime(0, 0), UTC);
+ }
+
+ {
+ // Random date
+ const sys_days date = 2000y/January/31;
+ const StdSysMillis dateTime = date + 3h + 10min + 42s;
+ QTest::newRow("2000-01-31 03:10:42")
+ << dateTime
+ << QDateTime(QDate(2000, 1, 31), QTime(3, 10, 42), UTC);
+ }
+#else
+ QSKIP("This test requires C++20's <chrono>.");
+#endif
+}
+
+void tst_QDateTime::stdCompatibilitySysTime()
+{
+#if __cpp_lib_chrono >= 201907L
+ QFETCH(StdSysMillis, sysTime);
+ QFETCH(QDateTime, expected);
+
+ using namespace std::chrono;
+
+ // system_clock in milliseconds -> QDateTime
+ QDateTime dtFromSysTime = QDateTime::fromStdTimePoint(sysTime);
+ QCOMPARE(dtFromSysTime, expected);
+ QCOMPARE(dtFromSysTime.timeSpec(), Qt::UTC);
+
+ // QDateTime -> system_clock in milliseconds
+ StdSysMillis sysTimeFromDt = dtFromSysTime.toStdSysMilliseconds();
+ QCOMPARE(sysTimeFromDt, sysTime);
+
+ // system_clock in seconds -> QDateTime
+ sys_seconds sysTimeSecs = floor<seconds>(sysTime);
+ QDateTime dtFromSysSeconds = QDateTime::fromStdTimePoint(sysTimeSecs);
+ QDateTime expectedInSeconds = expected.addMSecs(-expected.time().msec()); // "floor"
+ QCOMPARE(dtFromSysSeconds, expectedInSeconds);
+ QCOMPARE(dtFromSysSeconds.timeSpec(), Qt::UTC);
+
+ // QDateTime -> system_clock in seconds
+ sys_seconds sysTimeFromDtSecs = dtFromSysSeconds.toStdSysSeconds();
+ QCOMPARE(sysTimeFromDtSecs, sysTimeSecs);
+
+ // utc_clock in milliseconds -> QDateTime
+ utc_time<std::chrono::milliseconds> utcTime = utc_clock::from_sys(sysTime);
+ QDateTime dtFromUtcTime = QDateTime::fromStdTimePoint(utcTime);
+ QCOMPARE(dtFromUtcTime, expected);
+ QCOMPARE(dtFromUtcTime.timeSpec(), Qt::UTC);
+
+ // QDateTime -> system_clock in milliseconds
+ sysTimeFromDt = dtFromUtcTime.toStdSysMilliseconds();
+ QCOMPARE(sysTimeFromDt, sysTime);
+#else
+ QSKIP("This test requires C++20's <chrono>.");
+#endif
+}
+
+#if __cpp_lib_chrono >= 201907L
+using StdLocalMillis = std::chrono::local_time<std::chrono::milliseconds>;
+Q_DECLARE_METATYPE(StdLocalMillis);
+#endif
+
+void tst_QDateTime::stdCompatibilityLocalTime_data()
+{
+#if __cpp_lib_chrono >= 201907L
+ QTest::addColumn<StdLocalMillis>("localTime");
+ QTest::addColumn<QDateTime>("expected");
+
+ using namespace std::chrono;
+
+ QTest::newRow("zero")
+ << StdLocalMillis(0s)
+ << QDateTime(QDate(1970, 1, 1), QTime(0, 0));
+ QTest::newRow("1s")
+ << StdLocalMillis(1s)
+ << QDateTime(QDate(1970, 1, 1), QTime(0, 0, 1));
+ QTest::newRow("1ms")
+ << StdLocalMillis(1ms)
+ << QDateTime(QDate(1970, 1, 1), QTime(0, 0, 0, 1));
+ QTest::newRow("365d")
+ << StdLocalMillis(days(365))
+ << QDateTime(QDate(1971, 1, 1), QTime(0, 0));
+ QTest::newRow("-1s")
+ << StdLocalMillis(-1s)
+ << QDateTime(QDate(1969, 12, 31), QTime(23, 59, 59));
+ QTest::newRow("-1ms")
+ << StdLocalMillis(-1ms)
+ << QDateTime(QDate(1969, 12, 31), QTime(23, 59, 59, 999));
+ {
+ // Random date
+ const local_days date = local_days(2000y/January/31);
+ const StdLocalMillis dateTime = date + 3h + 10min + 42s;
+ QTest::newRow("2000-01-31 03:10:42")
+ << dateTime
+ << QDateTime(QDate(2000, 1, 31), QTime(3, 10, 42));
+ }
+#else
+ QSKIP("This test requires C++20's <chrono>.");
+#endif
+}
+
+void tst_QDateTime::stdCompatibilityLocalTime()
+{
+#if __cpp_lib_chrono >= 201907L
+ QFETCH(StdLocalMillis, localTime);
+ QFETCH(QDateTime, expected);
+
+ using namespace std::chrono;
+
+ QDateTime dtFromLocalTime = QDateTime::fromStdLocalTime(localTime);
+ QCOMPARE(dtFromLocalTime, expected);
+ QCOMPARE(dtFromLocalTime.timeSpec(), Qt::LocalTime);
+
+ const time_zone *tz = current_zone();
+ QVERIFY(tz);
+ const StdSysMillis sysMillis = tz->to_sys(localTime);
+ QCOMPARE(dtFromLocalTime.toStdSysMilliseconds(), sysMillis);
+#else
+ QSKIP("This test requires C++20's <chrono>.");
+#endif
+}
+
+#if QT_CONFIG(timezone)
+#if __cpp_lib_chrono >= 201907L
+using StdZonedMillis = std::chrono::zoned_time<std::chrono::milliseconds>;
+Q_DECLARE_METATYPE(StdZonedMillis);
+#endif
+
+void tst_QDateTime::stdCompatibilityZonedTime_data()
+{
+#if __cpp_lib_chrono >= 201907L
+ QTest::addColumn<StdZonedMillis>("zonedTime");
+ QTest::addColumn<QDateTime>("expected");
+
+ using namespace std::chrono;
+ using namespace std::literals;
+
+ const char timeZoneName[] = "Europe/Oslo";
+ const QTimeZone timeZone(timeZoneName);
+
+ {
+ StdZonedMillis zs(timeZoneName, local_days(2021y/1/1));
+ QTest::addRow("localTimeOslo")
+ << zs
+ << QDateTime(QDate(2021, 1, 1), QTime(0, 0), timeZone);
+ }
+ {
+ StdZonedMillis zs(timeZoneName, sys_days(2021y/1/1));
+ QTest::addRow("sysTimeOslo")
+ << zs
+ << QDateTime(QDate(2021, 1, 1), QTime(1, 0), timeZone);
+ }
+ {
+ StdZonedMillis zs(timeZoneName, sys_days(2021y/7/1));
+ QTest::addRow("sysTimeOslo summer")
+ << zs
+ << QDateTime(QDate(2021, 7, 1), QTime(2, 0), timeZone);
+ }
+#else
+ QSKIP("This test requires C++20's <chrono>.");
+#endif
+}
+
+void tst_QDateTime::stdCompatibilityZonedTime()
+{
+#if __cpp_lib_chrono >= 201907L
+ QFETCH(StdZonedMillis, zonedTime);
+ QFETCH(QDateTime, expected);
+
+ QDateTime dtFromZonedTime = QDateTime::fromStdZonedTime(zonedTime);
+ QCOMPARE(dtFromZonedTime, expected);
+ QCOMPARE(dtFromZonedTime.timeSpec(), Qt::TimeZone);
+#else
+ QSKIP("This test requires C++20's <chrono>.");
+#endif
+}
+#endif // QT_CONFIG(timezone)
+
QTEST_APPLESS_MAIN(tst_QDateTime)
#include "tst_qdatetime.moc"
diff --git a/tests/auto/corelib/time/qdatetime/tst_qdatetime_mac.mm b/tests/auto/corelib/time/qdatetime/tst_qdatetime_mac.mm
index 295454c472..08379ccb41 100644
--- a/tests/auto/corelib/time/qdatetime/tst_qdatetime_mac.mm
+++ b/tests/auto/corelib/time/qdatetime/tst_qdatetime_mac.mm
@@ -1,35 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2014 Petroules Corporation.
-** 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) 2020 The Qt Company Ltd.
+// Copyright (C) 2014 Petroules Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtCore/QDateTime>
#include <QTest>
+#include <QtCore/private/qcore_mac_p.h>
+
#include <CoreFoundation/CoreFoundation.h>
#include <Foundation/Foundation.h>
diff --git a/tests/auto/corelib/time/qdatetimeparser/CMakeLists.txt b/tests/auto/corelib/time/qdatetimeparser/CMakeLists.txt
index 9bdeb62501..6bdd66ebfc 100644
--- a/tests/auto/corelib/time/qdatetimeparser/CMakeLists.txt
+++ b/tests/auto/corelib/time/qdatetimeparser/CMakeLists.txt
@@ -1,12 +1,19 @@
-# Generated from qdatetimeparser.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdatetimeparser Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qdatetimeparser LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qdatetimeparser
SOURCES
tst_qdatetimeparser.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
)
diff --git a/tests/auto/corelib/time/qdatetimeparser/tst_qdatetimeparser.cpp b/tests/auto/corelib/time/qdatetimeparser/tst_qdatetimeparser.cpp
index 98dd36bc32..bfc811eebe 100644
--- a/tests/auto/corelib/time/qdatetimeparser/tst_qdatetimeparser.cpp
+++ b/tests/auto/corelib/time/qdatetimeparser/tst_qdatetimeparser.cpp
@@ -1,34 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
#include <private/qdatetimeparser_p.h>
+using namespace Qt::StringLiterals;
+
QT_BEGIN_NAMESPACE
// access to needed members in QDateTimeParser
@@ -71,6 +48,7 @@ class tst_QDateTimeParser : public QObject
Q_OBJECT
private Q_SLOTS:
+ void reparse();
void parseSection_data();
void parseSection();
@@ -78,6 +56,61 @@ private Q_SLOTS:
void intermediateYear();
};
+void tst_QDateTimeParser::reparse()
+{
+ const QDateTime when = QDate(2023, 6, 15).startOfDay();
+ // QTBUG-114575: 6.2 through 6.5 got back a bogus Qt::TimeZone (with zero offset):
+ const auto expect = ([](QStringView name) {
+ // When local time is UTC or a fixed offset from it, the parser prefers
+ // to interpret a UTC or offset suffix as such, rather than as local
+ // time (thereby avoiding DST-ness checks). We have to match that here.
+ if (name == "UTC"_L1)
+ return Qt::UTC;
+ if (name.startsWith(u'+') || name.startsWith(u'-')) {
+ if (std::all_of(name.begin() + 1, name.end(), [](QChar ch) { return ch == u'0'; }))
+ return Qt::UTC;
+ if (std::all_of(name.begin() + 1, name.end(), [](QChar ch) { return ch.isDigit(); }))
+ return Qt::OffsetFromUTC;
+ // Potential hh:mm offset ? Not yet seen as local tzname[] entry.
+ }
+ return Qt::LocalTime;
+ });
+
+ const QStringView format = u"dd/MM/yyyy HH:mm t";
+ QDateTimeParser who(QMetaType::QDateTime, QDateTimeParser::DateTimeEdit);
+ QVERIFY(who.parseFormat(format));
+ {
+ // QDTP defaults to the system locale.
+ const auto state = who.parse(QLocale::system().toString(when, format), -1, when, false);
+ QCOMPARE(state.state, QDateTimeParser::Acceptable);
+ QVERIFY(!state.conflicts);
+ QCOMPARE(state.padded, 0);
+ QCOMPARE(state.value.timeSpec(), expect(when.timeZoneAbbreviation()));
+ QCOMPARE(state.value, when);
+ }
+ {
+ // QDT::toString() uses the C locale:
+ who.setDefaultLocale(QLocale::c());
+ const QString zoneName = ([when]() {
+#if QT_CONFIG(timezone)
+ if (QLocale::c() != QLocale::system()) {
+ const QString local = when.timeRepresentation().displayName(
+ when, QTimeZone::ShortName, QLocale::c());
+ if (!local.isEmpty())
+ return local;
+ }
+#endif
+ return when.timeZoneAbbreviation();
+ })();
+ const auto state = who.parse(when.toString(format), -1, when, false);
+ QCOMPARE(state.state, QDateTimeParser::Acceptable);
+ QVERIFY(!state.conflicts);
+ QCOMPARE(state.padded, 0);
+ QCOMPARE(state.value.timeSpec(), expect(zoneName));
+ QCOMPARE(state.value, when);
+ }
+}
+
void tst_QDateTimeParser::parseSection_data()
{
QTest::addColumn<QString>("format");
@@ -165,10 +198,12 @@ void tst_QDateTimeParser::intermediateYear()
QVERIFY(testParser.parseFormat(format));
+ // Indian/Cocos has a transition at the start of 1900, so it started this
+ // day at 00:02:20, throwing a time offset into QDTP.
QDateTime val(QDate(1900, 1, 1).startOfDay());
const QDateTimeParser::StateNode tmp = testParser.parse(input, -1, val, false);
QCOMPARE(tmp.state, QDateTimeParser::Intermediate);
- QCOMPARE(tmp.value, expected.startOfDay());
+ QCOMPARE(tmp.value.date(), expected);
}
QTEST_APPLESS_MAIN(tst_QDateTimeParser)
diff --git a/tests/auto/corelib/time/qtime/CMakeLists.txt b/tests/auto/corelib/time/qtime/CMakeLists.txt
index 6d3034c595..6fe2968107 100644
--- a/tests/auto/corelib/time/qtime/CMakeLists.txt
+++ b/tests/auto/corelib/time/qtime/CMakeLists.txt
@@ -1,15 +1,23 @@
-# Generated from qtime.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qtime Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtime LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qtime
SOURCES
tst_qtime.cpp
DEFINES
QT_NO_FOREACH
QT_NO_KEYWORDS
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/time/qtime/tst_qtime.cpp b/tests/auto/corelib/time/qtime/tst_qtime.cpp
index 480fbcc14f..c0fdb07115 100644
--- a/tests/auto/corelib/time/qtime/tst_qtime.cpp
+++ b/tests/auto/corelib/time/qtime/tst_qtime.cpp
@@ -1,32 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <private/qglobal_p.h>
+#include <private/qcomparisontesthelper_p.h>
#include <QTest>
#include "qdatetime.h"
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
@@ -52,12 +28,11 @@ private Q_SLOTS:
void addMSecs();
void addSecs_data();
void addSecs();
+ void orderingCompiles();
void operator_eq_eq_data();
void operator_eq_eq();
- void operator_lt();
- void operator_gt();
- void operator_lt_eq();
- void operator_gt_eq();
+ void ordering_data();
+ void ordering();
#if QT_CONFIG(datestring)
# if QT_CONFIG(datetimeparser)
void fromStringFormat_data();
@@ -309,7 +284,7 @@ void tst_QTime::secsTo_data()
QTest::newRow("disregard msec (1s)") << QTime(12, 30, 1, 500) << QTime(12, 30, 2, 400) << 1;
QTest::newRow("disregard msec (0s)") << QTime(12, 30, 1, 500) << QTime(12, 30, 1, 900) << 0;
QTest::newRow("disregard msec (-1s)") << QTime(12, 30, 2, 400) << QTime(12, 30, 1, 500) << -1;
- QTest::newRow("disregard msec (0s)") << QTime(12, 30, 1, 900) << QTime(12, 30, 1, 500) << 0;
+ QTest::newRow("disregard msec (-0s)") << QTime(12, 30, 1, 900) << QTime(12, 30, 1, 500) << 0;
}
void tst_QTime::secsTo()
@@ -345,6 +320,11 @@ void tst_QTime::msecsTo()
QCOMPARE( t1.msecsTo( t2 ), delta );
}
+void tst_QTime::orderingCompiles()
+{
+ QTestPrivate::testAllComparisonOperatorsCompile<QTime>();
+}
+
void tst_QTime::operator_eq_eq_data()
{
QTest::addColumn<QTime>("t1");
@@ -370,169 +350,42 @@ void tst_QTime::operator_eq_eq()
QFETCH(QTime, t2);
QFETCH(bool, expectEqual);
- bool equal = t1 == t2;
- QCOMPARE(equal, expectEqual);
- bool notEqual = t1 != t2;
- QCOMPARE(notEqual, !expectEqual);
+ QT_TEST_EQUALITY_OPS(t1, t2, expectEqual);
- if (equal)
+ if (expectEqual)
QVERIFY(qHash(t1) == qHash(t2));
}
-void tst_QTime::operator_lt()
+void tst_QTime::ordering_data()
{
- QTime t1(0,0,0,0);
- QTime t2(0,0,0,0);
- QVERIFY( !(t1 < t2) );
-
- t1 = QTime(12,34,56,20);
- t2 = QTime(12,34,56,30);
- QVERIFY( t1 < t2 );
-
- t1 = QTime(13,34,46,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 < t2 );
-
- t1 = QTime(13,24,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 < t2 );
-
- t1 = QTime(12,34,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 < t2 );
-
- t1 = QTime(14,34,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 < t2) );
-
- t1 = QTime(13,44,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 < t2) );
-
- t1 = QTime(13,34,56,20);
- t2 = QTime(13,34,46,20);
- QVERIFY( !(t1 < t2) );
-
- t1 = QTime(13,44,56,30);
- t2 = QTime(13,44,56,20);
- QVERIFY( !(t1 < t2) );
+ QTest::addColumn<QTime>("left");
+ QTest::addColumn<QTime>("right");
+ QTest::addColumn<Qt::strong_ordering>("expectedOrdering");
+
+ auto generateRow = [](QTime t1, QTime t2, Qt::strong_ordering ordering) {
+ const QByteArray t1Str = t1.toString("hh:mm:ss.zz").toLatin1();
+ const QByteArray t2Str = t2.toString("hh:mm:ss.zz").toLatin1();
+ QTest::addRow("%s_vs_%s", t1Str.constData(), t2Str.constData()) << t1 << t2 << ordering;
+ };
+
+ generateRow(QTime(0, 0), QTime(0, 0), Qt::strong_ordering::equivalent);
+ generateRow(QTime(12, 34, 56, 20), QTime(12, 34, 56, 30), Qt::strong_ordering::less);
+ generateRow(QTime(13, 34, 46, 20), QTime(13, 34, 56, 20), Qt::strong_ordering::less);
+ generateRow(QTime(13, 24, 56, 20), QTime(13, 34, 56, 20), Qt::strong_ordering::less);
+ generateRow(QTime(12, 34, 56, 20), QTime(13, 34, 56, 20), Qt::strong_ordering::less);
+ generateRow(QTime(14, 34, 56, 20), QTime(13, 34, 56, 20), Qt::strong_ordering::greater);
+ generateRow(QTime(13, 44, 56, 20), QTime(13, 34, 56, 20), Qt::strong_ordering::greater);
+ generateRow(QTime(13, 34, 56, 20), QTime(13, 34, 46, 20), Qt::strong_ordering::greater);
+ generateRow(QTime(13, 34, 56, 30), QTime(13, 34, 56, 20), Qt::strong_ordering::greater);
}
-void tst_QTime::operator_gt()
+void tst_QTime::ordering()
{
- QTime t1(0,0,0,0);
- QTime t2(0,0,0,0);
- QVERIFY( !(t1 > t2) );
+ QFETCH(QTime, left);
+ QFETCH(QTime, right);
+ QFETCH(Qt::strong_ordering, expectedOrdering);
- t1 = QTime(12,34,56,20);
- t2 = QTime(12,34,56,30);
- QVERIFY( !(t1 > t2) );
-
- t1 = QTime(13,34,46,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 > t2) );
-
- t1 = QTime(13,24,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 > t2) );
-
- t1 = QTime(12,34,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 > t2) );
-
- t1 = QTime(14,34,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 > t2 );
-
- t1 = QTime(13,44,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 > t2 );
-
- t1 = QTime(13,34,56,20);
- t2 = QTime(13,34,46,20);
- QVERIFY( t1 > t2 );
-
- t1 = QTime(13,44,56,30);
- t2 = QTime(13,44,56,20);
- QVERIFY( t1 > t2 );
-}
-
-void tst_QTime::operator_lt_eq()
-{
- QTime t1(0,0,0,0);
- QTime t2(0,0,0,0);
- QVERIFY( t1 <= t2 );
-
- t1 = QTime(12,34,56,20);
- t2 = QTime(12,34,56,30);
- QVERIFY( t1 <= t2 );
-
- t1 = QTime(13,34,46,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 <= t2 );
-
- t1 = QTime(13,24,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 <= t2 );
-
- t1 = QTime(12,34,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 <= t2 );
-
- t1 = QTime(14,34,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 <= t2) );
-
- t1 = QTime(13,44,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 <= t2) );
-
- t1 = QTime(13,34,56,20);
- t2 = QTime(13,34,46,20);
- QVERIFY( !(t1 <= t2) );
-
- t1 = QTime(13,44,56,30);
- t2 = QTime(13,44,56,20);
- QVERIFY( !(t1 <= t2) );
-}
-
-void tst_QTime::operator_gt_eq()
-{
- QTime t1(0,0,0,0);
- QTime t2(0,0,0,0);
- QVERIFY( t1 >= t2 );
-
- t1 = QTime(12,34,56,20);
- t2 = QTime(12,34,56,30);
- QVERIFY( !(t1 >= t2) );
-
- t1 = QTime(13,34,46,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 >= t2) );
-
- t1 = QTime(13,24,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 >= t2) );
-
- t1 = QTime(12,34,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 >= t2) );
-
- t1 = QTime(14,34,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 >= t2 );
-
- t1 = QTime(13,44,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 >= t2 );
-
- t1 = QTime(13,34,56,20);
- t2 = QTime(13,34,46,20);
- QVERIFY( t1 >= t2 );
-
- t1 = QTime(13,44,56,30);
- t2 = QTime(13,44,56,20);
- QVERIFY( t1 >= t2 );
+ QT_TEST_ALL_COMPARISON_OPS(left, right, expectedOrdering);
}
#if QT_CONFIG(datestring)
@@ -718,7 +571,7 @@ void tst_QTime::fromStringDateFormat_data()
<< Qt::RFC2822Date << invalidTime();
// The common date text used by the "invalid character" tests, just to be
// sure *it's* not what's invalid:
- QTest::newRow("RFC 850 and 1036 invalid character at end")
+ QTest::newRow("RFC 850 and 1036 no invalid character")
<< QString::fromLatin1("Sun Jan 01 08:00:00 2012 +0100")
<< Qt::RFC2822Date << QTime(8, 0, 0);
diff --git a/tests/auto/corelib/time/qtimezone/CMakeLists.txt b/tests/auto/corelib/time/qtimezone/CMakeLists.txt
index 160ade2afd..612bab0db5 100644
--- a/tests/auto/corelib/time/qtimezone/CMakeLists.txt
+++ b/tests/auto/corelib/time/qtimezone/CMakeLists.txt
@@ -1,17 +1,25 @@
-# Generated from qtimezone.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qtimezone Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtimezone LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qtimezone
SOURCES
tst_qtimezone.cpp
DEFINES
QT_NO_FOREACH
QT_NO_KEYWORDS
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
+ Qt::TestPrivate
)
## Scopes:
@@ -25,6 +33,6 @@ qt_internal_extend_target(tst_qtimezone CONDITION QT_FEATURE_icu
qt_internal_extend_target(tst_qtimezone CONDITION APPLE
SOURCES
tst_qtimezone_darwin.mm
- PUBLIC_LIBRARIES
+ LIBRARIES
${FWFoundation}
)
diff --git a/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp b/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp
index f68aeced2f..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());
@@ -321,28 +309,157 @@ void tst_QTimeZone::nullTest()
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;
@@ -396,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);
}
}
@@ -468,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:
@@ -512,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);
}
}
@@ -527,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");
@@ -544,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;
}
@@ -574,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()
@@ -596,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;
}
}
}
@@ -649,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 },
@@ -667,42 +856,44 @@ 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 }
};
- bool lacksRows = true;
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;
- lacksRows = false;
} else {
qWarning("Skipping %s@%s test as zone is invalid", entry.zone, entry.nick);
}
}
- if (lacksRows)
- QSKIP("No valid zone info found, skipping test");
}
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()
@@ -728,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);
@@ -750,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);
@@ -806,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()
@@ -868,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
@@ -939,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
@@ -966,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
@@ -1023,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);
@@ -1074,14 +1282,16 @@ 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);
@@ -1119,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;
@@ -1129,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");
@@ -1154,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
@@ -1226,14 +1437,16 @@ void tst_QTimeZone::tzTest()
}
dat = tzp.nextTransition(ancient);
- QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, Qt::OffsetFromUTC, 3600),
- QDateTime(QDate(1893, 4, 1), QTime(0, 6, 32), Qt::OffsetFromUTC, 3600));
+ 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);
@@ -1253,32 +1466,33 @@ void tst_QTimeZone::tzTest()
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);
@@ -1293,9 +1507,12 @@ void tst_QTimeZone::tzTest()
QCOMPARE(datatz1.offsetFromUtc, datautc1.offsetFromUtc);
// Test TZ timezone vs UTC timezone for non-whole-hour positive offset:
- QTzTimeZonePrivate tztz2("Asia/Calcutta");
+ 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);
@@ -1307,7 +1524,7 @@ void tst_QTimeZone::tzTest()
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
@@ -1317,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;
@@ -1373,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,16 +1636,68 @@ void tst_QTimeZone::winTest()
testEpochTranPrivate(QWinTimeZonePrivate("America/Toronto"));
#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);
@@ -1461,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);
@@ -1494,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);
@@ -1526,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
@@ -1540,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);
@@ -1560,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"
diff --git a/tests/auto/corelib/time/qtimezone/tst_qtimezone_darwin.mm b/tests/auto/corelib/time/qtimezone/tst_qtimezone_darwin.mm
index 040bd941ae..f4ef15036d 100644
--- a/tests/auto/corelib/time/qtimezone/tst_qtimezone_darwin.mm
+++ b/tests/auto/corelib/time/qtimezone/tst_qtimezone_darwin.mm
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtCore/QTimeZone>
#include <QTest>
@@ -34,7 +9,7 @@
void tst_QTimeZone_darwinTypes()
{
-#if !defined(QT_NO_SYSTEMLOCALE)
+#if QT_CONFIG(timezone)
// QTimeZone <-> CFTimeZone
{
QTimeZone qtTimeZone("America/Los_Angeles");
@@ -64,5 +39,5 @@ void tst_QTimeZone_darwinTypes()
QVERIFY([qtTimeZone.toNSTimeZone() isEqual:nsTimeZone]);
[autoreleasepool release];
}
-#endif
+#endif // feature timezone
}