echs_instant_t echs_instant_add(echs_instant_t bas, echs_idiff_t add) { echs_instant_t res; int dd = add.dd; int msd = add.msd; int df_y; int df_m; res.y = bas.y + dd / 365; if ((df_y = res.y - bas.y)) { dd -= df_y * 365 + (df_y - 1) / 4; } res.m = bas.m + dd / 31; if ((df_m = res.m - bas.m)) { dd -= doy[bas.m + df_m] - doy[bas.m + 1]; } res.d = bas.d + dd; if (echs_instant_all_day_p(bas)) { res.H = ECHS_ALL_DAY; res.M = 0U; res.S = 0U; res.ms = 0U; goto out; } else if (msd < 0) { res.d--; msd += 86400000; } if (echs_instant_all_sec_p(bas)) { res.ms = ECHS_ALL_SEC; msd /= 1000; } else { int carry = (bas.ms + msd) / 1000; res.ms = (bas.ms + msd) % 1000; msd /= 1000; msd += carry; } { int carry = (bas.S + msd) / 60; res.S = (bas.S + msd) % 60; msd /= 60; msd += carry; } res.M = bas.M + msd % 60; msd /= 60; res.H = bas.H + msd % 24; msd /= 24; res.d += msd; out: return echs_instant_fixup(res); }
echs_instant_t echs_instant_add(echs_instant_t bas, echs_idiff_t add) { echs_instant_t res = bas; int dd = add.d / (int)MSECS_PER_DAY; int msd = add.d % (int)MSECS_PER_DAY; int car, cdr; if (UNLIKELY(echs_instant_all_day_p(bas))) { /* just fix up the day, dom and year portion */ goto fixup_d; } else if (UNLIKELY(echs_instant_all_sec_p(bas))) { /* just fix up the sec, min, ... portions */ msd /= (int)MSECS_PER_SEC; goto fixup_S; } car = (res.ms + msd) / (int)MSECS_PER_SEC; if ((cdr = (res.ms + msd) % (int)MSECS_PER_SEC) >= 0) { res.ms = cdr; } else { res.ms = cdr + MSECS_PER_SEC; car--; } msd = car; fixup_S: car = (res.S + msd) / (int)SECS_PER_MIN; if ((cdr = (res.S + msd) % (int)SECS_PER_MIN) >= 0) { res.S = cdr; } else { res.S = cdr + SECS_PER_MIN; car--; } msd = car; car = ((int)res.M + msd) / (int)MINS_PER_HOUR; if ((cdr = ((int)res.M + msd) % (int)MINS_PER_HOUR) >= 0) { res.M = cdr; } else { res.M = cdr + MINS_PER_HOUR; car--; } msd = car; car = (res.H + msd) / (int)HOURS_PER_DAY; if ((cdr = (res.H + msd) % (int)HOURS_PER_DAY) >= 0) { res.H = cdr; } else { res.H = cdr + HOURS_PER_DAY; car--; } msd = car; /* get ready to adjust the day */ if (UNLIKELY(msd)) { dd += msd; } if (dd) { int y; int m; int d; fixup_d: y = bas.y; m = bas.m; d = bas.d + dd; if (LIKELY(d >= 1 && d <= 28)) { /* all months in our design range have 28 days */ ; } else if (d < 1) { int mdays; do { if (UNLIKELY(--m < 1)) { --y; m = 12; } mdays = __get_mdays(y, m); d += mdays; } while (d < 1); } else { int mdays; while (d > (mdays = __get_mdays(y, m))) { d -= mdays; if (UNLIKELY(++m > 12)) { ++y; m = 1; } } } res.d = d; res.m = m; res.y = y; } return res; }
echs_instant_t echs_instant_fixup(echs_instant_t e) { /* this is basically __ymd_fixup_d of dateutils * we only care about additive cockups though because instants are * chronologically ascending */ unsigned int md; if (UNLIKELY(echs_instant_all_day_p(e))) { /* just fix up the day, dom and year portion */ goto fixup_d; } else if (UNLIKELY(echs_instant_all_sec_p(e))) { /* just fix up the sec, min, ... portions */ goto fixup_S; } if (UNLIKELY(e.ms >= MSECS_PER_SEC)) { unsigned int dS = e.ms / MSECS_PER_SEC; unsigned int ms = e.ms % MSECS_PER_SEC; e.ms = ms; e.S += dS; } fixup_S: if (UNLIKELY(e.S >= SECS_PER_MIN)) { /* leap seconds? */ unsigned int dM = e.S / SECS_PER_MIN; unsigned int S = e.S % SECS_PER_MIN; e.S = S; e.M += dM; } if (UNLIKELY(e.M >= MINS_PER_HOUR)) { unsigned int dH = e.M / MINS_PER_HOUR; unsigned int M = e.M % MINS_PER_HOUR; e.M = M; e.H += dH; } if (UNLIKELY(e.H >= HOURS_PER_DAY)) { unsigned int dd = e.H / HOURS_PER_DAY; unsigned int H = e.H % HOURS_PER_DAY; e.H = H; e.d += dd; } fixup_d: refix_ym: if (UNLIKELY(e.m > 12U)) { unsigned int dy = (e.m - 1) / 12U; unsigned int m = (e.m - 1) % 12U + 1U; e.m = m; e.y += dy; } if (UNLIKELY(e.d > (md = __get_mdays(e.y, e.m)))) { e.d -= md; e.m++; goto refix_ym; } return e; }
echs_instant_t echs_instant_fixup(echs_instant_t e) { /* this is basically __ymd_fixup_d of dateutils * we only care about additive cockups though because instants are * chronologically ascending */ static const unsigned int mdays[] = { 0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U, }; unsigned int md; if (UNLIKELY(echs_instant_all_day_p(e))) { /* just fix up the day, dom and year portion */ goto fixup_d; } if (UNLIKELY(e.S >= 60U)) { /* leap seconds? */ unsigned int dM = e.S / 60U; unsigned int S = e.S % 60U; e.S = S; e.M += dM; } if (UNLIKELY(e.M >= 60U)) { unsigned int dH = e.M / 60U; unsigned int M = e.M % 60U; e.M = M; e.H += dH; } if (UNLIKELY(e.H >= 24U)) { unsigned int dd = e.H / 24U; unsigned int H = e.H % 24U; e.H = H; e.d += dd; } fixup_d: if (UNLIKELY((int32_t)e.d <= 0)) { e.m--; } refix_ym: if (UNLIKELY((int32_t)e.m <= 0)) { unsigned int m = (e.m + 11) % 12U + 1U; e.m = m; e.y--; } else if (UNLIKELY(e.m > 12U)) { unsigned int dy = (e.m - 1) / 12U; unsigned int m = (e.m - 1) % 12U + 1U; e.m = m; e.y += dy; } if (UNLIKELY((int32_t)e.d <= 0)) { /* at least e.m should be fixed up now */ e.d += mdays[e.m]; /* leap year handling */ if (UNLIKELY(e.m == 2U && (e.y % 4U) == 0U)) { e.d++; } } else if (UNLIKELY(e.d > (md = mdays[e.m]))) { /* leap year handling */ if (UNLIKELY(e.m == 2U && (e.y % 4U) == 0U)) { md++; } if (LIKELY((e.d -= md) > 0)) { e.m++; goto refix_ym; } } return e; }