Files
anouma/lib/seo/dates.ts
T

30 lines
1.2 KiB
TypeScript

/**
* Formats a JS Date as an ISO 8601 string carrying its actual Europe/Berlin
* UTC offset (e.g. "2026-06-15T09:00:00+02:00" in summer,
* "...+01:00" in winter) - what schema.org's Event startDate/endDate
* expect. Uses Intl's timezone database rather than hardcoded +1/+2 math,
* so it's correct across the DST transition automatically.
*/
export function toBerlinOffsetISOString(date: Date): string {
const parts = new Intl.DateTimeFormat("en-US", {
timeZone: "Europe/Berlin",
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hourCycle: "h23",
timeZoneName: "shortOffset",
}).formatToParts(date);
const get = (type: string) => parts.find((p) => p.type === type)?.value ?? "00";
const tzName = parts.find((p) => p.type === "timeZoneName")?.value ?? "GMT+0";
const match = /GMT([+-])(\d+)(?::(\d+))?/.exec(tzName);
const sign = match?.[1] ?? "+";
const offsetHours = (match?.[2] ?? "0").padStart(2, "0");
const offsetMinutes = (match?.[3] ?? "0").padStart(2, "0");
return `${get("year")}-${get("month")}-${get("day")}T${get("hour")}:${get("minute")}:${get("second")}${sign}${offsetHours}:${offsetMinutes}`;
}