@burglekitt/gmt
Version:
Temporal-based date and time utilities with timezone support and polyfill integration
52 lines (51 loc) • 2.23 kB
JavaScript
import { Temporal } from "@js-temporal/polyfill";
import { ENGLISH_MONTH_NAMES } from "../../internal/index.js";
import { httpDate } from "../../regex/index.js";
/**
* Parse an RFC 7231 IMF-fixdate string — the fixed grammar HTTP headers like
* `Last-Modified`/`Date`/`Expires` use — into a UTC ISO 8601 datetime string.
*
* - **Decoding, not display.** Accepts English weekday/month abbreviations
* only, per the fixed grammar (see `formatHttp`'s JSDoc and roadmap
* Decision 1).
* - **IMF-fixdate only.** RFC 7231 also lists two obsolete forms
* (`rfc850-date`, `asctime-date`) that real HTTP servers occasionally
* still emit; this is a documented limitation — neither is accepted here.
* - Day, hour, minute, and second must each be exactly 2 digits and the
* trailing zone must be the literal `GMT` — unlike `parseRfc2822`, no
* numeric offset or named-zone table is accepted.
* - The day-of-week is not cross-validated against the computed date, the
* same deliberate scope limit `parseDateTimeWithPattern`/J11 uses.
*
* @param value RFC 7231 IMF-fixdate string (e.g. "Fri, 15 Mar 2024 14:30:00 GMT")
* @returns UTC ISO 8601 datetime string, or "" on invalid input
*
* @example parseHttp("Fri, 15 Mar 2024 14:30:00 GMT") // "2024-03-15T14:30:00Z"
* @example parseHttp("Fri, 15 Mar 2024 14:30:00 -0400") // "" (not IMF-fixdate)
* @example parseHttp("not a date") // ""
*/
export function parseHttp(value) {
if (typeof value !== "string")
return "";
const match = httpDate.exec(value);
if (match === null)
return "";
const [, , dayStr, monthName, yearStr, hourStr, minuteStr, secondStr] = match;
const monthIndex = ENGLISH_MONTH_NAMES.indexOf(monthName);
if (monthIndex === -1)
return "";
try {
const plainDateTime = Temporal.PlainDateTime.from({
year: Number(yearStr),
month: monthIndex + 1,
day: Number(dayStr),
hour: Number(hourStr),
minute: Number(minuteStr),
second: Number(secondStr),
}, { overflow: "reject" });
return plainDateTime.toZonedDateTime("UTC").toInstant().toString();
}
catch {
return "";
}
}