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;

Reply via email to