QDate: make conversion from/to chrono types constexpr and noexcept
Add method stdSysDaysToJulianDay(), which implements the conversion from std::chrono::sys_days to Julian Day in a constexpr and noexcept manner. Use it in the fromStdSysDays() method instead of addDays(), and also in all constructors from std::chrono types. This allows all constructors to be constexpr and noexcept. Simplify toStdSysDays() so that it could also be constexpr and noexcept. Add compile-time roundtrip tests between QDate and std::chrono types. Fixes: QTBUG-118221 Change-Id: Id35a669430162f1932ad8d28b553af2fd7f5c6de Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
bf42be723f
commit
c4f7dba81e
@ -446,14 +446,14 @@ 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 date)
|
||||||
\fn QDate::QDate(std::chrono::year_month_day_last ymd)
|
\fn QDate::QDate(std::chrono::year_month_day_last date)
|
||||||
\fn QDate::QDate(std::chrono::year_month_weekday ymd)
|
\fn QDate::QDate(std::chrono::year_month_weekday date)
|
||||||
\fn QDate::QDate(std::chrono::year_month_weekday_last ymd)
|
\fn QDate::QDate(std::chrono::year_month_weekday_last date)
|
||||||
|
|
||||||
\since 6.4
|
\since 6.4
|
||||||
|
|
||||||
Constructs a QDate representing the same date as \a ymd. This allows for
|
Constructs a QDate representing the same date as \a date. This allows for
|
||||||
easy interoperability between the Standard Library calendaring classes and
|
easy interoperability between the Standard Library calendaring classes and
|
||||||
Qt datetime classes.
|
Qt datetime classes.
|
||||||
|
|
||||||
@ -462,9 +462,9 @@ QDate::QDate(int y, int m, int d, QCalendar cal)
|
|||||||
\snippet code/src_corelib_time_qdatetime.cpp 22
|
\snippet code/src_corelib_time_qdatetime.cpp 22
|
||||||
|
|
||||||
\note Unlike QDate, std::chrono::year and the related classes feature the
|
\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
|
year zero. This means that if \a date is in the year zero or before, the
|
||||||
resulting QDate object will have an year one less than the one specified by
|
resulting QDate object will have an year one less than the one specified by
|
||||||
\a ymd.
|
\a date.
|
||||||
|
|
||||||
\note This function requires C++20.
|
\note This function requires C++20.
|
||||||
*/
|
*/
|
||||||
|
@ -32,53 +32,36 @@ public:
|
|||||||
QDate(int y, int m, int d, QCalendar cal);
|
QDate(int y, int m, int d, QCalendar cal);
|
||||||
#if __cpp_lib_chrono >= 201907L || defined(Q_QDOC)
|
#if __cpp_lib_chrono >= 201907L || defined(Q_QDOC)
|
||||||
QT_POST_CXX17_API_IN_EXPORTED_CLASS
|
QT_POST_CXX17_API_IN_EXPORTED_CLASS
|
||||||
Q_IMPLICIT QDate(std::chrono::year_month_day ymd)
|
Q_IMPLICIT constexpr QDate(std::chrono::year_month_day date) noexcept
|
||||||
|
: jd(date.ok() ? stdSysDaysToJulianDay(date) : nullJd())
|
||||||
|
{}
|
||||||
|
|
||||||
|
QT_POST_CXX17_API_IN_EXPORTED_CLASS
|
||||||
|
Q_IMPLICIT constexpr QDate(std::chrono::year_month_day_last date) noexcept
|
||||||
|
: jd(date.ok() ? stdSysDaysToJulianDay(date) : nullJd())
|
||||||
|
{}
|
||||||
|
|
||||||
|
QT_POST_CXX17_API_IN_EXPORTED_CLASS
|
||||||
|
Q_IMPLICIT constexpr QDate(std::chrono::year_month_weekday date) noexcept
|
||||||
|
: jd(date.ok() ? stdSysDaysToJulianDay(date) : nullJd())
|
||||||
|
{}
|
||||||
|
|
||||||
|
QT_POST_CXX17_API_IN_EXPORTED_CLASS
|
||||||
|
Q_IMPLICIT constexpr QDate(std::chrono::year_month_weekday_last date) noexcept
|
||||||
|
: jd(date.ok() ? stdSysDaysToJulianDay(date) : nullJd())
|
||||||
|
{}
|
||||||
|
|
||||||
|
QT_POST_CXX17_API_IN_EXPORTED_CLASS
|
||||||
|
static constexpr QDate fromStdSysDays(const std::chrono::sys_days &days) noexcept
|
||||||
{
|
{
|
||||||
if (!ymd.ok())
|
return QDate(stdSysDaysToJulianDay(days));
|
||||||
jd = nullJd();
|
|
||||||
else
|
|
||||||
*this = fromStdSysDays(ymd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_POST_CXX17_API_IN_EXPORTED_CLASS
|
QT_POST_CXX17_API_IN_EXPORTED_CLASS
|
||||||
Q_IMPLICIT QDate(std::chrono::year_month_day_last ymdl)
|
constexpr std::chrono::sys_days toStdSysDays() const noexcept
|
||||||
{
|
{
|
||||||
if (!ymdl.ok())
|
const qint64 days = isValid() ? jd - unixEpochJd() : 0;
|
||||||
jd = nullJd();
|
return std::chrono::sys_days(std::chrono::days(days));
|
||||||
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
|
#endif
|
||||||
|
|
||||||
@ -167,6 +150,21 @@ private:
|
|||||||
static constexpr inline qint64 maxJd() { return Q_INT64_C( 784354017364); }
|
static constexpr inline qint64 maxJd() { return Q_INT64_C( 784354017364); }
|
||||||
static constexpr inline qint64 unixEpochJd() { return Q_INT64_C(2440588); }
|
static constexpr inline qint64 unixEpochJd() { return Q_INT64_C(2440588); }
|
||||||
|
|
||||||
|
#if __cpp_lib_chrono >= 201907L
|
||||||
|
static constexpr qint64 stdSysDaysToJulianDay(const std::chrono::sys_days &days) noexcept
|
||||||
|
{
|
||||||
|
const auto epochDays = days.time_since_epoch().count();
|
||||||
|
// minJd() and maxJd() fit into 40 bits.
|
||||||
|
if constexpr (sizeof(epochDays) >= 41) {
|
||||||
|
constexpr auto top = maxJd() - unixEpochJd();
|
||||||
|
constexpr auto bottom = minJd() - unixEpochJd();
|
||||||
|
if (epochDays > top || epochDays < bottom)
|
||||||
|
return nullJd();
|
||||||
|
}
|
||||||
|
return unixEpochJd() + epochDays;
|
||||||
|
}
|
||||||
|
#endif // __cpp_lib_chrono >= 201907L
|
||||||
|
|
||||||
qint64 jd;
|
qint64 jd;
|
||||||
|
|
||||||
friend class QDateTime;
|
friend class QDateTime;
|
||||||
|
@ -1745,6 +1745,38 @@ void tst_QDate::roundtrip() const
|
|||||||
QCOMPARE(loopDate.toJulianDay(), testDate.toJulianDay());
|
QCOMPARE(loopDate.toJulianDay(), testDate.toJulianDay());
|
||||||
loopDate = loopDate.addDays(1);
|
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
|
void tst_QDate::qdebug() const
|
||||||
|
Loading…
x
Reference in New Issue
Block a user