You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 08:05:34