summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/time/qdate/tst_qdate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/time/qdate/tst_qdate.cpp')
-rw-r--r--tests/auto/corelib/time/qdate/tst_qdate.cpp889
1 files changed, 512 insertions, 377 deletions
diff --git a/tests/auto/corelib/time/qdate/tst_qdate.cpp b/tests/auto/corelib/time/qdate/tst_qdate.cpp
index 6f8699bc98..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,113 +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");
-
- const QTime initial(0, 0), final(23, 59, 59, 999), invalid(QDateTime().time());
-
- QTest::newRow("epoch")
- << QDate(1970, 1, 1) << QByteArray("UTC")
- << initial << final;
- 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
- QTest::newRow("Sofia")
- << QDate(1994, 3, 27) << QByteArray("Europe/Sofia")
- << QTime(1, 0) << final;
+ // 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
- QTest::newRow("Kiritimati")
- << QDate(1994, 12, 31) << QByteArray("Pacific/Kiritimati")
- << invalid << invalid;
- QTest::newRow("Samoa")
- << QDate(2011, 12, 30) << QByteArray("Pacific/Apia")
- << invalid << invalid;
- // TODO: find other zones with transitions at/crossing midnight.
+ const QTimeZone UTC(QTimeZone::UTC);
+
+ using Bound = std::numeric_limits<qint64>;
+ const auto dateAtMillis = [UTC](qint64 millis) {
+ return QDateTime::fromMSecsSinceEpoch(millis, UTC).date();
+ };
+
+ // 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;
+ }
+ }
+ }
+#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;
+ }
+ }
+#endif // timezone
}
void tst_QDate::startOfDay_endOfDay()
{
- QFETCH(QDate, date);
- QFETCH(QByteArray, zoneName);
- QFETCH(QTime, start);
- QFETCH(QTime, end);
- const QTimeZone zone(zoneName);
- const bool isSystem = QTimeZone::systemTimeZone() == zone;
+ 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());
+
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(-0x80000000L * kilo, Qt::UTC)),
- end32sign(QDateTime::fromMSecsSinceEpoch(0x80000000L * kilo, Qt::UTC)),
- end32unsign(QDateTime::fromMSecsSinceEpoch(0x100000000L * 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()
@@ -577,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);
@@ -694,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()
@@ -841,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);
@@ -868,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");
@@ -904,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()
+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_gt()
+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) );
-
- d1 = QDate(2000,12,5);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 > d2) );
+ QFETCH(QDate, left);
+ QFETCH(QDate, right);
+ QFETCH(Qt::strong_ordering, expectedOrdering);
- 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_lt_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) );
-}
-
-void tst_QDate::operator_gt_eq()
-{
- 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)
@@ -1138,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);
@@ -1183,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);
@@ -1224,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();
}
@@ -1377,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
@@ -1592,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) {
@@ -1610,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