Ensure QDateTime can handle QDate's full range of julian dates.

Currently, using QDate::maxJd() in tests will fail. This patch changes
some ints to qint64s to prevent overflows where necessary.

Change-Id: I61ebf8f233411a7544689fd5bfa9c3abee54e933
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Mitch Curtis 2013-02-04 17:08:24 +01:00 committed by The Qt Project
parent 86115848b5
commit 4aa86461eb
3 changed files with 54 additions and 7 deletions

View File

@ -2404,9 +2404,9 @@ uint QDateTime::toTime_t() const
(Qt::UTC). On systems that do not support time zones this function
will behave as if local time were Qt::UTC.
Note that there are possible values for \a msecs that lie outside the
valid range of QDateTime, both negative and positive. The behavior of
this function is undefined for those values.
Note that passing the minimum of \c qint64
(\c{std::numeric_limits<qint64>::min()}) to \a msecs will result in
undefined behavior.
\sa toMSecsSinceEpoch(), setTime_t()
*/
@ -4010,7 +4010,7 @@ static QDateTimePrivate::Spec utcToLocal(QDate &date, QTime &time)
time = QTime();
return QDateTimePrivate::LocalUnknown;
} else {
int deltaDays = fakeDate.daysTo(date);
qint64 deltaDays = fakeDate.daysTo(date);
date = QDate(brokenDown->tm_year + 1900, brokenDown->tm_mon + 1, brokenDown->tm_mday);
time = QTime(brokenDown->tm_hour, brokenDown->tm_min, brokenDown->tm_sec, time.msec());
date = date.addDays(deltaDays);
@ -4078,7 +4078,7 @@ static void localToUtc(QDate &date, QTime &time, int isdst)
date = QDate(1970, 1, 1);
time = QTime();
} else {
int deltaDays = fakeDate.daysTo(date);
qint64 deltaDays = fakeDate.daysTo(date);
date = QDate(brokenDown->tm_year + 1900, brokenDown->tm_mon + 1, brokenDown->tm_mday);
time = QTime(brokenDown->tm_hour, brokenDown->tm_min, brokenDown->tm_sec, time.msec());
date = date.addDays(deltaDays);

View File

@ -101,6 +101,9 @@ public:
void getUTC(QDate &outDate, QTime &outTime) const;
static QDateTime addMSecs(const QDateTime &dt, qint64 msecs);
static void addMSecs(QDate &utcDate, QTime &utcTime, qint64 msecs);
static inline qint64 minJd() { return QDate::minJd(); }
static inline qint64 maxJd() { return QDate::maxJd(); }
};
#ifndef QT_BOOTSTRAPPED

View File

@ -145,6 +145,8 @@ private:
QDateTime invalidDateTime() const { return QDateTime(invalidDate(), invalidTime()); }
QDate invalidDate() const { return QDate(); }
QTime invalidTime() const { return QTime(-1, -1, -1); }
qint64 minJd() const { return QDateTimePrivate::minJd(); }
qint64 maxJd() const { return QDateTimePrivate::maxJd(); }
};
Q_DECLARE_METATYPE(Qt::TimeSpec)
@ -462,14 +464,25 @@ void tst_QDateTime::setMSecsSinceEpoch_data()
<< (Q_INT64_C(123456) << 32)
<< QDateTime(QDate(18772, 8, 15), QTime(1, 8, 14, 976), Qt::UTC)
<< QDateTime(QDate(18772, 8, 15), QTime(3, 8, 14, 976));
QTest::newRow("min_date") // julian day 0 is an invalid date for QDate
QTest::newRow("old min (Tue Nov 25 00:00:00 -4714)")
<< Q_INT64_C(-210866716800000)
<< QDateTime(QDate::fromJulianDay(1), QTime(), Qt::UTC)
<< QDateTime(QDate::fromJulianDay(1), QTime(1, 0));
QTest::newRow("max_date") // technically jd is unsigned, but fromJulianDay takes int
QTest::newRow("old max (Tue Jun 3 21:59:59 5874898)")
<< Q_INT64_C(185331720376799999)
<< QDateTime(QDate::fromJulianDay(0x7fffffff), QTime(21, 59, 59, 999), Qt::UTC)
<< QDateTime(QDate::fromJulianDay(0x7fffffff), QTime(23, 59, 59, 999));
QTest::newRow("min")
// + 1 because, in the reference check below, calling addMSecs(qint64min)
// will internally apply unary minus to -qint64min, resulting in a
// positive value 1 too big for qint64max, causing an overflow.
<< std::numeric_limits<qint64>::min() + 1
<< QDateTime(QDate(-292275056, 5, 16), QTime(16, 47, 4, 193), Qt::UTC)
<< QDateTime(QDate(-292275056, 5, 16), QTime(17, 47, 4, 193), Qt::LocalTime);
QTest::newRow("max")
<< std::numeric_limits<qint64>::max()
<< QDateTime(QDate(292278994, 8, 17), QTime(7, 12, 55, 807), Qt::UTC)
<< QDateTime(QDate(292278994, 8, 17), QTime(9, 12, 55, 807), Qt::LocalTime);
}
void tst_QDateTime::setMSecsSinceEpoch()
@ -821,6 +834,29 @@ void tst_QDateTime::toTimeSpec_data()
QTest::newRow("winter4") << QDateTime(QDate(6000, 2, 29), utcTime, Qt::UTC)
<< QDateTime(QDate(6000, 2, 29), localStandardTime, Qt::LocalTime);
// Test mktime boundaries (1970 - 2038) and adjustDate().
QTest::newRow("1969/12/31 23:00 UTC")
<< QDateTime(QDate(1969, 12, 31), QTime(23, 0, 0), Qt::UTC)
<< QDateTime(QDate(1970, 1, 1), QTime(0, 0, 0), Qt::LocalTime);
QTest::newRow("2037/12/31 23:00 UTC")
<< QDateTime(QDate(2037, 12, 31), QTime(23, 0, 0), Qt::UTC)
<< QDateTime(QDate(2038, 1, 1), QTime(0, 0, 0), Qt::LocalTime);
QTest::newRow("-271821/4/20 00:00 UTC (JavaScript min date, start of day)")
<< QDateTime(QDate(-271821, 4, 20), QTime(0, 0, 0), Qt::UTC)
<< QDateTime(QDate(-271821, 4, 20), QTime(1, 0, 0), Qt::LocalTime);
QTest::newRow("-271821/4/20 23:00 UTC (JavaScript min date, end of day)")
<< QDateTime(QDate(-271821, 4, 20), QTime(23, 0, 0), Qt::UTC)
<< QDateTime(QDate(-271821, 4, 21), QTime(0, 0, 0), Qt::LocalTime);
QTest::newRow("QDate min")
<< QDateTime(QDate::fromJulianDay(minJd()), QTime(0, 0, 0), Qt::UTC)
<< QDateTime(QDate::fromJulianDay(minJd()), QTime(1, 0, 0), Qt::LocalTime);
QTest::newRow("QDate max")
<< QDateTime(QDate::fromJulianDay(maxJd()), QTime(22, 59, 59), Qt::UTC)
<< QDateTime(QDate::fromJulianDay(maxJd()), QTime(23, 59, 59), Qt::LocalTime);
if (europeanTimeZone) {
QTest::newRow("summer1") << QDateTime(QDate(2004, 6, 30), utcTime, Qt::UTC)
<< QDateTime(QDate(2004, 6, 30), localDaylightTime, Qt::LocalTime);
@ -835,6 +871,14 @@ void tst_QDateTime::toTimeSpec_data()
#endif
QTest::newRow("summer3") << QDateTime(QDate(4000, 6, 30), utcTime, Qt::UTC)
<< QDateTime(QDate(4000, 6, 30), localDaylightTime, Qt::LocalTime);
QTest::newRow("275760/9/23 00:00 UTC (JavaScript max date, start of day)")
<< QDateTime(QDate(275760, 9, 23), QTime(0, 0, 0), Qt::UTC)
<< QDateTime(QDate(275760, 9, 23), QTime(2, 0, 0), Qt::LocalTime);
QTest::newRow("275760/9/23 22:00 UTC (JavaScript max date, end of day)")
<< QDateTime(QDate(275760, 9, 23), QTime(22, 0, 0), Qt::UTC)
<< QDateTime(QDate(275760, 9, 24), QTime(0, 0, 0), Qt::LocalTime);
}
QTest::newRow("msec") << QDateTime(QDate(4000, 6, 30), utcTime.addMSecs(1), Qt::UTC)