Implement faster formatting for format_iso8601 and format_common_log

This commit is contained in:
Tatsuhiro Tsujikawa 2014-11-23 16:40:38 +09:00
parent df401f57a2
commit de2a855572
2 changed files with 107 additions and 28 deletions

View File

@ -167,7 +167,7 @@ std::string quote_string(const std::string& target)
namespace {
template<typename Iterator>
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;

View File

@ -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<typename InputIterator1, typename InputIterator2>
@ -489,21 +497,11 @@ std::vector<unsigned char> get_default_alpn();
template <typename T>
std::string format_common_log(const T& tp)
{
auto t = std::chrono::duration_cast<std::chrono::milliseconds>
auto t = std::chrono::duration_cast<std::chrono::seconds>
(tp.time_since_epoch());
time_t sec = t.count() / 1000;
tm tms;
if(localtime_r(&sec, &tms) == nullptr) {
return "";
return common_log_date(t.count());
}
char buf[32];
strftime(buf, sizeof(buf), "%d/%b/%Y:%T %z", &tms);
return buf;
}
// 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<std::chrono::milliseconds>
(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<int>(t.count() % 1000));
return buf;
return iso8601_date(t.count());
}
// Return the system precision of the template parameter |Clock| as