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_last ymd)
|
||||
\fn QDate::QDate(std::chrono::year_month_weekday ymd)
|
||||
\fn QDate::QDate(std::chrono::year_month_weekday_last ymd)
|
||||
\fn QDate::QDate(std::chrono::year_month_day date)
|
||||
\fn QDate::QDate(std::chrono::year_month_day_last date)
|
||||
\fn QDate::QDate(std::chrono::year_month_weekday date)
|
||||
\fn QDate::QDate(std::chrono::year_month_weekday_last date)
|
||||
|
||||
\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
|
||||
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
|
||||
|
||||
\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
|
||||
\a ymd.
|
||||
\a date.
|
||||
|
||||
\note This function requires C++20.
|
||||
*/
|
||||
|
@ -32,53 +32,36 @@ public:
|
||||
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)
|
||||
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())
|
||||
jd = nullJd();
|
||||
else
|
||||
*this = fromStdSysDays(ymd);
|
||||
return QDate(stdSysDaysToJulianDay(days));
|
||||
}
|
||||
|
||||
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())
|
||||
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)));
|
||||
const qint64 days = isValid() ? jd - unixEpochJd() : 0;
|
||||
return std::chrono::sys_days(std::chrono::days(days));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -167,6 +150,21 @@ private:
|
||||
static constexpr inline qint64 maxJd() { return Q_INT64_C( 784354017364); }
|
||||
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;
|
||||
|
||||
friend class QDateTime;
|
||||
|
@ -1745,6 +1745,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
|
||||
|
Loading…
x
Reference in New Issue
Block a user