summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_time_qdatetime.cpp20
-rw-r--r--src/corelib/time/qdatetime.cpp48
-rw-r--r--src/corelib/time/qdatetime.h52
-rw-r--r--tests/auto/corelib/time/qdate/tst_qdate.cpp39
4 files changed, 159 insertions, 0 deletions
diff --git a/src/corelib/doc/snippets/code/src_corelib_time_qdatetime.cpp b/src/corelib/doc/snippets/code/src_corelib_time_qdatetime.cpp
index a477e91548..265f46c067 100644
--- a/src/corelib/doc/snippets/code/src_corelib_time_qdatetime.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_time_qdatetime.cpp
@@ -216,3 +216,23 @@ QString string = "Tuesday, 23 April 12 22:51:41";
QString format = "dddd, d MMMM yy hh:mm:ss";
QDateTime valid = QDateTime::fromString(string, format);
//! [21]
+
+//! [22]
+// 23 April 2012:
+QDate date = std::chrono::year_month_day(std::chrono::year(2012),
+ std::chrono::month(4),
+ std::chrono::day(23));
+
+// Same, under `using std::chrono` convenience:
+QDate dateWithLiterals1 = 23 / April / 2012y;
+QDate dateWithLiterals2 = 2012y / April / 23;
+
+// Last day of February 2000
+QDate lastDayFeb2020 = 2000y / February / last;
+
+// First Monday of January 2020:
+QDate firstMonday = 2020y / January / Monday[0];
+
+// Last Monday of January 2020:
+QDate lastMonday = 2020y / January / Monday[last];
+//! [22]
diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp
index cea5623acf..09477612e4 100644
--- a/src/corelib/time/qdatetime.cpp
+++ b/src/corelib/time/qdatetime.cpp
@@ -449,6 +449,54 @@ QDate::QDate(int y, int m, int d, QCalendar cal)
}
/*!
+ \fn QDate::QDate(std::chrono::year_month_day ymd)
+ \fn QDate::QDate(std::chrono::year_month_day_last ymd)
+ \fn QDate::QDate(std::chrono::year_month_weekday ymd)
+ \fn QDate::QDate(std::chrono::year_month_weekday_last ymd)
+
+ \since 6.4
+
+ Constructs a QDate representing the same date as \a ymd. This allows for
+ easy interoperability between the Standard Library calendaring classes and
+ Qt datetime classes.
+
+ For example:
+
+ \snippet code/src_corelib_time_qdatetime.cpp 22
+
+ \note Unlike QDate, std::chrono::year and the related classes feature the
+ year zero. This means that if \a ymd is in the year zero or before, the
+ resulting QDate object will have an year one less than the one specified by
+ \a ymd.
+
+ \note This function requires C++20.
+*/
+
+/*!
+ \fn QDate QDate::fromStdSysDays(const std::chrono::sys_days &days)
+ \since 6.4
+
+ Returns a QDate \a days days after January 1st, 1970 (the UNIX epoch). If
+ \a days is negative, the returned date will be before the epoch.
+
+ \note This function requires C++20.
+
+ \sa toStdSysDays()
+*/
+
+/*!
+ \fn std::chrono::sys_days QDate::toStdSysDays() const
+
+ Returns the number of days between January 1st, 1970 (the UNIX epoch) and
+ this date, represented as a \c{std::chrono::sys_days} object. If this date
+ is before the epoch, the number of days will be negative.
+
+ \note This function requires C++20.
+
+ \sa fromStdSysDays(), daysTo()
+*/
+
+/*!
\fn bool QDate::isNull() const
Returns \c true if the date is null; otherwise returns \c false. A null
diff --git a/src/corelib/time/qdatetime.h b/src/corelib/time/qdatetime.h
index 839d0c2f28..f264a1e234 100644
--- a/src/corelib/time/qdatetime.h
+++ b/src/corelib/time/qdatetime.h
@@ -68,6 +68,57 @@ public:
constexpr QDate() : jd(nullJd()) {}
QDate(int y, int m, int d);
QDate(int y, int m, int d, QCalendar cal);
+#if __cpp_lib_chrono >= 201907L || defined(Q_QDOC)
+ QT_POST_CXX17_API_IN_EXPORTED_CLASS
+ Q_IMPLICIT QDate(std::chrono::year_month_day ymd)
+ {
+ if (!ymd.ok())
+ jd = nullJd();
+ else
+ *this = fromStdSysDays(ymd);
+ }
+
+ QT_POST_CXX17_API_IN_EXPORTED_CLASS
+ Q_IMPLICIT QDate(std::chrono::year_month_day_last ymdl)
+ {
+ if (!ymdl.ok())
+ jd = nullJd();
+ else
+ *this = fromStdSysDays(ymdl);
+ }
+
+ QT_POST_CXX17_API_IN_EXPORTED_CLASS
+ Q_IMPLICIT QDate(std::chrono::year_month_weekday ymw)
+ {
+ if (!ymw.ok())
+ jd = nullJd();
+ else
+ *this = fromStdSysDays(ymw);
+ }
+
+ QT_POST_CXX17_API_IN_EXPORTED_CLASS
+ Q_IMPLICIT QDate(std::chrono::year_month_weekday_last ymwl)
+ {
+ if (!ymwl.ok())
+ jd = nullJd();
+ else
+ *this = fromStdSysDays(ymwl);
+ }
+
+ QT_POST_CXX17_API_IN_EXPORTED_CLASS
+ static QDate fromStdSysDays(const std::chrono::sys_days &days)
+ {
+ const QDate epoch(unixEpochJd());
+ return epoch.addDays(days.time_since_epoch().count());
+ }
+
+ QT_POST_CXX17_API_IN_EXPORTED_CLASS
+ std::chrono::sys_days toStdSysDays() const
+ {
+ const QDate epoch(unixEpochJd());
+ return std::chrono::sys_days(std::chrono::days(epoch.daysTo(*this)));
+ }
+#endif
constexpr bool isNull() const { return !isValid(); }
constexpr bool isValid() const { return jd >= minJd() && jd <= maxJd(); }
@@ -144,6 +195,7 @@ private:
static constexpr inline qint64 nullJd() { return (std::numeric_limits<qint64>::min)(); }
static constexpr inline qint64 minJd() { return Q_INT64_C(-784350574879); }
static constexpr inline qint64 maxJd() { return Q_INT64_C( 784354017364); }
+ static constexpr inline qint64 unixEpochJd() { return Q_INT64_C(2440588); }
qint64 jd;
diff --git a/tests/auto/corelib/time/qdate/tst_qdate.cpp b/tests/auto/corelib/time/qdate/tst_qdate.cpp
index ac9c9db9d3..5d56eef559 100644
--- a/tests/auto/corelib/time/qdate/tst_qdate.cpp
+++ b/tests/auto/corelib/time/qdate/tst_qdate.cpp
@@ -199,6 +199,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);
@@ -218,6 +244,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);