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.
--- 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++; + } + return (P); +} /* my_localtime */ + PP(pp_gmtime) { dSP; @@ -4531,7 +4576,11 @@ PP(pp_gmtime) #endif if (PL_op->op_type == OP_LOCALTIME) +#ifdef LOCALTIME_EDGECASE_BROKEN + tmbuf = my_localtime(&when); +#else tmbuf = localtime(&when); +#endif else tmbuf = gmtime(&when); -- H.Merijn Brand Amsterdam Perl Mongers (http://amsterdam.pm.org/) using Perl 5.6.2, 5.8.0, 5.8.5, & 5.9.2 on HP-UX 10.20, 11.00 & 11.11, AIX 4.3 & 5.2, SuSE 9.2 & 9.3, and Cygwin. http://www.cmve.net/~merijn Smoking perl: http://www.test-smoke.org, perl QA: http://qa.perl.org reports to: [EMAIL PROTECTED], perl-qa@perl.org