diff --git a/src/timegm.c b/src/timegm.c index 62b14430..e52fe74a 100644 --- a/src/timegm.c +++ b/src/timegm.c @@ -53,3 +53,36 @@ time_t nghttp2_timegm(struct tm *tm) { return (time_t)t; } + +/* Returns nonzero if the |y| is the leap year. The |y| is the year, + including century (e.g., 2012) */ +static int is_leap_year(int y) { + return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0); +} + +/* The number of days before ith month begins */ +static int daysum[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; + +time_t nghttp2_timegm_without_yday(struct tm *tm) { + int days; + int num_leap_year; + int64_t t; + if (tm->tm_mon > 11) { + return -1; + } + num_leap_year = count_leap_year(tm->tm_year + 1900) - count_leap_year(1970); + days = (tm->tm_year - 70) * 365 + num_leap_year + daysum[tm->tm_mon] + + tm->tm_mday - 1; + if (tm->tm_mon >= 2 && is_leap_year(tm->tm_year + 1900)) { + ++days; + } + t = ((int64_t)days * 24 + tm->tm_hour) * 3600 + tm->tm_min * 60 + tm->tm_sec; + +#if SIZEOF_TIME_T == 4 + if (t < INT32_MIN || t > INT32_MAX) { + return -1; + } +#endif /* SIZEOF_TIME_T == 4 */ + + return t; +} diff --git a/src/timegm.h b/src/timegm.h index 4168fdd1..4383fda1 100644 --- a/src/timegm.h +++ b/src/timegm.h @@ -39,6 +39,11 @@ extern "C" { time_t nghttp2_timegm(struct tm *tm); +/* Just like nghttp2_timegm, but without using tm->tm_yday. This is + useful if we use tm from strptime, since some platforms do not + calculate tm_yday with that call. */ +time_t nghttp2_timegm_without_yday(struct tm *tm); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/util.cc b/src/util.cc index 191bd13f..9586ab77 100644 --- a/src/util.cc +++ b/src/util.cc @@ -354,7 +354,7 @@ time_t parse_http_date(const std::string &s) { if (r == 0) { return 0; } - return nghttp2_timegm(&tm); + return nghttp2_timegm_without_yday(&tm); } namespace {