Rework getting normalized dates adjacent to a given one

I originally wrote dateNormalize() because I expected to need it more,
but it turns out to only be needed for two cases of getting the days
before and after a given one. So rename to adjacentDay(), pass the +1
or -1 step and simplify a little.

In the process, fix a mistake in the winding backwards across a year
boundary, where I'd incremented the year instead of decrementing it.

Change-Id: I1bb0a8323fec7c1caffa7f20879f08d3526ba7ea
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Edward Welbourne 2023-09-26 14:38:16 +02:00
parent 44cbd4c315
commit 02d8dc5f8c

View File

@ -195,36 +195,41 @@ struct tm matchYearMonth(struct tm when, const struct tm &base)
} }
Q_DECL_COLD_FUNCTION Q_DECL_COLD_FUNCTION
struct tm dateNormalize(struct tm when) struct tm adjacentDay(struct tm when, int dayStep)
{ {
int daysInMonth = 28; // Before we adjust it, when is a return from timeToTm(), so in normal form.
// We have to wind through months one at a time, since their lengths vary. Q_ASSERT(dayStep * dayStep == 1);
while (when.tm_mday < 1) { when.tm_mday += dayStep;
// Month before's day-count; but tm_mon's value is one less than Qt's // That may have bumped us across a month boundary or even a year one.
// month numbering so, before we decrement it, it has the value we need, // So now we normalize it.
// unless it's 0.
daysInMonth = when.tm_mon if (dayStep < 0) {
? QGregorianCalendar::monthLength(when.tm_mon, qYearFromTmYear(when.tm_year)) if (when.tm_mday <= 0) {
: QGregorianCalendar::monthLength(12, qYearFromTmYear(when.tm_year - 1)); // Month before's day-count; but tm_mon's value is one less than Qt's
when.tm_mday += daysInMonth; // month numbering so, before we decrement it, it has the value we need,
if (--when.tm_mon < 0) { // unless it's 0.
++when.tm_year; int daysInMonth = when.tm_mon
when.tm_mon = 11; ? QGregorianCalendar::monthLength(when.tm_mon, qYearFromTmYear(when.tm_year))
: QGregorianCalendar::monthLength(12, qYearFromTmYear(when.tm_year - 1));
when.tm_mday += daysInMonth;
if (--when.tm_mon < 0) {
--when.tm_year;
when.tm_mon = 11;
}
Q_ASSERT(when.tm_mday >= 1);
} }
} } else if (when.tm_mday > 28) {
// If we came via that loop, we have set daysInMonth and when.tm_mday is <= it. // We have to wind through months one at a time, since their lengths vary.
// Otherwise, daysInMonth is 28, so this serves as a cheap pre-test: int daysInMonth = QGregorianCalendar::monthLength(
if (when.tm_mday > daysInMonth) {
daysInMonth = QGregorianCalendar::monthLength(
when.tm_mon + 1, qYearFromTmYear(when.tm_year)); when.tm_mon + 1, qYearFromTmYear(when.tm_year));
while (when.tm_mday > daysInMonth) { if (when.tm_mday > daysInMonth) {
when.tm_mday -= daysInMonth; when.tm_mday -= daysInMonth;
if (++when.tm_mon > 11) { if (++when.tm_mon > 11) {
++when.tm_year; ++when.tm_year;
when.tm_mon = 0; when.tm_mon = 0;
} }
daysInMonth = QGregorianCalendar::monthLength( Q_ASSERT(when.tm_mday <= QGregorianCalendar::monthLength(
when.tm_mon + 1, qYearFromTmYear(when.tm_year)); when.tm_mon + 1, qYearFromTmYear(when.tm_year)));
} }
} }
return when; return when;
@ -278,12 +283,8 @@ MkTimeResult resolveRejected(struct tm base, MkTimeResult result,
constexpr time_t twoDaysInSeconds = 2 * 24 * 60 * 60; constexpr time_t twoDaysInSeconds = 2 * 24 * 60 * 60;
// Bracket base, one day each side (in case the zone skipped a whole day): // Bracket base, one day each side (in case the zone skipped a whole day):
struct tm adjust = base; MkTimeResult early(adjacentDay(base, -1));
--adjust.tm_mday; MkTimeResult later(adjacentDay(base, +1));
MkTimeResult early(dateNormalize(adjust));
adjust = base;
++adjust.tm_mday;
MkTimeResult later(dateNormalize(adjust));
if (!early.good || !later.good) // Assume out of range, rather than gap. if (!early.good || !later.good) // Assume out of range, rather than gap.
return {}; return {};