diff options
Diffstat (limited to 'lib/parsedate.c')
-rw-r--r-- | lib/parsedate.c | 72 |
1 files changed, 40 insertions, 32 deletions
diff --git a/lib/parsedate.c b/lib/parsedate.c index 64bb2cc41..d1d1fdc82 100644 --- a/lib/parsedate.c +++ b/lib/parsedate.c @@ -222,6 +222,38 @@ enum assume { DATE_TIME }; +/* struct tm to time since epoch in GMT time zone */ +static time_t my_timegm(struct tm * tm) +{ + int month_days_cumulative [12] = + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + int month, year, leap_days; + + if(tm->tm_year < 70) + /* we don't support years before 1970 as they will cause this function + to return a negative value */ + return -1; + + year = tm->tm_year + 1900; + month = tm->tm_mon; + if (month < 0) { + year += (11 - month) / 12; + month = 11 - (11 - month) % 12; + } + else if (month >= 12) { + year -= month / 12; + month = month % 12; + } + + leap_days = year - (tm->tm_mon <= 1); + leap_days = ((leap_days / 4) - (leap_days / 100) + (leap_days / 400) + - (1969 / 4) + (1969 / 100) - (1969 / 400)); + + return ((((time_t) (year - 1970) * 365 + + leap_days + month_days_cumulative [month] + tm->tm_mday - 1) * 24 + + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec; +} + static time_t parsedate(const char *date) { time_t t = 0; @@ -247,7 +279,8 @@ static time_t parsedate(const char *date) /* a name coming up */ char buf[32]=""; size_t len; - sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]", buf); + sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]", + buf); len = strlen(buf); if(wdaynum == -1) { @@ -374,45 +407,20 @@ static time_t parsedate(const char *date) tm.tm_yday = 0; tm.tm_isdst = 0; - /* mktime() returns a time_t. time_t is often 32 bits, even on many + /* my_timegm() returns a time_t. time_t is often 32 bits, even on many architectures that feature 64 bit 'long'. Some systems have 64 bit time_t and deal with years beyond 2038. However, - even some of the systems with 64 bit time_t returns -1 for dates beyond - 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06) + even on some of the systems with 64 bit time_t mktime() returns -1 for + dates beyond 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06) */ - t = mktime(&tm); + t = my_timegm(&tm); /* time zone adjust (cast t to int to compare to negative one) */ if(-1 != (int)t) { - struct tm *gmt; - long delta; - time_t t2; - -#ifdef HAVE_GMTIME_R - /* thread-safe version */ - struct tm keeptime2; - gmt = (struct tm *)gmtime_r(&t, &keeptime2); - if(!gmt) - return -1; /* illegal date/time */ - t2 = mktime(gmt); -#else - /* It seems that at least the MSVC version of mktime() doesn't work - properly if it gets the 'gmt' pointer passed in (which is a pointer - returned from gmtime() pointing to static memory), so instead we copy - the tm struct to a local struct and pass a pointer to that struct as - input to mktime(). */ - struct tm gmt2; - gmt = gmtime(&t); /* use gmtime_r() if available */ - if(!gmt) - return -1; /* illegal date/time */ - gmt2 = *gmt; - t2 = mktime(&gmt2); -#endif - /* Add the time zone diff (between the given timezone and GMT) and the - diff between the local time zone and GMT. */ - delta = (long)((tzoff!=-1?tzoff:0) + (t - t2)); + /* Add the time zone diff between local time zone and GMT. */ + long delta = (long)(tzoff!=-1?tzoff:0); if((delta>0) && (t + delta < t)) return -1; /* time_t overflow */ |