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

如何在libfmt 9.1中按UTC格式化chrono::time_point<system_clock>

问题:在libfmt 9.1中以UTC格式化chrono::system_clock时间点

我正在使用libfmt 9.1版本,有一个内部以UTC存储的chrono::time_point<chrono::system_clock>时间点,希望输出其时间和日期时不转换为本地时区。

这是libfmt 10版本的默认行为,但在9.1版本中,libfmt会将时间点转换为本地时区输出。示例代码如下:

char e[] = "TZ=:Pacific/Auckland";
putenv(e);
tzset();
auto tp = std::chrono::sys_seconds::min();
auto tpStr = fmt::format( "{:%F %T %Z}", tp);
std::cout << tpStr << "\n";

使用libfmt v9.1编译时输出1970-01-01 12:00:00 NZST,使用v10编译时输出1970-01-01 00:00:00 GMT。

我无法轻易升级到libfmt v10,担心变更会破坏项目其他部分。我使用C++17,无法使用std::format。请问是否可以让libfmt 9.1按UTC格式化chrono::time_point<chrono::system_clock>?

libfmt文档未提及时区相关内容,std::format文档规定了L前缀,可从默认的C区域设置输出(即libfmt v10的默认行为)切换为本地时区输出。想知道libfmt 9.1是否有反向修饰符?


解决方案

方法1:临时切换时区环境变量

通过临时将进程时区设置为UTC,完成格式化后恢复原时区,实现UTC输出。此方法简单直接,但线程不安全,多线程场景需加锁。

示例代码:

#include <fmt/chrono.h>
#include <iostream>
#include <cstdlib>
#include <cstdio>

int main() {
    // 保存原时区环境变量
    const char* original_tz = getenv("TZ");
    
    // 临时设置时区为UTC
    char utc_tz[] = "TZ=UTC";
    putenv(utc_tz);
    tzset();
    
    // 格式化UTC时间点
    auto tp = std::chrono::sys_seconds::min();
    auto tpStr = fmt::format("{:%F %T %Z}", tp);
    std::cout << tpStr << "\n"; // 输出1970-01-01 00:00:00 GMT
    
    // 恢复原时区
    if (original_tz) {
        char restore_tz[256];
        snprintf(restore_tz, sizeof(restore_tz), "TZ=%s", original_tz);
        putenv(restore_tz);
    } else {
        // 原环境无TZ变量则移除
        unsetenv("TZ");
    }
    tzset();
    
    return 0;
}

方法2:自定义格式化器(推荐)

编写自定义的fmt格式化器,直接通过gmtime_r(线程安全)将时间点转换为UTC时间,完全控制格式化逻辑,不受libfmt默认时区行为影响。

示例代码:

#include <fmt/chrono.h>
#include <fmt/format.h>
#include <chrono>
#include <ctime>

// 自定义UTC格式化器
struct utc_time_formatter {
    // 支持自定义格式字符串(可选扩展)
    template <typename ParseContext>
    constexpr auto parse(ParseContext& ctx) {
        // 若需要支持自定义格式,可在此解析ctx.format()中的格式说明符
        return ctx.begin();
    }

    template <typename FormatContext>
    auto format(const std::chrono::system_clock::time_point& tp, FormatContext& ctx) {
        std::time_t t = std::chrono::system_clock::to_time_t(tp);
        std::tm tm{};
        gmtime_r(&t, &tm); // 线程安全的UTC时间转换

        // 按指定格式输出,此处可根据需求调整格式
        return fmt::format_to(ctx.out(), "{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d} GMT",
            tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
            tm.tm_hour, tm.tm_min, tm.tm_sec);
    }
};

// 注册格式化器,让fmt识别system_clock::time_point的UTC格式化
template <> struct fmt::formatter<std::chrono::system_clock::time_point, char> : utc_time_formatter {};

int main() {
    char e[] = "TZ=:Pacific/Auckland";
    putenv(e);
    tzset();
    
    auto tp = std::chrono::sys_seconds::min();
    auto tpStr = fmt::format("{}", tp);
    std::cout << tpStr << "\n"; // 输出1970-01-01 00:00:00 GMT
    
    return 0;
}

如果需要支持自定义格式字符串(如%F %T),可以扩展parse方法解析格式说明符,在format中动态生成输出格式。

方法3:依赖libfmt内部逻辑(不推荐)

libfmt 9.1的chrono格式化内部存在UTC处理逻辑,但未暴露为公共接口。直接调用内部函数会导致代码依赖未公开的实现细节,后续版本升级或维护时容易出问题,仅适合临时应急场景,不建议在生产环境使用。


内容的提问来源于stack exchange,提问作者Lukas Barth

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 04:49:57