Deploy QRoundingDown::qDivMod() in date-time calculations

This saves duplicate computations and incidentally now fixes some
overflow issues. In the process, simplify some calendrical
calculations.

Fixes: QTBUG-109845
Change-Id: Iee331803e8281bbf822a001722a6faa3e66f6322
Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
This commit is contained in:
Edward Welbourne 2023-01-16 18:42:24 +01:00
parent 0e653246b1
commit 19c913b43d
5 changed files with 36 additions and 41 deletions

View File

@ -3053,12 +3053,12 @@ static QPair<QDate, QTime> getDateTime(const QDateTimeData &d)
{
auto status = getStatus(d);
const qint64 msecs = getMSecs(d);
const qint64 days = QRoundingDown::qDiv<MSECS_PER_DAY>(msecs);
const auto dayMilli = QRoundingDown::qDivMod<MSECS_PER_DAY>(msecs);
return { status.testFlag(QDateTimePrivate::ValidDate)
? QDate::fromJulianDay(JULIAN_DAY_FOR_EPOCH + days)
? QDate::fromJulianDay(JULIAN_DAY_FOR_EPOCH + dayMilli.quotient)
: QDate(),
status.testFlag(QDateTimePrivate::ValidTime)
? QTime::fromMSecsSinceStartOfDay(msecs - days * MSECS_PER_DAY)
? QTime::fromMSecsSinceStartOfDay(dayMilli.remainder)
: QTime() };
}

View File

@ -77,11 +77,11 @@ bool QIslamicCivilCalendar::dateToJulianDay(int year, int month, int day, qint64
QCalendar::YearMonthDay QIslamicCivilCalendar::julianDayToDate(qint64 jd) const
{
constexpr qint64 epoch = 1948440;
const int32_t k2 = 30 * (jd - epoch) + 15;
const int32_t k1 = 11 * qDiv<30>(qMod<10631>(k2)) + 5;
int y = qDiv<10631>(k2) + 1;
const int month = qDiv<325>(k1) + 1;
const int day = qDiv<11>(qMod<325>(k1)) + 1;
const auto k2dm = qDivMod<10631>(30 * (jd - epoch) + 15);
int y = k2dm.quotient + 1;
const auto k1dm = qDivMod<325>(11 * qDiv<30>(k2dm.remainder) + 5);
const int month = k1dm.quotient + 1;
const int day = qDiv<11>(k1dm.remainder) + 1;
return QCalendar::YearMonthDay(y > 0 ? y : y - 1, month, day);
}

View File

@ -75,14 +75,12 @@ bool QJulianCalendar::dateToJulianDay(int year, int month, int day, qint64 *jd)
QCalendar::YearMonthDay QJulianCalendar::julianDayToDate(qint64 jd) const
{
const qint64 y2 = jd - 1721118;
const qint64 k2 = 4 * y2 + 3;
const qint64 k1 = 5 * qDiv<4>(qMod<1461>(k2)) + 2;
const qint64 x1 = qDiv<153>(k1);
const qint64 c0 = qDiv<12>(x1 + 2);
const int y = qint16(qDiv<1461>(k2) + c0);
const int month = quint8(x1 - 12 * c0 + 3);
const int day = qDiv<5>(qMod<153>(k1)) + 1;
const auto k2dm = qDivMod<1461>(4 * (jd - 1721118) + 3);
const auto k1dm = qDivMod<153>(5 * qDiv<4>(k2dm.remainder) + 2);
const auto c0dm = qDivMod<12>(k1dm.quotient + 2);
const int y = qint16(k2dm.quotient + c0dm.quotient);
const int month = quint8(c0dm.remainder + 1);
const int day = qDiv<5>(k1dm.remainder) + 1;
return QCalendar::YearMonthDay(y > 0 ? y : y - 1, month, day);
}

View File

@ -312,8 +312,9 @@ inline bool secondsAndMillisOverflow(qint64 epochSeconds, qint64 millis, qint64
// returns the local milliseconds, offset from UTC and DST status.
QDateTimePrivate::ZoneState utcToLocal(qint64 utcMillis)
{
const time_t epochSeconds = QRoundingDown::qDiv<MSECS_PER_SEC>(utcMillis);
const int msec = utcMillis - epochSeconds * MSECS_PER_SEC;
const auto epoch = QRoundingDown::qDivMod<MSECS_PER_SEC>(utcMillis);
const time_t epochSeconds = epoch.quotient;
const int msec = epoch.remainder;
Q_ASSERT(msec >= 0 && msec < MSECS_PER_SEC);
if (qint64(epochSeconds) * MSECS_PER_SEC + msec != utcMillis) // time_t range too narrow
return {utcMillis};
@ -341,10 +342,10 @@ QDateTimePrivate::ZoneState utcToLocal(qint64 utcMillis)
QString localTimeAbbbreviationAt(qint64 local, QDateTimePrivate::DaylightStatus dst)
{
const qint64 localDays = QRoundingDown::qDiv<MSECS_PER_DAY>(local);
qint64 millis = local - localDays * MSECS_PER_DAY;
const auto localDayMilli = QRoundingDown::qDivMod<MSECS_PER_DAY>(local);
qint64 millis = localDayMilli.remainder;
Q_ASSERT(0 <= millis && millis < MSECS_PER_DAY); // Definition of QRD::qDiv.
struct tm tmLocal = timeToTm(localDays, int(millis / MSECS_PER_SEC), dst);
struct tm tmLocal = timeToTm(localDayMilli.quotient, int(millis / MSECS_PER_SEC), dst);
time_t utcSecs;
if (!callMkTime(&tmLocal, &utcSecs))
return {};
@ -356,11 +357,11 @@ QDateTimePrivate::ZoneState mapLocalTime(qint64 local, QDateTimePrivate::Dayligh
{
qint64 localSecs = local / MSECS_PER_SEC;
qint64 millis = local - localSecs * MSECS_PER_SEC; // 0 or with same sign as local
const qint64 localDays = QRoundingDown::qDiv<SECS_PER_DAY>(localSecs);
qint64 daySecs = localSecs - localDays * SECS_PER_DAY;
const auto localDaySec = QRoundingDown::qDivMod<SECS_PER_DAY>(localSecs);
qint64 daySecs = localDaySec.remainder;
Q_ASSERT(0 <= daySecs && daySecs < SECS_PER_DAY); // Definition of QRD::qDiv.
struct tm tmLocal = timeToTm(localDays, daySecs, dst);
struct tm tmLocal = timeToTm(localDaySec.quotient, daySecs, dst);
time_t utcSecs;
if (!callMkTime(&tmLocal, &utcSecs))
return {local};

View File

@ -55,8 +55,9 @@ bool QMilankovicCalendar::isLeapYear(int year) const
++year;
if (qMod<4>(year))
return false;
if (qMod<100>(year) == 0) {
const qint16 century = qMod<9>(qDiv<100>(year));
const auto yeardm = qDivMod<100>(year);
if (yeardm.remainder == 0) {
const qint16 century = qMod<9>(yeardm.quotient);
if (century != 2 && century != 6)
return false;
}
@ -72,11 +73,9 @@ bool QMilankovicCalendar::dateToJulianDay(int year, int month, int day, qint64 *
++year;
const qint16 c0 = month < 3 ? -1 : 0;
const qint16 x1 = month - 12 * c0 - 3;
const qint16 x4 = year + c0;
const qint16 x3 = qDiv<100>(x4);
const qint16 x2 = qMod<100>(x4);
*jd = qDiv<9>(328718 * x3 + 6)
+ qDiv<100>(36525 * x2)
const auto x4dm = qDivMod<100>(year + c0);
*jd = qDiv<9>(328718 * x4dm.quotient + 6)
+ qDiv<100>(36525 * x4dm.remainder)
+ qDiv<5>(153 * x1 + 2)
+ day + 1721119;
return true;
@ -84,16 +83,13 @@ bool QMilankovicCalendar::dateToJulianDay(int year, int month, int day, qint64 *
QCalendar::YearMonthDay QMilankovicCalendar::julianDayToDate(qint64 jd) const
{
const qint64 k3 = 9 * (jd - 1721120) + 2;
const qint64 x3 = qDiv<328718>(k3);
const qint64 k2 = 100 * qDiv<9>(qMod<328718>(k3)) + 99;
const qint64 k1 = qDiv<100>(qMod<36525>(k2)) * 5 + 2;
const qint64 x2 = qDiv<36525>(k2);
const qint64 x1 = qDiv<153>(5 * qDiv<100>(qMod<36525>(k2)) + 2);
const qint64 c0 = qDiv<12>(x1 + 2);
const int y = 100 * x3 + x2 + c0;
const int month = x1 - 12 * c0 + 3;
const int day = qDiv<5>(qMod<153>(k1)) + 1;
const auto k3dm = qDivMod<328718>(9 * (jd - 1721120) + 2);
const auto k2dm = qDivMod<36525>(100 * qDiv<9>(k3dm.remainder) + 99);
const auto k1dm = qDivMod<153>(qDiv<100>(k2dm.remainder) * 5 + 2);
const auto c0dm = qDivMod<12>(k1dm.quotient + 2);
const int y = 100 * k3dm.quotient + k2dm.quotient + c0dm.quotient;
const int month = c0dm.remainder + 1;
const int day = qDiv<5>(k1dm.remainder) + 1;
return QCalendar::YearMonthDay(y > 0 ? y : y - 1, month, day);
}