diff --git a/src/util.cc b/src/util.cc index b40fd40c..635439fb 100644 --- a/src/util.cc +++ b/src/util.cc @@ -167,7 +167,7 @@ std::string quote_string(const std::string& target) namespace { template -Iterator cpydig(Iterator d, int n, size_t len) +Iterator cpydig(Iterator d, uint32_t n, size_t len) { auto p = d + len - 1; @@ -223,6 +223,100 @@ std::string http_date(time_t t) return res; } +std::string common_log_date(time_t t) +{ + struct tm tms; + + if(localtime_r(&t, &tms) == nullptr) { + return ""; + } + + // Format data like this: + // 03/Jul/2014:00:19:38 +0900 + std::string res; + res.resize(26); + + auto p = std::begin(res); + + p = cpydig(p, tms.tm_mday, 2); + *p++ = '/'; + auto s = MONTH[tms.tm_mon]; + p = std::copy(s, s + 3, p); + *p++ = '/'; + p = cpydig(p, tms.tm_year + 1900, 4); + *p++ = ':'; + p = cpydig(p, tms.tm_hour, 2); + *p++ = ':'; + p = cpydig(p, tms.tm_min, 2); + *p++ = ':'; + p = cpydig(p, tms.tm_sec, 2); + *p++ = ' '; + + auto gmtoff = tms.tm_gmtoff; + if(gmtoff >= 0) { + *p++ = '+'; + } else { + *p++ = '-'; + gmtoff = -gmtoff; + } + + p = cpydig(p, gmtoff / 3600, 2); + p = cpydig(p, (gmtoff % 3600) / 60, 2); + + return res; +} + +std::string iso8601_date(int64_t ms) +{ + time_t sec = ms / 1000; + + tm tms; + if(localtime_r(&sec, &tms) == nullptr) { + return ""; + } + + // Format data like this: + // 2014-11-15T12:58:24.741Z + // 2014-11-15T12:58:24.741+09:00 + std::string res; + res.resize(29); + + auto p = std::begin(res); + + p = cpydig(p, tms.tm_year + 1900, 4); + *p++ = '-'; + p = cpydig(p, tms.tm_mon + 1, 2); + *p++ = '-'; + p = cpydig(p, tms.tm_mday, 2); + *p++ = 'T'; + p = cpydig(p, tms.tm_hour, 2); + *p++ = ':'; + p = cpydig(p, tms.tm_min, 2); + *p++ = ':'; + p = cpydig(p, tms.tm_sec, 2); + *p++ = '.'; + p = cpydig(p, ms % 1000, 3); + + auto gmtoff = tms.tm_gmtoff; + if(gmtoff == 0) { + *p++ = 'Z'; + } else { + if(gmtoff > 0) { + *p++ = '+'; + } else { + *p++ = '-'; + gmtoff = -gmtoff; + } + p = cpydig(p, gmtoff / 3600, 2); + *p++ = ':'; + p = cpydig(p, (gmtoff % 3600) / 60, 2); + } + + res.resize(p - std::begin(res)); + + return res; +} + time_t parse_http_date(const std::string& s) { tm tm; diff --git a/src/util.h b/src/util.h index 94f51f94..f0ddced0 100644 --- a/src/util.h +++ b/src/util.h @@ -212,6 +212,14 @@ std::string format_hex(const unsigned char *s, size_t len); std::string http_date(time_t t); +// Returns given time |t| from epoch in Common Log format (e.g., +// 03/Jul/2014:00:19:38 +0900) +std::string common_log_date(time_t t); + +// Returns given millisecond |ms| from epoch in ISO 8601 format (e.g., +// 2014-11-15T12:58:24.741Z) +std::string iso8601_date(int64_t ms); + time_t parse_http_date(const std::string& s); template @@ -489,21 +497,11 @@ std::vector get_default_alpn(); template std::string format_common_log(const T& tp) { - auto t = std::chrono::duration_cast + auto t = std::chrono::duration_cast (tp.time_since_epoch()); - time_t sec = t.count() / 1000; - - tm tms; - if(localtime_r(&sec, &tms) == nullptr) { - return ""; - } - - char buf[32]; - - strftime(buf, sizeof(buf), "%d/%b/%Y:%T %z", &tms); - - return buf; + return common_log_date(t.count()); } + // Returns given time |tp| in ISO 8601 format (e.g., // 2014-11-15T12:58:24.741Z) // Expected type of |tp| is std::chrono::timepoint @@ -512,20 +510,7 @@ std::string format_iso8601(const T& tp) { auto t = std::chrono::duration_cast (tp.time_since_epoch()); - time_t sec = t.count() / 1000; - - tm tms; - if(gmtime_r(&sec, &tms) == nullptr) { - return ""; - } - - char buf[128]; - - auto nwrite = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &tms); - snprintf(&buf[nwrite], sizeof(buf) - nwrite, ".%03ldZ", - static_cast(t.count() % 1000)); - - return buf; + return iso8601_date(t.count()); } // Return the system precision of the template parameter |Clock| as