如何基于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");
注意事项
- 上述代码依赖C20标准,若需兼容C17及更早版本,需手动解析日期字符串并计算天数差
- 所有日期解析均基于UTC时区,若需本地时区支持,可替换为
local_days并结合时区库 - 严格限制输入格式为
YYYY-MM-DD,任何不符合该格式的字符串都会被判定为无效
内容的提问来源于stack exchange,提问作者Howard Hinnant
相关产品推荐
相关产品推荐

