功能说明
formatHttpDate 输出 HTTP 头要求的 IMF-fixdate 形式,例如 Sun, 06 Nov 1994 08:49:37 GMT,所有字段固定为 UTC,日期与时间补零。parseHttpDate 接受 IMF-fixdate、RFC 850 与 asctime 三种历史格式,并返回新的 Date。它们适合设置 Expires、Last-Modified、If-Modified-Since 以及解析 Retry-After 中的日期值。
关键代码
格式化函数使用固定的星期与月份缩写表,按 UTC 取年月日时分秒,再用 padStart 补齐两位。输入既可以是 Date,也可以传给 Date 构造器解析的字符串,非法日期会抛错。解析函数直接调用 Date.parse,现代运行时能识别三种 HTTP 日期格式,之后检查是否为 NaN 并包装成 Date,避免把无效字符串静默变成 Invalid Date。
使用注意
HTTP 日期必须使用 GMT,不能输出本地时区或毫秒,格式化函数已忽略毫秒。Date.parse 对非标准格式的容忍度因实现而异,解析外部头时应限定格式并做范围校验。Expires 使用绝对时间,受客户端时钟影响,缓存控制通常优先用 Cache-Control 的 max-age。比较日期时直接用时间戳,不要比较格式化字符串。
验证方式
用已知时间戳断言输出为 Sun, 06 Nov 1994 08:49:37 GMT,并测试个位数日期与时间的补零。构造三种历史格式字符串,验证解析结果一致。测试带毫秒的 Date 会被截断、非法日期与非字符串输入会抛错。再验证跨年、闰日与 GMT 与本地时区差异,确保格式化始终基于 UTC。
代码示例
const DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
function pad(value) {
return String(value).padStart(2, "0");
}
export function formatHttpDate(date = new Date()) {
const value = date instanceof Date ? date : new Date(date);
if (Number.isNaN(value.getTime())) throw new RangeError("invalid date");
return DAYS[value.getUTCDay()] + ", "
+ pad(value.getUTCDate()) + " "
+ MONTHS[value.getUTCMonth()] + " "
+ value.getUTCFullYear() + " "
+ pad(value.getUTCHours()) + ":"
+ pad(value.getUTCMinutes()) + ":"
+ pad(value.getUTCSeconds()) + " GMT";
}
export function parseHttpDate(input) {
if (typeof input !== "string") throw new TypeError("input must be a string");
const value = Date.parse(input);
if (Number.isNaN(value)) throw new RangeError("invalid HTTP date");
return new Date(value);
}