C++实现纳秒级Unix时间与指定时区可读时间互转
纳秒级Unix时间与时区可读字符串的双向转换(C17/C20)
需求说明
实现自epoch起的纳秒级Unix时间(uint64_t类型的纳秒数)与指定时区(TZ字符串)的可读字符串双向转换,全程保留纳秒精度。示例代码及期望输出如下:
示例代码:
uint64_t unix_time = 1669058870115719258; std::string datetime = convert_unix_to_datetime(unix_time, "America/Detroit"); std::cout << datetime << "\n"; std::cout << convert_datetime_to_unix_time(datetime, "America/Detroit") << "\n";
期望输出:
2021-11-21 14:27:50.115719258 1669058870115719258
C++20 解决方案(推荐)
C++20的<chrono>库原生支持时区、时间格式化与解析,无需第三方依赖,代码简洁且符合标准。
完整实现代码
#include <chrono> #include <format> #include <string> #include <sstream> #include <stdexcept> #include <iomanip> using namespace std::chrono; // 纳秒级Unix时间转指定时区的可读字符串 std::string convert_unix_to_datetime(uint64_t unix_nanos, const std::string& tz_str) { // 将纳秒数转换为系统时钟时间点 auto sys_tp = system_clock::time_point( duration_cast<system_clock::duration>(nanoseconds(unix_nanos)) ); // 绑定目标时区 zoned_time zt{tz_str, sys_tp}; // 格式化日期时间部分,补零输出9位纳秒 std::ostringstream oss; oss << format("{:%Y-%m-%d %H:%M:%S}", zt) << "." << std::setw(9) << std::setfill('0') << (zt.get_local_time().time_since_epoch().count() % 1'000'000'000); return oss.str(); } // 可读字符串转纳秒级Unix时间(需指定时区) uint64_t convert_datetime_to_unix_time(const std::string& datetime_str, const std::string& tz_str) { // 格式合法性检查 if (datetime_str.size() < 20 || datetime_str[19] != '.') { throw std::invalid_argument("Invalid format: missing nanosecond separator"); } std::string nano_part = datetime_str.substr(20); if (nano_part.size() != 9) { throw std::invalid_argument("Invalid nanoseconds: must be 9 digits"); } // 解析日期时间部分为本地时间点 local_time<nanoseconds> local_tp; std::istringstream iss(datetime_str.substr(0, 19)); if (!(iss >> parse("%Y-%m-%d %H:%M:%S", local_tp))) { throw std::invalid_argument("Invalid datetime format"); } // 转换为系统时钟时间点并计算总纳秒数 zoned_time zt{tz_str, local_tp}; auto sys_tp = zt.get_sys_time(); uint64_t total_nanos = duration_cast<nanoseconds>(sys_tp.time_since_epoch()).count(); total_nanos += std::stoull(nano_part); return total_nanos; }
关键说明
zoned_time自动处理时区的夏令时、偏移变更等规则,无需手动计算std::format和std::chrono::parse原生支持时间格式的标准化处理- 纳秒部分单独补零,确保输出固定为9位数字,符合精度要求
C++17 解决方案(依赖第三方库)
C17标准库无原生时区支持,推荐使用Howard Hinnant的date库(纯头文件库,无需编译),该库是C20 chrono时区模块的原型,API高度兼容。
前置准备
获取date库的头文件(开源渠道可获取),包含date/date.h和date/tz.h即可使用。
完整实现代码
#include <date/date.h> #include <date/tz.h> #include <string> #include <sstream> #include <stdexcept> #include <iomanip> using namespace date; using namespace std::chrono; // 纳秒级Unix时间转指定时区的可读字符串 std::string convert_unix_to_datetime(uint64_t unix_nanos, const std::string& tz_str) { auto sys_tp = system_clock::time_point( duration_cast<system_clock::duration>(nanoseconds(unix_nanos)) ); // 获取目标时区对象 const auto& tz = locate_zone(tz_str); zoned_time<nanoseconds> zt{tz, sys_tp}; std::ostringstream oss; oss << format("%Y-%m-%d %H:%M:%S", zt) << "." << std::setw(9) << std::setfill('0') << (zt.get_local_time().time_since_epoch().count() % 1'000'000'000); return oss.str(); } // 可读字符串转纳秒级Unix时间(需指定时区) uint64_t convert_datetime_to_unix_time(const std::string& datetime_str, const std::string& tz_str) { if (datetime_str.size() < 20 || datetime_str[19] != '.') { throw std::invalid_argument("Invalid format: missing nanosecond separator"); } std::string nano_part = datetime_str.substr(20); if (nano_part.size() != 9) { throw std::invalid_argument("Invalid nanoseconds: must be 9 digits"); } local_time<nanoseconds> local_tp; std::istringstream iss(datetime_str.substr(0, 19)); if (!(iss >> parse("%Y-%m-%d %H:%M:%S", local_tp))) { throw std::invalid_argument("Invalid datetime format"); } const auto& tz = locate_zone(tz_str); auto sys_tp = tz.to_sys(local_tp); uint64_t total_nanos = duration_cast<nanoseconds>(sys_tp.time_since_epoch()).count(); total_nanos += std::stoull(nano_part); return total_nanos; }
关键说明
- date库的API与C20 chrono几乎一致,后续迁移到C20仅需替换头文件
locate_zone支持标准IANA时区字符串(如"America/Detroit"),自动处理时区规则
内容的提问来源于stack exchange,提问作者rampatowl
相关产品推荐
相关产品推荐

