The fix is to use the fact that--at least for now--the calendar operates on a grand 2800-year cycle: any set of 2800 consecutive years contains exactly 1,022,679 days. A bit of modular arithmetic will get us where we want to be.
To me this calls attention to a fundamental design flaw: any computation of daylight savings time that involves looping a billion times, or even a thousand, cannot be right. Under what circumstances does this happen?
The attached might be used to avoid thousands of loops. --ado SCCS/s.localtime.c: 7.45 vs. 7.48 *** 7.45/localtime.c Mon Oct 23 10:48:43 1995 --- 7.48/localtime.c Mon Oct 23 10:48:45 1995 *************** *** 1,6 **** #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)localtime.c 7.45"; #endif /* !defined NOID */ #endif /* !defined lint */ --- 1,6 ---- #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)localtime.c 7.48"; #endif /* !defined NOID */ #endif /* !defined lint */ *************** *** 1173,1191 **** if (tmp->tm_wday < 0) tmp->tm_wday += DAYSPERWEEK; y = EPOCH_YEAR; ! if (days >= 0) ! for ( ; ; ) { ! yleap = isleap(y); ! if (days < (long) year_lengths[yleap]) ! break; ! ++y; ! days = days - (long) year_lengths[yleap]; ! } ! else do { ! --y; ! yleap = isleap(y); ! days = days + (long) year_lengths[yleap]; ! } while (days < 0); tmp->tm_year = y - TM_YEAR_BASE; tmp->tm_yday = (int) days; ip = mon_lengths[yleap]; --- 1173,1190 ---- if (tmp->tm_wday < 0) tmp->tm_wday += DAYSPERWEEK; y = EPOCH_YEAR; ! #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) ! while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) { ! register int newy; ! ! newy = y + days / DAYSPERNYEAR; ! if (days < 0) ! --newy; ! days -= (newy - y) * DAYSPERNYEAR + ! LEAPS_THRU_END_OF(newy - 1) - ! LEAPS_THRU_END_OF(y - 1); ! y = newy; ! } tmp->tm_year = y - TM_YEAR_BASE; tmp->tm_yday = (int) days; ip = mon_lengths[yleap];