Path: utzoo!utgpu!water!watmath!clyde!rutgers!rochester!PT.CS.CMU.EDU!K.GP.CS.CMU.EDU!bww From: bww@K.GP.CS.CMU.EDU (Bradley White) Newsgroups: comp.bugs.4bsd Subject: ctime(3) and leap seconds :-) Keywords: ctime, leap second, epoch Message-ID: <604@PT.CS.CMU.EDU> Date: 7 Jan 88 18:35:41 GMT Sender: netnews@PT.CS.CMU.EDU Organization: Carnegie-Mellon University, CS/RI Lines: 118 Index: lib/libc/gen/ctime.c 4.3BSD Description: The time routines in the C library know nothing about leap seconds. This means that the correspondence between the number of seconds since the epoch and the actual time of day is broken. Repeat-By: Count the actual number of seconds since January 1, 1970 and run the answer through ctime(3). Notice that the answer is fourteen seconds in the future. Fix: Apply the following patch and then check the output of the test program. main() { long t; t = 567993612; printf("%s", ctime(&t)); t = 567993613; printf("%s", ctime(&t)); t = 567993614; printf("%s", ctime(&t)); } It should look like this (in EST at least). Thu Dec 31 18:59:59 1987 Thu Dec 31 18:59:60 1987 Thu Dec 31 19:00:00 1987 RCS file: RCS/ctime.c,v retrieving revision 1.1 diff -c -r1.1 ctime.c *** /tmp/,RCSt1011358 Wed Jan 6 00:08:34 1988 --- ctime.c Wed Jan 6 00:03:48 1988 *************** *** 321,326 **** --- 321,362 ---- return tmp; } + /* THE LEAP SECOND TABLE SHOULD BE LOADED FROM A FILE */ + + static struct leapsec { + time_t ls_when; + long ls_corr; + } leapsecs[] = { + 78796800, 1, /* 30 Jun 1972 */ + 94694401, 2, /* 31 Dec 1972 */ + 126230402, 3, /* 31 Dec 1973 */ + 157766403, 4, /* 31 Dec 1974 */ + 189302404, 5, /* 31 Dec 1975 */ + 220924805, 6, /* 31 Dec 1976 */ + 252460806, 7, /* 31 Dec 1977 */ + 283996807, 8, /* 31 Dec 1978 */ + 315532808, 9, /* 31 Dec 1979 */ + 362793609, 10, /* 30 Jun 1981 */ + 394329610, 11, /* 30 Jun 1982 */ + 425865611, 12, /* 30 Jun 1983 */ + 489024012, 13, /* 30 Jun 1985 */ + 567993613, 14 /* 31 Dec 1987 */ + }; + + #define NLEAPSECS (sizeof(leapsecs)/sizeof(leapsecs[0])) + + struct leapsec * + lssearch(t) + time_t t; + { + register int i = NLEAPSECS; + + while (--i >= 0) + if (t >= leapsecs[i].ls_when) + return &leapsecs[i]; + return 0; + } + static int mon_lengths[2][MONS_PER_YEAR] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 *************** *** 341,348 **** --- 377,392 ---- register int y; register int yleap; register int * ip; + int ls_flag; + struct leapsec *l; static struct tm tm; + ls_flag = 0; + if (l = lssearch(*clock)) { + if (*clock == l->ls_when) + ls_flag = 1; + *clock -= l->ls_corr; + } tmp = &tm; days = *clock / SECS_PER_DAY; rem = *clock % SECS_PER_DAY; *************** *** 359,364 **** --- 403,415 ---- rem = rem % SECS_PER_HOUR; tmp->tm_min = (int) (rem / SECS_PER_MIN); tmp->tm_sec = (int) (rem % SECS_PER_MIN); + if (ls_flag) + /* + * How should a leap second be represented? + * We choose to add one to tm_sec which will + * usually result in "... ??:59:60". + */ + tmp->tm_sec += 1; tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYS_PER_WEEK); if (tmp->tm_wday < 0) tmp->tm_wday += DAYS_PER_WEEK; -- -- Bradley White +1-412-268-3060 CMU Computer Science Department 40 26'33"N 79 56'48"W