如何用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
相关产品推荐
相关产品推荐

