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

如何用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 11:24:08