使用std::chrono::from_stream解析"DD/MM/YYYY at hh:mm:ss"等时间格式
问题根因与修复方案
1. 绝对时间(带日期)解析失败的原因
你使用duration类型接收包含年/月/日的解析结果是错误的:std::chrono::duration是时间间隔的抽象,本身不携带日期锚点,对应的from_stream重载根本不支持%d、%m、%Y这类日期格式符,因此解析直接失败,返回的dur是调试模式下未初始化的脏值,或是Release模式下的默认0值。
解析带日期的绝对时间应该使用std::chrono::sys_time<Duration>(system_clock时间点的别名),它本身以1970-01-01为基准存储时间,完全支持日期类格式符的解析。
2. 时间间隔解析值正确但误报失败的原因
你的解析结果判断逻辑错误:ss.good()要求流的eofbit、failbit、badbit全部为0,判断条件过于严格。from_stream只要完整解析完所有格式符内容,就算流还没到末尾也不会设置failbit,判断解析是否成功应该用!ss.fail()。你解析5秒间隔时实际已经解析成功,只是被错误的判断逻辑误报了失败。
修复后代码示例
#include <chrono> #include <string> #include <sstream> #include <iostream> using nano = std::chrono::duration<std::uint64_t, std::nano>; using SysNanoTime = std::chrono::sys_time<nano>; // 解析时间间隔 template <typename Duration> Duration ParseDuration(const std::string& str, const std::string& fmt, const Duration& default_val) { Duration dur; std::stringstream ss{ str }; std::chrono::from_stream(ss, fmt.c_str(), dur); if (!ss.fail()) { std::cout << "Duration parse success!" << std::endl; std::cout << dur.count() << std::endl; return dur; } else { std::cout << "Duration parse failed!" << std::endl; return default_val; } } // 解析绝对时间点 SysNanoTime ParseTimePoint(const std::string& str, const std::string& fmt, const SysNanoTime& default_val) { SysNanoTime tp; std::stringstream ss{ str }; std::chrono::from_stream(ss, fmt.c_str(), tp); if (!ss.fail()) { std::cout << "Time point parse success!" << std::endl; std::cout << tp.time_since_epoch().count() << std::endl; return tp; } else { std::cout << "Time point parse failed!" << std::endl; return default_val; } } int main() { std::string str1("08/03/2021 at 09:37:25"), str2("00:00:05"); std::string fmt1("%d/%m/%Y at %H:%M:%S"), fmt2("%H:%M:%S"); auto test1 = ParseTimePoint(str1, fmt1, SysNanoTime{}); auto test2 = ParseDuration<nano>(str2, fmt2, nano::zero()); // Windows文件时间转换示例:1601-01-01到1970-01-01的间隔是11644473600秒 constexpr nano win_file_time_epoch_offset = nano(11644473600LL * 1000000000ULL); uint64_t win_file_time = (test1.time_since_epoch() + win_file_time_epoch_offset).count() / 100; std::cout << "Windows file time: " << win_file_time << std::endl; }
额外说明
你选择纳秒作为时间单位完全适配Windows文件时间的处理需求:Windows文件时间以1601-01-01为基准、以100纳秒为单位,只需要计算解析得到的system_clock时间点和1601-01-01基准的差值,再除以100即可得到标准Windows文件时间值。
内容的提问来源于stack exchange,提问作者Ben Andrews
相关产品推荐
相关产品推荐

