* localtime.c (transtime): Refactor to allow negative years
and years of a different type in future versions.  Make the
code a bit clearer and faster with fewer conditional branches.
This does not change current behavior.
---
 localtime.c | 68 ++++++++++++++++++-----------------------------------
 1 file changed, 23 insertions(+), 45 deletions(-)

diff --git a/localtime.c b/localtime.c
index 8044f1a0..c2d58027 100644
--- a/localtime.c
+++ b/localtime.c
@@ -1536,37 +1536,23 @@ static int_fast32_t
 transtime(const int year, register const struct rule *const rulep,
          const int_fast32_t offset)
 {
+       int d;  /* Day of year (zero-origin).  */
        register bool   leapyear;
-       register int_fast32_t value;
-       register int    i;
-       int             d, m1, yy0, yy1, yy2, dow;
 
        leapyear = isleap(year);
-       switch (rulep->r_type) {
 
-       case JULIAN_DAY:
+       if (rulep->r_type <= DAY_OF_YEAR) {
                /*
                ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
                ** years.
                ** In non-leap years, or if the day number is 59 or less, just
-               ** add SECSPERDAY times the day number-1 to the time of
-               ** January 1, midnight, to get the day.
-               */
-               value = (rulep->r_day - 1) * SECSPERDAY;
-               if (leapyear && rulep->r_day >= 60)
-                       value += SECSPERDAY;
-               break;
-
-       case DAY_OF_YEAR:
-               /*
+               ** use the day number - 1.
+               **
                ** n - day of year.
-               ** Just add SECSPERDAY times the day number to the time of
-               ** January 1, midnight, to get the day.
                */
-               value = rulep->r_day * SECSPERDAY;
-               break;
-
-       case MONTH_NTH_DAY_OF_WEEK:
+               d = rulep->r_day - ((rulep->r_type < DAY_OF_YEAR)
+                                   & (!leapyear | (rulep->r_day <= 59)));
+       } else {
                /*
                ** Mm.n.d - nth "dth day" of month m.
                */
@@ -1575,14 +1561,15 @@ transtime(const int year, register const struct rule 
*const rulep,
                ** Use Zeller's Congruence to get day-of-week of first day of
                ** month.
                */
-               m1 = (rulep->r_mon + 9) % 12 + 1;
-               yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
-               yy1 = yy0 / 100;
-               yy2 = yy0 % 100;
-               dow = ((26 * m1 - 2) / 10 +
-                       1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
-               if (dow < 0)
-                       dow += DAYSPERWEEK;
+               int i;
+               bool janfeb = rulep->r_mon <= 2;
+               int month = (rulep->r_mon
+                            + (janfeb ? MONSPERYEAR : 0)); /* 3..14  */
+               int ay_rem = (year - janfeb) % YEARSPERREPEAT;
+               int y = ay_rem + (ay_rem < 0 ? YEARSPERREPEAT : 0);
+               int dow = (((13 * (month + 1)) / 5
+                           + y + y / 4 - y / 100 + y / 400)
+                          % DAYSPERWEEK);
 
                /*
                ** "dow" is the day-of-week of the first day of the month. Get
@@ -1590,33 +1577,24 @@ transtime(const int year, register const struct rule 
*const rulep,
                ** month.
                */
                d = rulep->r_day - dow;
-               if (d < 0)
-                       d += DAYSPERWEEK;
-               for (i = 1; i < rulep->r_week; ++i) {
-                       if (d + DAYSPERWEEK >=
-                               mon_lengths[leapyear][rulep->r_mon - 1])
-                                       break;
-                       d += DAYSPERWEEK;
-               }
+               d += (rulep->r_week - (0 <= d)) * DAYSPERWEEK;
+               if (mon_lengths[leapyear][rulep->r_mon - 1] <= d)
+                 d -= DAYSPERWEEK;
 
                /*
                ** "d" is the day-of-month (zero-origin) of the day we want.
                */
-               value = d * SECSPERDAY;
                for (i = 0; i < rulep->r_mon - 1; ++i)
-                       value += mon_lengths[leapyear][i] * SECSPERDAY;
-               break;
-
-       default: unreachable();
+                 d += mon_lengths[leapyear][i];
        }
 
        /*
-       ** "value" is the year-relative time of 00:00:00 UT on the day in
+       ** d is the origin-0 year-relative day in
        ** question. To get the year-relative time of the specified local
        ** time on that day, add the transition time and the current offset
-       ** from UT.
+       ** from UT to d * SECSPERDAY.
        */
-       return value + rulep->r_time + offset;
+       return d * SECSPERDAY + rulep->r_time + offset;
 }
 
 /*
-- 
2.55.0

Reply via email to