高效生成 UTC 时间戳
Efficiently generating a UTC timestamp
我需要经常以字符串格式生成UTC时间戳(每秒几次),而且我的代码效率低下。 有没有比我正在使用的方法更快的方法?可以假设程序不会跨日边界运行。
void GenerateUTCTimestamp(std::string& out)
{
auto now = std::chrono::system_clock::now();
time_t tnow = std::chrono::system_clock::to_time_t(now);
tm* utc = gmtime(&tnow);
std::stringstream ss;
ss << std::setfill('0');
ss << std::setw(4) << utc->tm_year + 1900; // Year
ss << std::setw(2) << utc->tm_mon + 1; // Month
ss << std::setw(2) << utc->tm_mday; // Day
ss << '-';
ss << std::setw(2) << utc->tm_hour << ':'; // Hours
ss << std::setw(2) << utc->tm_min << ':'; // Minutes
ss << std::setw(2) << utc->tm_sec; // Seconds
out = ss.str();
}
您将很难找到比这更快的代码:
#include <chrono>
#include <string>
void
stamp(char* s, int i)
{
do
{
*s-- = char(i % 10) + '0';
i /= 10;
} while (i > 0);
}
void GenerateUTCTimestamp(std::string& out)
{
using namespace std;
using namespace std::chrono;
using days = duration<int, ratio<86400>>;
auto now = time_point_cast<seconds>(system_clock::now());
auto today = time_point_cast<days>(now);
auto s = now - today;
// y-m-d
auto z = today.time_since_epoch().count() + 719468;
const auto era = 5;
const auto doe = z - era * 146097;
const auto yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365;
const auto y = yoe + era * 400;
const auto doy = doe - (365*yoe + yoe/4 - yoe/100);
auto m = (5*doy + 2)/153;
const auto d = doy - (153*m+2)/5 + 1;
m = m + (m < 10 ? 3 : -9);
// h:M:s
const auto h = duration_cast<hours>(s);
s -= h;
const auto M = duration_cast<minutes>(s);
s -= M;
// format yyyymmdd-hh:MM:ss
out = "00000000-00:00:00";
stamp(&out[3], y);
stamp(&out[5], m);
stamp(&out[7], d);
stamp(&out[10], h.count());
stamp(&out[13], M.count());
stamp(&out[16], s.count());
}
此代码使用从这里
civil_from_days
的公共域算法:http://howardhinnant.github.io/date_algorithms.html#civil_from_days
您可以在其中找到该算法的深入解释。
代码中的分支数最小化,代码大小本身最小化。
完全避免使用通用(和方便)流,而是选择基本的整数到字符算法,该算法不处理本地化、特征、宽字符、自定义宽度或对齐方式甚至负值。
除了第一次调用外,通过重用和格式化直接到
out
中完全避免了内存分配。此代码的有效期有限:2000-03-01 到 2400-02-29。 如果需要使此代码对此范围之外的时间点有效,请将
era
的计算更改为:const auto era = (z >= 0 ? z : z - 146096) / 146097;
我把这段代码放在一个包含 1000 次调用(具有相同string
)的循环中,对其进行计时,并平均所有调用的时间。
在我的机器(macOS,clang,libc ++,-O3)上,原始代码大约需要3.9μs,优化代码大约需要150ns(快约25倍)。
然后,为了咧嘴一笑,我使用 Howard Hinnant 的日期库实现了GenerateUTCTimestamp
,看看它在计时测试中的表现如何。 它显然赢得了易用性测试(恕我直言):
#include "date.h"
void GenerateUTCTimestamp(std::string& out)
{
using namespace date;
using namespace std::chrono;
out = format("%Y%m%d-%T", time_point_cast<seconds>(system_clock::now()));
}
它的时钟频率为2.5μs,比线程不安全的C API快50%,但比优化的代码慢得多。 通用工具的灵活性会降低性能。
日期库使用与优化工具相同的历法算法(使用广义era
除外),但格式为与原始代码一样的stringstream
。 当然,它还必须解析格式化字符串。
- C++:floor unix时间戳到UTC月份
- 如何在c++中录制具有精确帧时间戳的视频
- 在两台机器之间进行时间戳的最佳c++chrono函数是什么
- Google protobuf 时间戳未声明标识符,在 Windows 上具有C++
- 在多个时间戳处执行函数
- 以天C++为单位的两个时间戳之间的差异
- 获取 QInputEvent 在 Qt 4.8 中被放入 QEventLoop 队列时的时间戳
- 在 C++ 中为文件名添加时间戳
- 如何从远程 SFTP 服务器获取 HH-MM-SS 时间戳格式的文件列表
- 如何将消息时间戳写入日志文件?
- 将时间戳打印到流的最简单方法
- 读取悖论时间戳字段
- 将具有 DST 的时间字符串转换为 UTC 时间戳
- 使用 std::chrono / date::gps_clock 将双 GPS 时间戳转换为 UTC/tai
- 高效生成 UTC 时间戳
- 如何将 UTC 时间戳转换为本地时间,即整点后的几秒钟
- 如何从 UTC 时间戳的组件(Y,M,D,H,M,S,MS)创建system_clock::time_point
- C++提升以 UTC 格式获取 unix 时间戳
- 从GMT/UTC字符串到UNIX时间戳的Qt5(C++)转换
- 使用时间位置将日期时间从/转换为UTC时间戳