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:
parent
0e653246b1
commit
19c913b43d
@ -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() };
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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};
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user