On Fri, Jun 24, 2005 at 09:02:37AM +0200, H.Merijn Brand wrote: > In my queeste to get only 'O's in the smokes, I have attacked the bug in AIX > 5.2's implementation of it's localtime function. Please read and comment.
Hi, Sorry for responding so slowly -- I had just gone on holiday when you posted this. > --- pp_sys.c.org 2005-06-24 08:08:48.000000000 +0200 > +++ pp_sys.c 2005-06-24 08:57:36.000000000 +0200 > @@ -201,6 +201,15 @@ void endservent(void); > #undef PERL_EFF_ACCESS_W_OK > #undef PERL_EFF_ACCESS_X_OK > > +/* AIX 5.2 and below use mktime for localtime, and defines the edge case > + * for time 0x7fffffff to be valid only in UTC. AIX 5.3 provides localtime64 > + * available in the 32bit environment, which could warrant Configure > + * checks in the future. > + */ > +#ifdef _AIX > +#define LOCALTIME_EDGECASE_BROKEN > +#endif > + > /* F_OK unused: if stat() cannot find it... */ > > #if !defined(PERL_EFF_ACCESS_R_OK) && defined(HAS_ACCESS) && defined > (EFF_ONLY_ K) && !defined(NO_EFF_ONLY_OK) > @@ -4510,6 +4519,42 @@ PP(pp_localtime) > return pp_gmtime(); > } > > +static struct tm *my_localtime (Time_t *tp) > +{ > + auto time_t T; > + auto struct tm *P; > + > + /* No workarounds in the valid range */ > + if (!tp || *tp < 0x7fff573f || *tp >= 0x80000000) > + return (localtime (tp)); > + > + /* This edge case is to workaround the undefined behaviour, where the > + * TIMEZONE makes the time go beyond the defined range. > + * gmtime (0x7fffffff) => 2038-01-19 03:14:07 > + * If there is a negative offset in TZ, like MET-1METDST, some broken > + * implementations of localtime () (like AIX 5.2) barf with bogus > + * return values: > + * 0x7fffffff gmtime 2038-01-19 03:14:07 > + * 0x7fffffff localtime 1901-12-13 21:45:51 > + * 0x7fffffff mylocaltime 2038-01-19 04:14:07 > + * 0x3c19137f gmtime 2001-12-13 20:45:51 > + * 0x3c19137f localtime 2001-12-13 21:45:51 > + * 0x3c19137f mylocaltime 2001-12-13 21:45:51 > + * Given that legal timezones are typically between GMT-12 and GMT+12 > + * we turn back the clock 23 hours before calling the localtime > + * function, and add those to the return value. This will never cause > + * day wrapping problems, since the edge case is Jan *19* > + */ > + T = *tp - 82800; /* 23 hour. allows up to GMT-23 */ > + P = localtime (&T); > + P->tm_hour += 23; > + if (P->tm_hour >= 24) { > + P->tm_hour -= 24; > + P->tm_mday++; > + } Well, it's not nice, but I suppose it should fix the boundary case. However, I think you should also increment these other fields along with tm_mday: int tm_wday; /* Day of week (Sunday = 0) */ int tm_yday; /* Day of year (0 - 365) */ I'm not fond of this sort of struct tm manipulation. It's easy to get wrong, and then you have just replaced a known bug by an unknown one. Luckily, 2038-01-19 is supposed to be on a Tuesday, and we are sufficiently far away from the boundaries of the week, month, and year... Until someone starts using TZ=CUT-50, say :-( Hth, -- $_ = "Campo Weijerman [rfc822://nl.ibm.com/]" and tr-[:]/-<@>-d and print;