← 中文资源

简体中文版本

HTTP 日期格式化与解析

把 Date 格式化为 HTTP 头使用的 IMF-fixdate,并把三种历史 HTTP 日期格式解析为 Date。

阅读英文原文

功能说明

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);
}