RFC 1123日期格式为“Sun, 06 Nov 1994 08:49:37 GMT”,因std::get_time依赖locale且不支持GMT字面量解析,故需手动分段校验:长度29、逗号空格位置固定、星期/月份白名单、日期/时间范围检查、年份1900–2100、时区严格为GMT。

什么是RFC 1123日期格式,为什么不能直接用std::get_time?
RFC 1123规定的HTTP日期格式是:Sun, 06 Nov 1994 08:49:37 GMT(注意逗号后有空格、月份是英文全称、时区固定为GMT)。C++标准库的std::get_time在多数实现(尤其是libstdc++)中对%a(缩写星期)、%b(缩写月份)的locale依赖极强,且不保证支持GMT字面量解析——它会尝试匹配当前locale的时区名,而GMT在很多系统locale里不是合法时区标识,导致解析失败或静默截断。
手动解析+白名单校验是最可靠的做法
绕过locale陷阱的务实办法:不依赖std::get_time,而是用std::string_view分段切片,逐字段校验。关键点在于:
- 字符串总长必须是29字符(
"Sun, 06 Nov 1994 08:49:37 GMT"),少一位或多一位都直接拒绝 - 第0–2位必须是星期缩写白名单:
"Sun"、"Mon"…"Sat"(注意大小写敏感) - 第5–6位是两位数字日期,需检查是否为
'0'或'1'开头且整体在01–31范围内 - 第8–10位必须是月份白名单:
"Jan"、"Feb"…"Dec" - 第12–15位是四位年份,范围限定在
1900–2100(RFC未规定上下限,但HTTP实践中极少超出) - 第17–18位小时、第20–21位分钟、第23–24位秒,均需是
00–59或00–23有效值 - 第26–28位必须严格等于
"GMT"(不可是"UTC"或空格)
示例代码:轻量级校验函数
bool is_rfc1123_date(const std::string& s) {
if (s.length() != 29) return false;
// 检查固定分隔符位置
if (s[3] != ',' || s[7] != ' ' || s[11] != ' ' || s[16] != ' ' || s[19] != ':' || s[22] != ':' || s[25] != ' ')
return false;
<pre class="brush:php;toolbar:false;">// 星期白名单
static const std::unordered_set<std::string_view> weekdays = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
if (weekdays.find(std::string_view(s.c_str(), 3)) == weekdays.end()) return false;
// 日期数字校验(第5-6位)
if (!std::isdigit(s[5]) || !std::isdigit(s[6])) return false;
int day = (s[5] - '0') * 10 + (s[6] - '0');
if (day < 1 || day > 31) return false;
// 月份白名单(第8-10位)
static const std::unordered_set<std::string_view> months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
if (months.find(std::string_view(s.c_str() + 8, 3)) == months.end()) return false;
// 年份(第12-15位)
if (!std::all_of(s.begin() + 12, s.begin() + 16, ::isdigit)) return false;
int year = std::stoi(s.substr(12, 4));
if (year < 1900 || year > 2100) return false;
// 时间部分(小时/分钟/秒)
auto parse_two = [](const char* p) -> int {
return (p[0] - '0') * 10 + (p[1] - '0');
};
int hour = parse_two(s.c_str() + 17);
int min = parse_two(s.c_str() + 20);
int sec = parse_two(s.c_str() + 23);
if (hour > 23 || min > 59 || sec > 59) return false;
// 时区必须是GMT
if (s.substr(26, 3) != "GMT") return false;
return true;}
注意时区和闰秒等边界情况
RFC 1123明确要求使用GMT而非UTC,且不支持闰秒(即60秒非法)。实际HTTP服务器生成的日期几乎不会出现闰秒,但如果你对接的是自制服务或旧设备,要留意sec == 60的情况——它不符合规范,应拒绝。另外,这个校验不处理输入字符串的前后空白,调用前建议先std::string::find_first_not_of(" \t\r\n")做trim,否则" Sun, 06 Nov 1994 08:49:37 GMT "会因长度不符被直接判错。
立即学习“C++免费学习笔记(深入)”;


















