如何用Howard Hinnant的date库以同一类型解析各类ISO-8601日期时间格式
C++ date库统一解析多类ISO-8601格式的实现方案
完全可以实现用同一类型完成所有支持格式的解析和存储,常用的实现思路有两种:
方案1:自定义统一存储结构体 + 适配解析逻辑
你可以先定义一个包含所有可选日期时间字段的聚合类型,再封装统一的解析入口,内部按格式优先级尝试解析,将结果填充到结构体对应字段中:
#include <chrono> #include <optional> #include <string> #include <sstream> #include "date/date.h" using namespace std::chrono; struct UnifiedDateTime { // 存储所有可能的字段,用optional标记是否存在 std::optional<date::year> year; std::optional<date::month> month; std::optional<date::day> day; std::optional<microseconds> time_of_day; std::optional<sys_time<microseconds>> full_zoned_time; }; // 统一解析函数 bool parse_unified(const std::string& str, UnifiedDateTime& out) { // 每次解析前清空旧结果 out = {}; std::istringstream iss(str); // 优先尝试解析完整带时区的格式 sys_time<microseconds> sys_us; iss >> date::parse("%FT%T%Ez", sys_us); if (!iss.fail()) { out.full_zoned_time = sys_us; auto dp = floor<date::days>(sys_us); date::year_month_day ymd(dp); out.year = ymd.year(); out.month = ymd.month(); out.day = ymd.day(); out.time_of_day = sys_us - dp; return true; } // 尝试解析完整日期 iss.clear(); iss.seekg(0); date::year_month_day ymd; iss >> date::parse("%F", ymd); if (!iss.fail()) { out.year = ymd.year(); out.month = ymd.month(); out.day = ymd.day(); return true; } // 尝试解析年月 iss.clear(); iss.seekg(0); date::year_month ym; iss >> date::parse("%Y-%m", ym); if (!iss.fail()) { out.year = ym.year(); out.month = ym.month(); return true; } // 尝试解析年份 iss.clear(); iss.seekg(0); date::year y; iss >> date::parse("%Y", y); if (!iss.fail()) { out.year = y; return true; } // 尝试解析纯时间 iss.clear(); iss.seekg(0); microseconds us; iss >> date::parse("%T", us); if (!iss.fail()) { out.time_of_day = us; return true; } return false; }
使用时不需要再切换变量类型,直接调用即可:
UnifiedDateTime dt; assert(parse_unified("2012-03-04T05:06:07.123456+07:00", dt)); assert(parse_unified("2012-03", dt)); assert(parse_unified("05:06:07.123456", dt));
方案2:用std::variant包装原生类型
如果不需要拆分字段存储,只需要统一存储解析结果,可以直接用variant包装所有需要的date库原生类型,封装解析逻辑自动匹配对应类型:
#include <variant> using DateTimeVariant = std::variant< sys_time<microseconds>, // 完整带时区时间 date::year_month_day, // 完整日期 date::year_month, // 年月 date::year, // 年份 microseconds // 纯时间 >; bool parse_variant(const std::string& str, DateTimeVariant& out) { std::istringstream iss(str); sys_time<microseconds> sys_us; iss >> date::parse("%FT%T%Ez", sys_us); if (!iss.fail()) { out = sys_us; return true; } iss.clear(); iss.seekg(0); date::year_month_day ymd; iss >> date::parse("%F", ymd); if (!iss.fail()) { out = ymd; return true; } iss.clear(); iss.seekg(0); date::year_month ym; iss >> date::parse("%Y-%m", ym); if (!iss.fail()) { out = ym; return true; } iss.clear(); iss.seekg(0); date::year y; iss >> date::parse("%Y", y); if (!iss.fail()) { out = y; return true; } iss.clear(); iss.seekg(0); microseconds us; iss >> date::parse("%T", us); if (!iss.fail()) { out = us; return true; } return false; }
后续可以通过std::visit访问不同类型的解析结果做分支处理。
两种方案都可以完全满足你不用切换解析变量类型的需求,如果后续需要对解析结果做统一运算处理优先选方案1,如果只需要存储、判断类型后分支处理优先选方案2。
内容的提问来源于stack exchange,提问作者user17360045
相关产品推荐
相关产品推荐

