如何实现std::chrono::zoned_time的序列化与反序列化?
实现
std::chrono::zoned_seconds的序列化与反序列化 问题背景
std::chrono::zoned_time 并非POD类型(因为它不属于trivial类型),无法直接以原始数据序列的形式读写到文件。它内部包含一个std::chrono::time_point成员,以及一个指向std::chrono::time_zone对象的指针成员。
问题核心在于指针成员无法直接序列化/反序列化,但我们需要同时保存并恢复zoned_time对象的时区信息(而非仅存储时间点)。可行思路是通过std::chrono::time_zone::name获取时区名称,将其字符串形式与时间点的秒数存储到文件,再反向重建对象。
完整代码实现
#include <chrono> #include <fstream> #include <string> #include <stdexcept> // 序列化zoned_seconds std::ofstream& operator<<(std::ofstream& ofs, const std::chrono::zoned_seconds& time) { // 1. 写入时区名称的长度,避免读取时字符串截断 const auto& zone_name = time.get_time_zone()->name(); const std::size_t name_len = zone_name.size(); ofs.write(reinterpret_cast<const char*>(&name_len), sizeof(name_len)); // 2. 写入时区名称的字符数据 ofs.write(zone_name.data(), name_len); // 3. 写入时间点的秒数(转换为int64_t保证跨平台兼容性) const auto tp = time.get_sys_time(); const std::int64_t seconds = std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch()).count(); ofs.write(reinterpret_cast<const char*>(&seconds), sizeof(seconds)); return ofs; } // 反序列化zoned_seconds std::ifstream& operator>>(std::ifstream& ifs, std::chrono::zoned_seconds& time) { // 1. 读取时区名称长度 std::size_t name_len; ifs.read(reinterpret_cast<char*>(&name_len), sizeof(name_len)); if (!ifs) throw std::runtime_error("Failed to read zone name length"); // 2. 读取时区名称字符串 std::string zone_name(name_len, '\0'); ifs.read(zone_name.data(), name_len); if (!ifs) throw std::runtime_error("Failed to read zone name"); // 3. 通过名称获取对应的time_zone对象 auto* zone = std::chrono::locate_zone(zone_name); if (!zone) throw std::runtime_error("Invalid time zone name: " + zone_name); // 4. 读取秒数并重建time_point std::int64_t seconds; ifs.read(reinterpret_cast<char*>(&seconds), sizeof(seconds)); if (!ifs) throw std::runtime_error("Failed to read seconds"); std::chrono::sys_seconds tp{std::chrono::seconds{seconds}}; // 5. 赋值给目标zoned_seconds对象 time = std::chrono::zoned_seconds{zone, tp}; return ifs; }
关键细节说明
- 时区名称处理:先写入字符串长度再写入内容,避免读取时因无结束符导致的字符串截断问题,兼容包含特殊字符的时区名称。
- 时间点存储:将系统时间点转换为秒数用
std::int64_t存储,能覆盖chrono库支持的时间范围,且跨平台兼容性更强。 - 错误处理:加入基础异常抛出,方便调试时定位序列化/反序列化环节的问题。
- 环境依赖:需确保程序运行环境的时区数据库可用(如Linux的
/usr/share/zoneinfo、Windows系统时区数据),locate_zone才能正确找到对应时区。
内容的提问来源于stack exchange,提问作者digito_evo
相关产品推荐
相关产品推荐

