QDateTime: add support for std::chrono::duration arithmetic

QDateTime represents a specific point in time, so arithmetic
with durations makes perfect sense.

Moreover, we can finally equip QDateTime with a subtraction
operator, to calculate the duration between two QDateTime
objects.

[ChangeLog][QtCore][QDateTime] QDateTime now supports arithmetic
between QDateTime objects and std::chrono::duration objects.
A duration can be added to or subtracted from a QDateTime, yielding
another QDateTime; and two QDateTime objects can be subtracted
from each other, yielding the duration between them.

Change-Id: I656419f3bb9418c49f0e2fd0800c3dbaaf6aff32
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Giuseppe D'Angelo 2022-04-02 02:25:26 +02:00
parent b36de79ffd
commit 0a17a0da61
3 changed files with 122 additions and 1 deletions

View File

@ -4622,6 +4622,75 @@ qint64 QDateTime::msecsTo(const QDateTime &other) const
return other.toMSecsSinceEpoch() - toMSecsSinceEpoch();
}
/*!
\fn std::chrono::milliseconds QDateTime::operator-(const QDateTime &lhs, const QDateTime &rhs)
\since 6.4
Returns the number of milliseconds between \a lhs and \a rhs.
If \a lhs is earlier than \a rhs, the result will be negative.
Returns 0 if either datetime is invalid.
\sa msecsTo()
*/
/*!
\fn QDateTime QDateTime::operator+(const QDateTime &dateTime, std::chrono::milliseconds duration)
\fn QDateTime QDateTime::operator+(std::chrono::milliseconds duration, const QDateTime &dateTime)
\since 6.4
Returns a QDateTime object containing a datetime \a duration milliseconds
later than \a dateTime (or earlier if \a duration is negative).
If \a dateTime is invalid, an invalid datetime will be returned.
\sa addMSecs()
*/
/*!
\fn QDateTime &QDateTime::operator+=(std::chrono::milliseconds duration)
\since 6.4
Modifies this datetime object by adding the given \a duration.
The updated object will be later if \a duration is positive,
or earlier if it is negative.
If this datetime is invalid, this function has no effect.
Returns a reference to this datetime object.
\sa addMSecs()
*/
/*!
\fn QDateTime QDateTime::operator-(const QDateTime &dateTime, std::chrono::milliseconds duration)
\since 6.4
Returns a QDateTime object containing a datetime \a duration milliseconds
earlier than \a dateTime (or later if \a duration is negative).
If \a dateTime is invalid, an invalid datetime will be returned.
\sa addMSecs()
*/
/*!
\fn QDateTime &QDateTime::operator-=(std::chrono::milliseconds duration)
\since 6.4
Modifies this datetime object by subtracting the given \a duration.
The updated object will be earlier if \a duration is positive,
or later if it is negative.
If this datetime is invalid, this function has no effect.
Returns a reference to this datetime object.
\sa addMSecs
*/
/*!
Returns a copy of this datetime converted to the given time
\a spec.

View File

@ -47,6 +47,7 @@
#include <QtCore/qcalendar.h>
#include <limits>
#include <chrono>
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
Q_FORWARD_DECLARE_CF_TYPE(CFDate);
@ -385,6 +386,38 @@ public:
NSDate *toNSDate() const Q_DECL_NS_RETURNS_AUTORELEASED;
#endif
friend std::chrono::milliseconds operator-(const QDateTime &lhs, const QDateTime &rhs)
{
return std::chrono::milliseconds(rhs.msecsTo(lhs));
}
friend QDateTime operator+(const QDateTime &dateTime, std::chrono::milliseconds duration)
{
return dateTime.addMSecs(duration.count());
}
friend QDateTime operator+(std::chrono::milliseconds duration, const QDateTime &dateTime)
{
return dateTime + duration;
}
QDateTime &operator+=(std::chrono::milliseconds duration)
{
*this = addMSecs(duration.count());
return *this;
}
friend QDateTime operator-(const QDateTime &dateTime, std::chrono::milliseconds duration)
{
return dateTime.addMSecs(-duration.count());
}
QDateTime &operator-=(std::chrono::milliseconds duration)
{
*this = addMSecs(-duration.count());
return *this;
}
// (1<<63) ms is 292277024.6 (average Gregorian) years, counted from the start of 1970, so
// Last is floor(1970 + 292277024.6); no year 0, so First is floor(1970 - 1 - 292277024.6)
enum class YearRange : qint32 { First = -292275056, Last = +292278994 };

View File

@ -1483,14 +1483,29 @@ void tst_QDateTime::addSecs()
QFETCH(const qint64, nsecs);
QFETCH(const QDateTime, result);
QDateTime test = dt.addSecs(nsecs);
QDateTime test2 = dt + std::chrono::seconds(nsecs);
QDateTime test3 = dt;
test3 += std::chrono::seconds(nsecs);
if (!result.isValid()) {
QVERIFY(!test.isValid());
QVERIFY(!test2.isValid());
QVERIFY(!test3.isValid());
} else {
QCOMPARE(test, result);
QCOMPARE(test2, result);
QCOMPARE(test3, result);
QCOMPARE(test.timeSpec(), dt.timeSpec());
if (test.timeSpec() == Qt::OffsetFromUTC)
QCOMPARE(test2.timeSpec(), dt.timeSpec());
QCOMPARE(test3.timeSpec(), dt.timeSpec());
if (test.timeSpec() == Qt::OffsetFromUTC) {
QCOMPARE(test.offsetFromUtc(), dt.offsetFromUtc());
QCOMPARE(test2.offsetFromUtc(), dt.offsetFromUtc());
QCOMPARE(test3.offsetFromUtc(), dt.offsetFromUtc());
}
QCOMPARE(result.addSecs(-nsecs), dt);
QCOMPARE(result - std::chrono::seconds(nsecs), dt);
test3 -= std::chrono::seconds(nsecs);
QCOMPARE(test3, dt);
}
}
@ -1744,7 +1759,9 @@ void tst_QDateTime::msecsTo()
if (result.isValid()) {
QCOMPARE(dt.msecsTo(result), qint64(nsecs) * 1000);
QCOMPARE(result - dt, std::chrono::milliseconds(nsecs * 1000));
QCOMPARE(result.msecsTo(dt), -qint64(nsecs) * 1000);
QCOMPARE(dt - result, -std::chrono::milliseconds(nsecs * 1000));
QVERIFY((dt == result) == (0 == (qint64(nsecs) * 1000)));
QVERIFY((dt != result) == (0 != (qint64(nsecs) * 1000)));
QVERIFY((dt < result) == (0 < (qint64(nsecs) * 1000)));
@ -1753,7 +1770,9 @@ void tst_QDateTime::msecsTo()
QVERIFY((dt >= result) == (0 >= (qint64(nsecs) * 1000)));
} else {
QVERIFY(dt.msecsTo(result) == 0);
QCOMPARE(result - dt, std::chrono::milliseconds(0));
QVERIFY(result.msecsTo(dt) == 0);
QCOMPARE(dt - result, std::chrono::milliseconds(0));
}
}