* private.h (DAYSPERREPEAT): New macro. (SECSPERREPEAT, AVGSECSPERYEAR): Use it. Rearrange REPEATish macros in a more-logical order. * zic.c (rpytime): Avoid some conditional branches and don’t treat years in the range 0..1969 as a special case. The code for negative years was dubious anyway. (LDAYSPERWEEK): Remove. All uses removed. --- private.h | 18 ++++++------------ zic.c | 46 +++++++++++++++++----------------------------- 2 files changed, 23 insertions(+), 41 deletions(-) diff --git a/private.h b/private.h index a919e4f..e38a4f3 100644 --- a/private.h +++ b/private.h @@ -710,8 +710,6 @@ char *ctime_r(time_t const *, char *); /* Handy macros that are independent of tzfile implementation. */ -#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */ - #define SECSPERMIN 60 #define MINSPERHOUR 60 #define HOURSPERDAY 24 @@ -722,6 +720,12 @@ char *ctime_r(time_t const *, char *); #define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY) #define MONSPERYEAR 12 +#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */ +#define DAYSPERREPEAT ((int_fast32_t) 400 * 365 + 100 - 4 + 1) +#define SECSPERREPEAT ((int_fast64_t) DAYSPERREPEAT * SECSPERDAY) +#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */ +#define AVGSECSPERYEAR (SECSPERREPEAT / YEARSPERREPEAT) + #define TM_SUNDAY 0 #define TM_MONDAY 1 #define TM_TUESDAY 2 @@ -764,14 +768,4 @@ char *ctime_r(time_t const *, char *); #define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) - -/* -** The Gregorian year averages 365.2425 days, which is 31556952 seconds. -*/ - -#define AVGSECSPERYEAR 31556952L -#define SECSPERREPEAT \ - ((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR) -#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */ - #endif /* !defined PRIVATE_H */ diff --git a/zic.c b/zic.c index f5d813b..6c38bd7 100644 --- a/zic.c +++ b/zic.c @@ -3420,6 +3420,7 @@ rpytime(const struct rule *rp, zic_t wantedy) register int m, i; register zic_t dayoff; /* with a nod to Margaret O. */ register zic_t t, y; + int yrem; if (wantedy == ZIC_MIN) return min_time; @@ -3428,24 +3429,20 @@ rpytime(const struct rule *rp, zic_t wantedy) dayoff = 0; m = TM_JANUARY; y = EPOCH_YEAR; - if (y < wantedy) { - wantedy -= y; - dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY); - wantedy %= YEARSPERREPEAT; - wantedy += y; - } else if (wantedy < 0) { - dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY); - wantedy %= YEARSPERREPEAT; - } + + /* dayoff = floor((wantedy - y) / YEARSPERREPEAT) * DAYSPERREPEAT, + sans overflow. */ + yrem = wantedy % YEARSPERREPEAT - y % YEARSPERREPEAT; + dayoff = ((wantedy / YEARSPERREPEAT - y / YEARSPERREPEAT + + yrem / YEARSPERREPEAT - (yrem % YEARSPERREPEAT < 0)) + * DAYSPERREPEAT); + /* wantedy = y + ((wantedy - y) mod YEARSPERREPEAT), sans overflow. */ + wantedy = y + (yrem + 2 * YEARSPERREPEAT) % YEARSPERREPEAT; + while (wantedy != y) { - if (wantedy > y) { - i = len_years[isleap(y)]; - ++y; - } else { - --y; - i = -len_years[isleap(y)]; - } + i = len_years[isleap(y)]; dayoff = oadd(dayoff, i); + y++; } while (m != rp->r_month) { i = len_months[isleap(y)][m]; @@ -3464,30 +3461,21 @@ rpytime(const struct rule *rp, zic_t wantedy) --i; dayoff = oadd(dayoff, i); if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { - register zic_t wday; - -#define LDAYSPERWEEK ((zic_t) DAYSPERWEEK) - wday = EPOCH_WDAY; /* ** Don't trust mod of negative numbers. */ - if (dayoff >= 0) - wday = (wday + dayoff) % LDAYSPERWEEK; - else { - wday -= ((-dayoff) % LDAYSPERWEEK); - if (wday < 0) - wday += LDAYSPERWEEK; - } + zic_t wday = ((EPOCH_WDAY + dayoff % DAYSPERWEEK + DAYSPERWEEK) + % DAYSPERWEEK); while (wday != rp->r_wday) if (rp->r_dycode == DC_DOWGEQ) { dayoff = oadd(dayoff, 1); - if (++wday >= LDAYSPERWEEK) + if (++wday >= DAYSPERWEEK) wday = 0; ++i; } else { dayoff = oadd(dayoff, -1); if (--wday < 0) - wday = LDAYSPERWEEK - 1; + wday = DAYSPERWEEK - 1; --i; } if (i < 0 || i >= len_months[isleap(y)][m]) { -- 2.27.0