c++oding="utf-8" ?>
rfc 1123时间格式为“sun, 06 nov 1994 08:49:37 gmt”,要求严格匹配英文缩写、4位年份、固定gmt时区及标点空格;std::get_time因locale依赖强、不校验gmt字面量且容忍多余字符,无法可靠解析。

什么是RFC 1123时间格式,为什么不能直接用std::get_time解析
RFC 1123定义的HTTP时间格式是:Sun, 06 Nov 1994 08:49:37 GMT(注意逗号、空格、英文缩写、时区固定为GMT)。它要求:星期和月份必须是英文全称缩写(Mon–Sun、Jan–Dec),年份4位,时区严格为GMT(不能是UTC或空),且整个字符串必须完全匹配——多一个空格、少一个逗号都算失败。
std::get_time在多数标准库实现(尤其是libstdc++)中对locale依赖强,%a %b %d %H:%M:%S %Y这类格式无法可靠识别英文缩写(尤其在非C locale下会失败),且不校验GMT字面量、不拒绝多余字符。直接用它解析"Mon, 01 Jan 2000 00:00:00 GMT"可能看似成功,但遇到"Mon, 01 Jan 2000 00:00:00 UTC"或"Mon, 01 Jan 2000 00:00:00 GMT "(末尾空格)时不会报错,导致误判。
手动分段校验:拆解字符串再逐项验证
最稳妥的方式是按RFC 1123结构硬解析:以逗号分隔星期部分,再按空格切出其余字段,然后逐字段比对。这样绕过locale和std::get_time的不确定性。
关键步骤:
- 检查总长度是否在29±1范围内(合法RFC 1123字符串长度固定为29,但部分实现允许末尾换行或空格,建议先
trim) - 验证前4字符是否形如
"Mon,"、"Tue,"等(逗号必须紧贴缩写后) - 第5–6位必须是空格,第7–9位必须是
"Jan"–"Dec"之一,第10位必须是空格 - 第11–12位是日期(
"01"–"31",需校验是否有效数字,且不能是"00") - 第13位必须是空格,第14–15位小时(
"00"–"23"),第16位:,依此类推 - 最后4字符必须严格等于
"GMT"(大小写敏感)
示例片段(不依赖第三方库):
bool is_rfc1123(const std::string& s) {
if (s.length() <h3>用<code>strptime</code>配合C locale(仅限POSIX系统)</h3><p>如果你确定运行环境是Linux/macOS(即支持POSIX),可以临时切到C locale调用<code>strptime</code>,并显式指定格式串<code>"%a, %d %b %Y %H:%M:%S GMT"</code>。这比<code>std::get_time</code>更可控,但仍有陷阱:</p>
- 必须在调用前用
setlocale(LC_TIME, "C"),否则locale可能返回中文星期名导致失败 -
strptime不检查输入结尾,"Mon, 01 Jan 2000 00:00:00 GMT extra"也会返回非空指针,需手动验证解析后指针是否指向字符串末尾 - Windows不原生支持
strptime(需第三方实现或MinGW) - 某些旧glibc版本对
%a匹配不严格,可能接受"mon"小写
安全用法示例:
char buf[32];
strcpy(buf, s.c_str());
struct tm t = {};
const char* end = strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &t);
if (!end || *end != '\0' || t.tm_wday <h3>推荐方案:用<code>date</code>库(现代C++首选)</h3><p>如果项目允许引入外部依赖,Howard Hinnant的<code>date</code>库(已融入C++20 <code><chrono></chrono></code>)是最省心的选择。它原生支持RFC 1123解析,且默认严格:</p>
- 调用
date::parse("%a, %d %b %Y %H:%M:%S GMT", ss, tp),其中ss是std::istringstream,tp是sys_time<seconds></seconds> - 解析失败时
ss.fail()为true;成功后还需检查ss.peek() == EOF,防止尾部垃圾字符 - 自动校验星期/月份缩写、数值范围、
GMT字面量,且不依赖系统locale - C++20可直接用
std::chrono::parse,但注意GCC 13+ / Clang 15+才完善支持
简短示例(C++17 + date.h):
#include "date/date.h"
bool is_rfc1123(const std::string& s) {
std::istringstream ss{s};
sys_seconds tp;
ss >> parse("%a, %d %b %Y %H:%M:%S GMT", tp);
return ss.good() && ss.peek() == EOF;
}
真正容易被忽略的是:即使用了date库,也得自己确保输入字符串不含BOM、\r\n混用、或不可见Unicode空格——这些在HTTP头里偶尔出现,会导致parse静默失败。预处理时用std::erase_if(s, ::isspace)不行,得用更保守的trim逻辑。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











