RFC 1123日期合法性需双重校验:先用正则匹配严格格式(如首字母大写的3字母星期、2位日期、GMT时区),再手动验证星期缩写与实际日期一致性,std::get_time和std::chrono::parse均无法替代此语义校验。

不能只靠 std::get_time 或 std::chrono::parse 判断 RFC 1123 格式是否合法——它们只做语法解析,不校验字段语义(比如星期几是否匹配日期、月份缩写是否正确、时区是否固定为 GMT)。
RFC 1123 格式字符串必须严格匹配 "ddd, dd MMM yyyy HH:mm:ss GMT"
RFC 1123 规定的 HTTP 日期格式是硬编码的:7 字母星期缩写(Mon–Sun)、2 位日期(01–31)、3 字母月份缩写(Jan–Dec)、4 位年份(1970–9999)、6 位时间(HH:mm:ss),且时区**必须是字面量 "GMT"**,不允许 "UTC" 或空格/大小写变体。
-
Mon, 01 Jan 2023 00:00:00 GMT✅ 合法 -
mon, 01 jan 2023 00:00:00 GMT❌ 星期和月份必须首字母大写 -
Mon, 01 Jan 2023 00:00:00 UTC❌ 时区必须是GMT,不是UTC -
Mon, 1 Jan 2023 00:00:00 GMT❌ 日期必须是两位(01,非1) -
Monday, 01 Jan 2023 00:00:00 GMT❌ 星期必须是 3 字母缩写
用 std::regex 做初步格式过滤(C++11 起)
正则只能验证字符串结构,不能验证“2023-02-30”这种逻辑错误,但能快速筛掉明显非法输入。推荐预编译一个带命名捕获的正则:
const std::regex rfc1123_regex(
R"(^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (\d{2}) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d{2}):(\d{2}):(\d{2}) GMT$)"
);匹配后还需提取并验证:
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 检查
day是否在01–31范围内(字符串形式,不用转整数) - 确认
hour/min/sec数值合法(00–23、00–59、00–59) - 月份缩写与数字月份要一致(
Jan↔1) - 星期缩写必须与计算出的星期几一致(需用
std::mktime或std::chrono推算)
星期几和日期是否匹配必须手动验证
这是最容易被忽略的点:RFC 1123 要求 ddd(如 Mon)必须与 dd MMM yyyy 实际对应的星期几完全一致。C++ 标准库没有现成函数直接从字符串推星期,得走一遍转换:
- 用
std::sscanf提取年、月、日(注意月份要映射:"Jan"→1,"Feb"→2…) - 构造
std::tm:设tm.tm_year = year - 1900,tm.tm_mon = month - 1,tm.tm_mday = day,其他字段清零 - 调用
std::mktime(&tm)—— 它会归一化并填入tm.tm_wday - 比对原始字符串中的
ddd和tm.tm_wday(0=Sun,1=Mon…)
如果 std::mktime 返回 -1,说明日期本身非法(如 2023-02-30),直接判错。
C++20 std::chrono::parse 仍不能替代手动校验
即使使用 std::chrono::parse("%a, %d %b %Y %T GMT", tp, ss),它仍存在两个致命缺陷:
- 对星期缩写大小写不敏感(
mon也能过),而 RFC 1123 要求首字母大写 - 不验证
%a与实际日期是否对应 —— 即使你传入"Fri, 01 Jan 2023",而那天其实是 Saturday,parse仍可能成功
所以无论用哪种解析方式,最终都必须做两件事:格式正则过滤 + 星期/日期一致性校验。漏掉任一环节,就可能把伪造的或错位的日期当成合法 HTTP 日期。

















