diff options
author | Edward Welbourne <edward.welbourne@qt.io> | 2018-06-13 21:19:18 +0200 |
---|---|---|
committer | Edward Welbourne <edward.welbourne@qt.io> | 2020-10-09 01:09:42 +0200 |
commit | cb0ecd6b6dfaea372d7973e4d78e661deb441540 (patch) | |
tree | 0c40156d09605f5901136d5727bf71278fd09267 /tests | |
parent | 83bff8951a6129cb9e6eaa0286328ae4953f0e8c (diff) |
Check value is in range when setting a QDateTime
Previously, a QDate representing more than about 0.3 gigayears before
or after the epoch would overflow the millisecond count and produce a
"valid" date-time that didn't represent the date and time passed to
its constructor. Changed to detect such overflow and produce an
invalid date-time instead, if it happens.
Corrected some tests that wrongly expected to be able to represent
extreme date-time values with every time-spec. The (milli)seconds
since epoch are from UTC's epoch, so converting to another offset,
zone or local time may give a value outside the actual range. Added
some tests for the actual exact bounds.
Task-number: QTBUG-68855
Change-Id: I866a4974aeb54bba92dbe7eab0a440baf02124f0
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp | 42 |
1 files changed, 31 insertions, 11 deletions
diff --git a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp index 2e2b5fbf24..d66ee5c832 100644 --- a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp @@ -755,17 +755,22 @@ void tst_QDateTime::fromMSecsSinceEpoch() void tst_QDateTime::fromSecsSinceEpoch() { const qint64 maxSeconds = std::numeric_limits<qint64>::max() / 1000; + const QDateTime early = QDateTime::fromSecsSinceEpoch(-maxSeconds, Qt::UTC); + const QDateTime late = QDateTime::fromSecsSinceEpoch(maxSeconds, Qt::UTC); - QVERIFY(QDateTime::fromSecsSinceEpoch(maxSeconds).isValid()); - QVERIFY(!QDateTime::fromSecsSinceEpoch(maxSeconds + 1).isValid()); - QVERIFY(QDateTime::fromSecsSinceEpoch(-maxSeconds).isValid()); - QVERIFY(!QDateTime::fromSecsSinceEpoch(-maxSeconds - 1).isValid()); - - QVERIFY(QDateTime::fromSecsSinceEpoch(maxSeconds, Qt::UTC).isValid()); + QVERIFY(late.isValid()); QVERIFY(!QDateTime::fromSecsSinceEpoch(maxSeconds + 1, Qt::UTC).isValid()); - QVERIFY(QDateTime::fromSecsSinceEpoch(-maxSeconds, Qt::UTC).isValid()); + QVERIFY(early.isValid()); QVERIFY(!QDateTime::fromSecsSinceEpoch(-maxSeconds - 1, Qt::UTC).isValid()); + // Local time: need to adjust for its zone offset + const qint64 last = maxSeconds - qMax(late.addYears(-1).toLocalTime().offsetFromUtc(), 0); + QVERIFY(QDateTime::fromSecsSinceEpoch(last).isValid()); + QVERIFY(!QDateTime::fromSecsSinceEpoch(last + 1).isValid()); + const qint64 first = -maxSeconds - qMin(early.addYears(1).toLocalTime().offsetFromUtc(), 0); + QVERIFY(QDateTime::fromSecsSinceEpoch(first).isValid()); + QVERIFY(!QDateTime::fromSecsSinceEpoch(first - 1).isValid()); + // Use an offset for which .toUTC()'s return would flip the validity: QVERIFY(QDateTime::fromSecsSinceEpoch(maxSeconds, Qt::OffsetFromUTC, 7200).isValid()); QVERIFY(!QDateTime::fromSecsSinceEpoch(maxSeconds + 1, Qt::OffsetFromUTC, -7200).isValid()); @@ -775,10 +780,10 @@ void tst_QDateTime::fromSecsSinceEpoch() #if QT_CONFIG(timezone) // As for offset, use zones each side of UTC: const QTimeZone west("UTC-02:00"), east("UTC+02:00"); - QVERIFY(QDateTime::fromSecsSinceEpoch(maxSeconds, east).isValid()); - QVERIFY(!QDateTime::fromSecsSinceEpoch(maxSeconds + 1, west).isValid()); - QVERIFY(QDateTime::fromSecsSinceEpoch(-maxSeconds, west).isValid()); - QVERIFY(!QDateTime::fromSecsSinceEpoch(-maxSeconds - 1, east).isValid()); + QVERIFY(QDateTime::fromSecsSinceEpoch(maxSeconds, west).isValid()); + QVERIFY(!QDateTime::fromSecsSinceEpoch(maxSeconds + 1, east).isValid()); + QVERIFY(QDateTime::fromSecsSinceEpoch(-maxSeconds, east).isValid()); + QVERIFY(!QDateTime::fromSecsSinceEpoch(-maxSeconds - 1, west).isValid()); #endif // timezone } @@ -3759,6 +3764,21 @@ void tst_QDateTime::range() const int(QDateTime::YearRange::First)); QCOMPARE(QDateTime::fromMSecsSinceEpoch(Bounds::max() - 1, Qt::UTC).date().year(), int(QDateTime::YearRange::Last)); + constexpr qint64 millisPerDay = 24 * 3600 * 1000; + constexpr qint64 wholeDays = Bounds::max() / millisPerDay; + constexpr qint64 millisRemainder = Bounds::max() % millisPerDay; + QVERIFY(QDateTime(QDate(1970, 1, 1).addDays(wholeDays), + QTime::fromMSecsSinceStartOfDay(millisRemainder), + Qt::UTC).isValid()); + QVERIFY(!QDateTime(QDate(1970, 1, 1).addDays(wholeDays), + QTime::fromMSecsSinceStartOfDay(millisRemainder + 1), + Qt::UTC).isValid()); + QVERIFY(QDateTime(QDate(1970, 1, 1).addDays(-wholeDays - 1), + QTime::fromMSecsSinceStartOfDay(3600 * 24000 - millisRemainder - 1), + Qt::UTC).isValid()); + QVERIFY(!QDateTime(QDate(1970, 1, 1).addDays(-wholeDays - 1), + QTime::fromMSecsSinceStartOfDay(3600 * 24000 - millisRemainder - 2), + Qt::UTC).isValid()); } void tst_QDateTime::macTypes() |