Revised mktime on systems with exotic time_t types
Thanks to Paul Eggert and Ken Pizzini for checking the proposed changes to improve mktime on systems with exotic time_t types. Below find a revised version of the changes; as usual for yours truly, these are relative to what's currently available using ftp. With providence, a new version of the time zone stuff incorporating these changes and Paul's proposed data changes will go out next week. --ado ------- localtime.c ------- *** /tmp/geta10193 Thu Jan 13 09:58:48 2005 --- /tmp/getb10193 Thu Jan 13 09:58:48 2005 *************** *** 1,9 **** /* - ** XXX--have mktime et al. do the right thing when time_t is exotic - ** (for example, double). - */ - - /* ** This file is in the public domain, so clarified as of ** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov). */ --- 1,4 ---- *************** *** 10,16 **** #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)localtime.c 7.86"; #endif /* !defined NOID */ #endif /* !defined lint */ --- 5,11 ---- #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)localtime.c 7.89"; #endif /* !defined NOID */ #endif /* !defined lint */ *************** *** 1061,1067 **** for (i = 1; i < sp->timecnt; ++i) if (t < sp->ats[i]) break; ! i = sp->types[i - 1]; } ttisp = &sp->ttis[i]; /* --- 1056,1062 ---- for (i = 1; i < sp->timecnt; ++i) if (t < sp->ats[i]) break; ! i = (int) sp->types[i - 1]; } ttisp = &sp->ttis[i]; /* *************** *** 1092,1102 **** */ struct tm * ! localtime_r(timep, tm) const time_t * const timep; ! struct tm * tm; { ! return localsub(timep, 0L, tm); } /* --- 1087,1097 ---- */ struct tm * ! localtime_r(timep, tmp) const time_t * const timep; ! struct tm * tmp; { ! return localsub(timep, 0L, tmp); } /* *************** *** 1154,1164 **** */ struct tm * ! gmtime_r(timep, tm) const time_t * const timep; ! struct tm * tm; { ! return gmtsub(timep, 0L, tm); } #ifdef STD_INSPIRED --- 1149,1159 ---- */ struct tm * ! gmtime_r(timep, tmp) const time_t * const timep; ! struct tm * tmp; { ! return gmtsub(timep, 0L, tmp); } #ifdef STD_INSPIRED *************** *** 1338,1346 **** const time_t * const timep; char * buf; { ! struct tm tm; ! return asctime_r(localtime_r(timep, &tm), buf); } /* --- 1333,1341 ---- const time_t * const timep; char * buf; { ! struct tm mytm; ! return asctime_r(localtime_r(timep, &mytm), buf); } /* *************** *** 1441,1450 **** { register const struct state * sp; register int dir; - register int bits; register int i, j; register int saved_seconds; register long li; long y; time_t newt; time_t t; --- 1436,1446 ---- { register const struct state * sp; register int dir; register int i, j; register int saved_seconds; register long li; + register time_t lo; + register time_t hi; long y; time_t newt; time_t t; *************** *** 1518,1545 **** yourtm.tm_sec = 0; } /* ! ** Divide the search space in half ! ** (this works whether time_t is signed or unsigned). */ ! bits = TYPE_BIT(time_t) - 1; ! /* ! ** If time_t is signed, then 0 is just above the median, ! ** assuming two's complement arithmetic. ! ** If time_t is unsigned, then (1 << bits) is just above the median. ! */ ! t = TYPE_SIGNED(time_t) ? 0 : (((unsigned long) 1) << bits); for ( ; ; ) { ! if ((*funcp)(&t, offset, &mytm) == NULL) ! return WRONG; /* XXX probably wrong */ ! dir = tmcomp(&mytm, &yourtm); if (dir != 0) { ! if (bits-- < 0) return WRONG; ! if (bits < 0) ! --t; /* may be needed if new t is minimal */ ! else if (dir > 0) ! t -= ((long) 1) << bits; ! else t += ((long) 1) << bits; continue; } if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) --- 1514,1562 ---- yourtm.tm_sec = 0; } /* ! ** Do a binary search (this works whatever time_t's type is). */ ! if (!TYPE_SIGNED(time_t)) { ! lo = 0; ! hi = lo - 1; ! } else if (!TYPE_INTEGRAL(time_t)) { ! if (sizeof(time_t) > sizeof(float)) ! hi = (time_t) DBL_MAX; ! else hi = (time_t) FLT_MAX; ! lo = -hi; ! } else { ! lo = 1; ! for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i) ! lo *= 2; ! hi = -(lo + 1); ! } for ( ; ; ) { ! t = lo / 2 + hi / 2; ! if (t < lo) ! t = lo; ! else if (t > hi) ! t = hi; ! if ((*funcp)(&t, offset, &mytm) == NULL) { ! /* ! ** Assume that t is too extreme to be represented in ! ** a struct tm; arrange things so that it is less ! ** extreme on the next pass. ! */ ! dir = (t > 0) ? 1 : -1; ! } else dir = tmcomp(&mytm, &yourtm); if (dir != 0) { ! if (t == lo) { ! ++t; ! ++lo; ! } else if (t == hi) { ! --t; ! --hi; ! } ! if (lo > hi) return WRONG; ! if (dir > 0) ! hi = t; ! else lo = t; continue; } if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) *************** *** 1569,1575 **** newt = t + sp->ttis[j].tt_gmtoff - sp->ttis[i].tt_gmtoff; if ((*funcp)(&newt, offset, &mytm) == NULL) ! return WRONG; /* XXX probably wrong */ if (tmcomp(&mytm, &yourtm) != 0) continue; if (mytm.tm_isdst != yourtm.tm_isdst) --- 1586,1592 ---- newt = t + sp->ttis[j].tt_gmtoff - sp->ttis[i].tt_gmtoff; if ((*funcp)(&newt, offset, &mytm) == NULL) ! continue; if (tmcomp(&mytm, &yourtm) != 0) continue; if (mytm.tm_isdst != yourtm.tm_isdst) ------- Makefile ------- *** /tmp/geta10212 Thu Jan 13 09:58:57 2005 --- /tmp/getb10212 Thu Jan 13 09:58:57 2005 *************** *** 1,4 **** ! # @(#)Makefile 7.102 # Change the line below for your time zone (after finding the zone you want in # the time zone files, or adding it to a time zone file). --- 1,4 ---- ! # @(#)Makefile 7.103 # Change the line below for your time zone (after finding the zone you want in # the time zone files, or adding it to a time zone file). *************** *** 396,404 **** typecheck: make clean ! for i in "long long" double unsigned; \ do \ ! make CFLAGS="-D_TIME_T \"-Dtime_t=$$i\"" ; \ ./zdump -v US/Eastern ; \ make clean ; \ done --- 396,404 ---- typecheck: make clean ! for i in "long long" unsigned double; \ do \ ! make CFLAGS="-DTYPECHECK -D_TIME_T \"-Dtime_t=$$i\"" ; \ ./zdump -v US/Eastern ; \ make clean ; \ done ------- zdump.c ------- *** /tmp/geta10231 Thu Jan 13 09:59:07 2005 --- /tmp/getb10231 Thu Jan 13 09:59:07 2005 *************** *** 1,4 **** ! static char elsieid[] = "@(#)zdump.c 7.59"; /* ** This code has been made independent of the rest of the time --- 1,4 ---- ! static char elsieid[] = "@(#)zdump.c 7.61"; /* ** This code has been made independent of the rest of the time *************** *** 149,159 **** static long delta P((struct tm * newp, struct tm * oldp)); static void dumptime P((const struct tm * tmp)); static time_t hunt P((char * name, time_t lot, time_t hit)); ! static void setabsolutes(); static void show P((char * zone, time_t t, int v)); static const char * tformat P((void)); static time_t yeartot P((long y)); int main(argc, argv) int argc; --- 149,195 ---- static long delta P((struct tm * newp, struct tm * oldp)); static void dumptime P((const struct tm * tmp)); static time_t hunt P((char * name, time_t lot, time_t hit)); ! static void setabsolutes P((void)); static void show P((char * zone, time_t t, int v)); static const char * tformat P((void)); static time_t yeartot P((long y)); + #ifndef TYPECHECK + #define my_localtime localtime + #else /* !defined TYPECHECK */ + static struct tm * + my_localtime(tp) + time_t * tp; + { + register struct tm * tmp; + + tmp = localtime(tp); + if (tp != NULL && tmp != NULL) { + struct tm tm; + register time_t t; + + tm = *tmp; + t = mktime(&tm); + if (t - *tp >= 1 || *tp - t >= 1) { + (void) fflush(stdout); + (void) fprintf(stderr, "\n%s: ", progname); + (void) fprintf(stderr, tformat(), *tp); + (void) fprintf(stderr, " ->"); + (void) fprintf(stderr, " sec %d", tmp->tm_sec); + (void) fprintf(stderr, " min %d", tmp->tm_min); + (void) fprintf(stderr, " hour %d", tmp->tm_hour); + (void) fprintf(stderr, " mday %d", tmp->tm_mday); + (void) fprintf(stderr, " mon %d", tmp->tm_mon); + (void) fprintf(stderr, " year %d", tmp->tm_year); + (void) fprintf(stderr, " -> "); + (void) fprintf(stderr, tformat(), t); + (void) fprintf(stderr, "\n"); + } + } + return tmp; + } + #endif /* !defined TYPECHECK */ + int main(argc, argv) int argc; *************** *** 208,219 **** if (cutarg != NULL) { long lo; long hi; ! char c; ! if (sscanf(cutarg, "%ld%c", &hi, &c) == 1) { cuthiyear = hi; } else if (sscanf(cutarg, "%ld,%ld%c", ! &lo, &hi, &c) == 2) { cutloyear = lo; cuthiyear = hi; } else { --- 244,255 ---- if (cutarg != NULL) { long lo; long hi; ! char dummy; ! if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) { cuthiyear = hi; } else if (sscanf(cutarg, "%ld,%ld%c", ! &lo, &hi, &dummy) == 2) { cutloyear = lo; cuthiyear = hi; } else { *************** *** 266,272 **** show(argv[i], t, TRUE); if (t < cutlotime) t = cutlotime; ! tmp = localtime(&t); if (tmp != NULL) { tm = *tmp; (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1); --- 302,308 ---- show(argv[i], t, TRUE); if (t < cutlotime) t = cutlotime; ! tmp = my_localtime(&t); if (tmp != NULL) { tm = *tmp; (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1); *************** *** 399,405 **** register struct tm * tmp; char loab[MAX_STRING_LENGTH]; ! lotmp = localtime(&lot); if (lotmp != NULL) { lotm = *lotmp; (void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1); --- 435,441 ---- register struct tm * tmp; char loab[MAX_STRING_LENGTH]; ! lotmp = my_localtime(&lot); if (lotmp != NULL) { lotm = *lotmp; (void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1); *************** *** 414,420 **** ++t; else if (t >= hit) --t; ! tmp = localtime(&t); if (tmp != NULL) tm = *tmp; if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) : --- 450,456 ---- ++t; else if (t >= hit) --t; ! tmp = my_localtime(&t); if (tmp != NULL) tm = *tmp; if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) : *************** *** 477,483 **** } (void) printf(" = "); } ! tmp = localtime(&t); dumptime(tmp); if (tmp != NULL) { if (*abbr(tmp) != '\0') --- 513,519 ---- } (void) printf(" = "); } ! tmp = my_localtime(&t); dumptime(tmp); if (tmp != NULL) { if (*abbr(tmp) != '\0')
participants (1)
-
Olson, Arthur David (NIH/NCI)