From 0acb56518d72c09650dd83ca34a7d5bb0763b06a Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 10 Aug 2022 16:29:39 +0200 Subject: [PATCH] Rearrange mapLocalTime() so its millis always have the right sign MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Doing a simple division to get seconds, before using rounding-down division to get days and positive seconds, saves the need to check for seconds and millis in opposite directions that might cause a needless overflow when computing the final result. Change-Id: Ia4f95bb0510eb4f2c1f9131a34d317bd41bbed2a Reviewed-by: Qt CI Bot Reviewed-by: MÃ¥rten Nordheim --- src/corelib/time/qlocaltime.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/corelib/time/qlocaltime.cpp b/src/corelib/time/qlocaltime.cpp index 2081b167534..19aaeb25408 100644 --- a/src/corelib/time/qlocaltime.cpp +++ b/src/corelib/time/qlocaltime.cpp @@ -348,11 +348,13 @@ QString localTimeAbbbreviationAt(qint64 local, QDateTimePrivate::DaylightStatus QDateTimePrivate::ZoneState mapLocalTime(qint64 local, QDateTimePrivate::DaylightStatus dst) { - const qint64 localDays = QRoundingDown::qDiv(local, MSECS_PER_DAY); - qint64 millis = local - localDays * MSECS_PER_DAY; - Q_ASSERT(0 <= millis && millis < MSECS_PER_DAY); // Definition of QRD::qDiv. - struct tm tmLocal = timeToTm(localDays, int(millis / MSECS_PER_SEC), dst); - millis %= MSECS_PER_SEC; + 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(localSecs, SECS_PER_DAY); + qint64 daySecs = localSecs - localDays * SECS_PER_DAY; + Q_ASSERT(0 <= daySecs && daySecs < SECS_PER_DAY); // Definition of QRD::qDiv. + + struct tm tmLocal = timeToTm(localDays, daySecs, dst); time_t utcSecs; if (!callMkTime(&tmLocal, &utcSecs)) return {local}; @@ -368,22 +370,21 @@ QDateTimePrivate::ZoneState mapLocalTime(qint64 local, QDateTimePrivate::Dayligh &jd))) { return {local, offset, dst, false}; } - qint64 daySecs = tmSecsWithinDay(tmLocal); + daySecs = tmSecsWithinDay(tmLocal); Q_ASSERT(0 <= daySecs && daySecs < SECS_PER_DAY); if (daySecs > 0 && jd < JULIAN_DAY_FOR_EPOCH) { ++jd; daySecs -= SECS_PER_DAY; } - qint64 localSecs; if (Q_UNLIKELY(daysAndSecondsOverflow(jd, daySecs, &localSecs))) return {local, offset, dst, false}; offset = localSecs - utcSecs; - if (localSecs < 0 && millis > 0) { - ++localSecs; - millis -= MSECS_PER_SEC; - } + // The only way localSecs and millis can now have opposite sign is for + // resolution of the local time to have kicked us across the epoch, in which + // case there's no danger of overflow. So if overflow is in danger of + // happening, we're already doing the best we can to avoid it. qint64 revised; const bool overflow = secondsAndMillisOverflow(localSecs, millis, &revised); return {overflow ? local : revised, offset, dst, !overflow};