Alain Guibert <[EMAIL PROTECTED]> writes:
> (1) Libc 5.4.33 own mktime() produces wrong by some minutes results for
> all summer dates when tm_isdst is forced to false 0. Wget's
> mktime_from_utc() forces tm_isdst=0 at a stage, and produces wrong by
> some minutes result only for one hour, beginning at DST transition plus
> one hour.
>
> (2) Replacing wget's mktime_from_utc() by a TZ=GMT0 mktime() scheme.
> Solves problem one, is faster, may seem cleaner (no discontinuities to
> support), but introduces portability issues. Still at discussion.
>
> (3) When wget's cmpt.c:mktime() is forced to override platform's
> mktime(), then mktime_from_utc() produces wrong results for two hours,
> beginning at to-DST transition plus two hours. Wrong by an hour less, or
> totally wrong. Even on platforms not affected by problem one.
Am I completely off the mark, or can mktime_from_utc (or in fact
timegm) be replaced by something as simple as the following? Or is it
too good to be true?
#ifndef HAVE_TIMEGM
/* timegm is a GNU extension, but lately also available on *BSD and
possibly elsewhere. */
/* Inverse of gmtime: converts struct tm to time_t, assuming the data
in tm is UTC rather than local timezone. This implementation
returns the number of seconds since 1970-01-01, converted to
time_t. */
#define IS_LEAP(year) \
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
time_t
timegm (struct tm *t)
{
static const unsigned short int month_to_days[][13] = {
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }
};
unsigned long secs;
int days;
/* Only handles years between 1970 and 2099. */
if (t->tm_year < 70 || t->tm_year > 129)
return (time_t) -1;
days = 365 * (t->tm_year - 70);
/* Take into account leap years between 1970 and t->tm_year-1; all
years divisible by four between 1968 and 2100 should be leap. */
days += (t->tm_year - 1 - 68) / 4;
if (t->tm_mon < 0 || t->tm_mon >= 12)
return (time_t) -1;
days += month_to_days[IS_LEAP (1900 + t->tm_year)][t->tm_mon];
days += t->tm_mday - 1;
secs = days * 86400 + t->tm_hour * 3600 + t->tm_min * 60 + t->tm_sec;
return (time_t) secs;
}
#endif /* HAVE_TIMEGM */