Revised mktime on systems with exotic time_t types
Olson, Arthur David (NIH/NCI)
olsona at dc37a.nci.nih.gov
Thu Jan 13 15:03:35 UTC 2005
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 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.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')
More information about the tz
mailing list