解析HTTP日期格式,尤其是严格按照RFC 1123规范的那种——比如“Sun, 06 Nov 1994 08:49:37 GMT”——看起来简单,实际上在C++里踩坑的人不在少数。最常见的误区就是直接上std::get_time,结果发现怎么也解析不了。这不是你代码写错了,而是底层strptime对逗号的兼容性问题。

什么是RFC 1123日期格式,为什么不能直接用std::get_time?
RFC 1123格式要求非常严格:逗号必须紧跟星期缩写,后面有一个空格,时区字段必须是全大写的“GMT”,星期和月份缩写必须是固定的小写英文(例如sun、jan)。C++标准库的std::get_time在libstdc++和MSVC等常见实现中,一旦遇到逗号就直接罢工——它不支持%a之后紧跟逗号的格式,底层strptime根本过不了这一关。所以别自责,是工具本身的限制,不是你写错了格式字符串。
用std::regex做初步格式校验是否够用?
正则表达式用来快速筛掉明显不合法的字符串是OK的,但关键问题是它验证不了语义,比如2月30号、时区是不是真的GMT。推荐用下面这个模式做前置过滤:
^([A-Za-z]{3}), ([0-9]{2}) ([A-Za-z]{3}) ([0-9]{4}) ([0-9]{2}):([0-9]{2}):([0-9]{2}) GMT$
匹配之后一定要记得查表比对星期和月份缩写,因为[A-Za-z]{3}会放过像“Xxx”这种非法缩写,而RFC要求必须是全小写的标准缩写(sun/mon/jan/feb等)。正则只适合做快速淘汰,最终还是要靠后续的逻辑验证。
手动解析+查表验证才是可靠做法
最可靠的做法是彻底放弃std::get_time,自己动手按字符位置拆解字段,再逐一校验。步骤其实很清晰:
- 检查第0–2位是否为合法的星期缩写(忽略大小写,但后续必须映射到标准集合集,像
sun、mon等) - 检查第5–6位是否为01–31之间的数字(但需要结合月份判断具体上限)
- 检查第8–10位是否为合法月份缩写(
jan–dec) - 检查第12–15位是否为合理的年份,一般限制在1970–2038(POSIX时间范围内)
- 检查时间部分是否符合24小时制(00–23),秒数≤59
- 强制要求时区字段精确等于“GMT”(全大写,两端无空格)
其中比较隐蔽的是月份天数的动态判断——比如2月需要区分闰年。可以用std::chrono::year_month_day辅助验证,不过得先把提取出来的数字构造为year{y}/month{m}/day{d},然后调用ok()成员函数。这套流程写起来不复杂,但比直接调库多了一份可控性。
有没有现成可用的轻量级方案?
如果你项目里已经有Boost,那直接用boost::date_time的parse_date_time配合rfc_1123格式器就能正确解析,但为了一个日期解析引入Boost可能显得有些重。更务实的做法是复用curl或Poco里现成的RFC 1123解析函数,它们都是手工实现的查表+校验,经过大量生产验证。甚至可以直接抄一段老C代码(比如http_date_parse类函数),比自己从零写省心多了。
真正容易被忽略的细节是:GMT必须全大写、逗号后面必须有且仅有一个空格、月份和星期缩写必须小写——这些条件缺一不可,稍微偏差一点,就不算合法的RFC 1123日期。记住这些硬约束,才能写出真正健壮的解析逻辑。