From: hniksic Date: Tue, 5 Jul 2005 10:26:57 +0000 (-0700) Subject: [svn] A new timegm implementation. X-Git-Tag: v1.13~794 X-Git-Url: http://sjero.net/git/?p=wget;a=commitdiff_plain;h=1ebb66269fa80ee576c08f4b8d721f50a640f73b [svn] A new timegm implementation. --- diff --git a/src/ChangeLog b/src/ChangeLog index 644559f2..3143b83b 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +2005-07-05 Hrvoje Niksic + + * cmpt.c (timegm): Don't call mktime; simply count the seconds + between 1970-01-01 and the specified date. + 2005-07-05 Hrvoje Niksic * wget.h (or): Define HAVE_SSL when either HAVE_OPENSSL or diff --git a/src/cmpt.c b/src/cmpt.c index 1b69eab9..1f63291f 100644 --- a/src/cmpt.c +++ b/src/cmpt.c @@ -1226,64 +1226,37 @@ fnmatch (const char *pattern, const char *string, int flags) possibly elsewhere. */ /* Inverse of gmtime: converts struct tm to time_t, assuming the data - in tm is UTC rather than local timezone. - - mktime is similar but assumes struct tm, also known as the - "broken-down" form of time, is in local time zone. This - implementation of timegm uses mktime to make the conversion - understanding that an offset will be introduced by the local time - assumption. - - It then measures the introduced offset by applying gmtime to the - initial result and applying mktime to the resulting "broken-down" - form. The difference between the two mktime results is the - measured offset which is then subtracted from the initial mktime - result to yield a calendar time which is the value returned. - - tm_isdst in struct tm is set to 0 to force mktime to introduce a - consistent offset (the non DST offset) since tm and tm+o might be - on opposite sides of a DST change. - - Some implementations of mktime return -1 for the nonexistent - localtime hour at the beginning of DST. In this event, use - mktime(tm - 1hr) + 3600. - - Schematically - mktime(tm) --> t+o - gmtime(t+o) --> tm+o - mktime(tm+o) --> t+2o - t+o - (t+2o - t+o) = t - - Contributed by Roger Beeman, with the help of Mark Baushke and - other experts at CISCO. Further improved by Roger with assistance - from Edward J. Sabol based on input by Jamie Zawinski. */ + in tm is UTC rather than local timezone. This implementation + returns the number of seconds since 1070-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) { - time_t tl, tb; - struct tm *tg; - - tl = mktime (t); - if (tl == -1) - { - t->tm_hour--; - tl = mktime (t); - if (tl == -1) - return -1; /* can't deal with contents of T */ - tl += 3600; - } - tg = gmtime (&tl); - tg->tm_isdst = 0; - tb = mktime (tg); - if (tb == -1) - { - tg->tm_hour--; - tb = mktime (tg); - if (tb == -1) - return -1; /* can't deal with output from gmtime */ - tb += 3600; - } - return (tl - (tb - tl)); + 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 year, 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 the leap days between 1970 and 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 */