Mktime on systems with exotic time_t types
Olson, Arthur David (NIH/NCI)
olsona at dc37a.nci.nih.gov
Tue Jan 11 18:11:21 UTC 2005
Below find proposed changes to localtime.c to get mktime working correctly
on systems with exotic time_t types (such as unsigned or double).
Also included are changes to zdump.c and Makefile to arrange things that
doing a...
make typecheck
...exercises mktime for a good range of values.
--ado
------- localtime.c -------
*** /tmp/geta3175 Tue Jan 11 11:57:49 2005
--- /tmp/getb3175 Tue Jan 11 11:57:49 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 at 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.87";
#endif /* !defined NOID */
#endif /* !defined lint */
***************
*** 1445,1450 ****
--- 1440,1447 ----
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)
--- 1515,1565 ----
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) FLT_MAX;
! else hi = (time_t) DBL_MAX;
! lo = -hi;
! } else {
! register int i;
!
! lo = 1;
! for (i = 0; i < 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)
--- 1589,1595 ----
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)
------- zdump.c -------
*** /tmp/geta3196 Tue Jan 11 11:57:58 2005
--- /tmp/getb3196 Tue Jan 11 11:57:58 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.60";
/*
** This code has been made independent of the rest of the time
***************
*** 154,159 ****
--- 154,195 ----
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;
***************
*** 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')
------- Makefile -------
*** /tmp/geta3221 Tue Jan 11 11:58:07 2005
--- /tmp/getb3221 Tue Jan 11 11:58:07 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
More information about the tz
mailing list