diff options
-rw-r--r-- | src/corelib/doc/snippets/code/src_corelib_time_qdatetime.cpp | 20 | ||||
-rw-r--r-- | src/corelib/time/qdatetime.cpp | 48 | ||||
-rw-r--r-- | src/corelib/time/qdatetime.h | 52 | ||||
-rw-r--r-- | tests/auto/corelib/time/qdate/tst_qdate.cpp | 39 |
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); |