C++如何解析HH:MM:SS.微秒格式时间戳字符串以便比较排序
解决方案
因为你的时间戳仅包含单日的时分秒和微秒,没有日期时区信息,直接用std::chrono::microseconds存储从当天0点开始的总微秒数即可,该类型原生支持比较、排序运算,完全满足需求,比std::chrono::time_point更轻量。
实现要点
- 用C++17新增的
std::from_chars做字符串到数值的转换,性能更高、无额外内存分配,也不存在locale兼容问题 - 对输入格式和数值范围做校验,避免非法输入导致异常结果
- 解析结果直接支持所有比较操作和标准库排序算法
完整可运行代码
#include <iostream> #include <vector> #include <string> #include <chrono> #include <algorithm> #include <charconv> #include <stdexcept> // 输入格式要求:HH:MM:SS.ffffff,时分秒固定2位,微秒固定6位 std::chrono::microseconds parse_time(const std::string& ts_str) { // 若输入没有严格补前导零,可删除该长度校验,改用find查找冒号、小数点位置拆分字段 if (ts_str.size() != 15) { throw std::invalid_argument("Invalid timestamp length"); } int hh, mm, ss, us; // 解析小时 auto res = std::from_chars(ts_str.data(), ts_str.data() + 2, hh); if (res.ec != std::errc() || res.ptr != ts_str.data() + 2 || ts_str[2] != ':') { throw std::invalid_argument("Invalid hour field"); } // 解析分钟 res = std::from_chars(ts_str.data() + 3, ts_str.data() + 5, mm); if (res.ec != std::errc() || res.ptr != ts_str.data() + 5 || ts_str[5] != ':') { throw std::invalid_argument("Invalid minute field"); } // 解析秒 res = std::from_chars(ts_str.data() + 6, ts_str.data() + 8, ss); if (res.ec != std::errc() || res.ptr != ts_str.data() + 8 || ts_str[8] != '.') { throw std::invalid_argument("Invalid second field"); } // 解析微秒 res = std::from_chars(ts_str.data() + 9, ts_str.data() + 15, us); if (res.ec != std::errc() || res.ptr != ts_str.data() + 15) { throw std::invalid_argument("Invalid microsecond field"); } // 数值范围校验 if (hh < 0 || hh > 23 || mm < 0 || mm > 59 || ss < 0 || ss > 59 || us < 0 || us > 999999) { throw std::invalid_argument("Timestamp value out of range"); } using namespace std::chrono_literals; return hh * 3600000000us + mm * 60000000us + ss * 1000000us + std::chrono::microseconds(us); } int main() { std::vector<std::string> raw_ts = { "12:27:37.740002", "19:37:17.314002", "20:00:07.140902", "20:00:07.000000" }; // 批量解析 std::vector<std::chrono::microseconds> parsed_ts; parsed_ts.reserve(raw_ts.size()); for (const auto& s : raw_ts) { parsed_ts.push_back(parse_time(s)); } // 示例:时间比较 auto t_a = parse_time("20:00:07.140902"); auto t_b = parse_time("20:00:07.000000"); if (t_a > t_b) { std::cout << "20:00:07.140902 晚于 20:00:07.000000" << std::endl; } // 示例:排序 std::sort(parsed_ts.begin(), parsed_ts.end()); return 0; }
可选扩展
如果你确实需要使用std::chrono::time_point类型存储,只需要将解析得到的微秒数和当天0点的time_point相加即可,逻辑如下:
std::chrono::sys_time<std::chrono::microseconds> to_time_point(std::chrono::microseconds day_offset) { // 取当天0点的时间戳,根据你实际的日期需求调整即可 auto today = std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now()); return today + day_offset; }
内容的提问来源于stack exchange,提问作者psb
相关产品推荐
相关产品推荐

