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

如何用std::chrono::parse实现std::chrono::zoned_seconds的流读写?

如何高效实现std::chrono::zoned_seconds的序列化与反序列化?

我尝试将std::chrono::zoned_seconds对象以文本形式写入文件,之后读取该文本并重建新的std::chrono::zoned_seconds对象,但现有代码无法得到正确结果。

错误代码如下:

#include <fstream>
#include <print>
#include <chrono>
#include <format>
#include <string>
#include <sstream>


int main()
{
    {
        std::ofstream file("data.txt");
        if (!file) {
            std::println( "无法打开文件。" );
            return 1;
        }

        auto now = std::chrono::system_clock::now();
        const std::chrono::zoned_seconds zs { "America/New_York", std::chrono::time_point_cast<std::chrono::seconds>( now ) };

        std::format_to(std::ostreambuf_iterator<char>(file), "{:%F %T %Z}", zs);
        std::println( "{:%F %T %Z}", zs ); // 输出正确时间
    }

    {
        std::ifstream file("data.txt");
        if (!file) {
            std::println( "无法打开文件。" );
            return 1;
        }

        std::string str;
        std::getline(file, str);
        std::istringstream iss { str };

        std::chrono::sys_seconds tp;
        std::string zone_name;
        iss >> std::chrono::parse("%F %T %Z", tp, zone_name);
        std::chrono::zoned_seconds zs { zone_name, tp };
        std::println( "{:%F %T %Z}", zs );  // 输出错误时间!!
    }
}

运行后输出不匹配:

2024-03-01 13:35:20 EST
2024-03-01 08:35:20 EST

问题原因

你的代码核心问题是序列化与反序列化的逻辑不匹配:

  • 写入时,std::format("{:%F %T %Z}", zs)输出的是纽约时区的本地时间(比如示例中的13:35:20 EST);
  • 读取时,你直接把这个本地时间解析成了UTC系统时间点(sys_seconds),相当于把EST时区的13:35当成了UTC时间——而EST比UTC晚5小时,所以转成纽约时区时就变成了08:35,导致结果错误。

正确实现方案

方案一:存储UTC时间点+完整时区名称(推荐)

这种方式完全避免时区缩写的歧义(比如EST可能对应多个时区),逻辑简单可靠,不受夏令时变化影响:

#include <fstream>
#include <print>
#include <chrono>
#include <format>
#include <string>
#include <sstream>

int main()
{
    {
        std::ofstream file("data.txt");
        if (!file) {
            std::println("无法打开文件。");
            return 1;
        }

        auto now = std::chrono::system_clock::now();
        const std::chrono::zoned_seconds zs { "America/New_York", std::chrono::time_point_cast<std::chrono::seconds>(now) };
        
        // 存储UTC时间点 + 完整时区名称
        std::format_to(std::ostreambuf_iterator<char>(file), "{} {}", zs.get_sys_time(), zs.get_time_zone()->name());
        std::println("原始输出:{:%F %T %Z}", zs);
    }

    {
        std::ifstream file("data.txt");
        if (!file) {
            std::println("无法打开文件。");
            return 1;
        }

        std::string str;
        std::getline(file, str);
        std::istringstream iss { str };

        std::chrono::sys_seconds tp;
        std::string zone_name;
        iss >> tp >> zone_name;
        
        std::chrono::zoned_seconds zs { zone_name, tp };
        std::println("读取后输出:{:%F %T %Z}", zs);
    }
}

方案二:保留本地时间格式(需注意歧义)

如果必须保留%F %T %Z的人类可读格式,解析时要先把字符串解析成对应时区的本地时间点,再构建zoned_seconds:

#include <fstream>
#include <print>
#include <chrono>
#include <format>
#include <string>
#include <sstream>

int main()
{
    {
        std::ofstream file("data.txt");
        if (!file) {
            std::println("无法打开文件。");
            return 1;
        }

        auto now = std::chrono::system_clock::now();
        const std::chrono::zoned_seconds zs { "America/New_York", std::chrono::time_point_cast<std::chrono::seconds>(now) };
        
        std::format_to(std::ostreambuf_iterator<char>(file), "{:%F %T %Z}", zs);
        std::println("原始输出:{:%F %T %Z}", zs);
    }

    {
        std::ifstream file("data.txt");
        if (!file) {
            std::println("无法打开文件。");
            return 1;
        }

        std::string str;
        std::getline(file, str);
        
        // 先解析成本地时间点
        std::chrono::local_seconds local_tp;
        std::string zone_abbr;
        std::istringstream iss(str);
        iss >> std::chrono::parse("%F %T %Z", local_tp, zone_abbr);
        
        // 注意:时区缩写有歧义,建议用完整时区名称而非缩写
        std::chrono::zoned_seconds zs { "America/New_York", local_tp };
        std::println("读取后输出:{:%F %T %Z}", zs);
    }
}

方案对比

  • 方案一:优先选择,UTC时间点全局唯一,完整时区名称无歧义,序列化/反序列化逻辑稳定,不会受时区规则变化影响。
  • 方案二:适合需要人类可读格式的场景,但需注意时区缩写的歧义问题(比如CST可代表中国标准时间、美国中部标准时间等),若必须使用,建议同时存储完整时区名称而非仅缩写。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 02:47:49