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

如何基于ISO 8601日期获取固定的std::chrono time_point?

实现支持ISO 8601格式的std::chrono datetime函数

我们可以基于C++标准库的<chrono>组件,实现一个符合需求的datetime函数,直接从ISO 8601日期字符串生成system_clock::time_point。

核心需求回顾

  • 输入必须是严格ISO 8601格式的日期字符串(如"2023-12-25"),不支持其他格式
  • 无效日期可选择抛出异常,或返回system_clock的epoch时间点(1970-01-01 00:00:00 UTC)
  • 可选支持用XXXX替换为当前年份(如"XXXX-01-01"表示当年1月1日)

基础实现(C++20+)

利用C++20新增的std::chrono::parse和日期类型,可以快速实现核心功能:

#include <chrono>
#include <stdexcept>
#include <string>
#include <sstream>

namespace std::chrono {

system_clock::time_point datetime(std::string_view date_str, bool throw_on_invalid = true)
{
    // 仅支持YYYY-MM-DD格式
    year_month_day ymd;
    try {
        std::istringstream ss(std::string(date_str));
        ss >> parse("%F", ymd);
    } catch (...) {
        if (throw_on_invalid) {
            throw std::invalid_argument("Invalid ISO 8601 date string");
        }
        return system_clock::time_point{};
    }

    // 验证日期有效性(比如2月30日这类无效日期)
    if (!ymd.ok()) {
        if (throw_on_invalid) {
            throw std::invalid_argument("Invalid calendar date");
        }
        return system_clock::time_point{};
    }

    // 转换为system_clock的time_point
    return sys_days{ymd};
}

} // namespace std::chrono

使用示例

#include <iostream>

int main()
{
    try {
        auto xmas = std::chrono::datetime("2023-12-25");
        // 输出时间点对应的时间戳
        std::cout << std::chrono::system_clock::to_time_t(xmas) << '\n';
    } catch (const std::exception& e) {
        std::cerr << e.what() << '\n';
    }

    // 无效日期示例,返回epoch
    auto invalid_date = std::chrono::datetime("2023-02-30", false);
    std::cout << std::chrono::system_clock::to_time_t(invalid_date) << '\n'; // 输出0
}

可选功能:支持XXXX替换为当前年份

只需在解析前对输入字符串做替换处理,获取当前年份后替换XXXX:

#include <chrono>
#include <stdexcept>
#include <string>
#include <sstream>
#include <algorithm>

namespace std::chrono {

namespace detail {
std::string replace_current_year(std::string_view date_str)
{
    std::string str(date_str);
    size_t pos = str.find("XXXX");
    if (pos == std::string::npos) {
        return str;
    }

    // 获取当前UTC年份
    auto now = system_clock::now();
    auto ymd = year_month_day{floor<days>(now)};
    std::string year_str = std::to_string(static_cast<int>(ymd.year()));
    
    str.replace(pos, 4, year_str);
    return str;
}
} // namespace detail

system_clock::time_point datetime(std::string_view date_str, bool throw_on_invalid = true)
{
    std::string processed_str = detail::replace_current_year(date_str);
    
    year_month_day ymd;
    try {
        std::istringstream ss(processed_str);
        ss >> parse("%F", ymd);
    } catch (...) {
        if (throw_on_invalid) {
            throw std::invalid_argument("Invalid ISO 8601 date string");
        }
        return system_clock::time_point{};
    }

    if (!ymd.ok()) {
        if (throw_on_invalid) {
            throw std::invalid_argument("Invalid calendar date");
        }
        return system_clock::time_point{};
    }

    return sys_days{ymd};
}

} // namespace std::chrono

可选功能使用示例

// 获取当年1月1日的时间点
auto year_start = std::chrono::datetime("XXXX-01-01");

注意事项

  1. 上述代码依赖C20标准,若需兼容C17及更早版本,需手动解析日期字符串并计算天数差
  2. 所有日期解析均基于UTC时区,若需本地时区支持,可替换为local_days并结合时区库
  3. 严格限制输入格式为YYYY-MM-DD,任何不符合该格式的字符串都会被判定为无效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 20:23:08