perf: cache log timestamp formatters

This commit is contained in:
Peter Steinberger
2026-05-31 06:09:03 +01:00
parent b858d418aa
commit 51dee73a5d

View File

@@ -1,10 +1,21 @@
const validTimeZoneCache = new Map<string, boolean>();
const timestampFormatterCache = new Map<string, Intl.DateTimeFormat>();
let hostTimeZone: string | undefined;
export function isValidTimeZone(tz: string): boolean {
const cached = validTimeZoneCache.get(tz);
if (cached !== undefined) {
return cached;
}
let valid = false;
try {
new Intl.DateTimeFormat("en", { timeZone: tz }).format();
return true;
valid = true;
} catch {
return false;
valid = false;
}
validTimeZoneCache.set(tz, valid);
return valid;
}
type TimestampStyle = "short" | "medium" | "long";
@@ -18,7 +29,7 @@ function resolveEffectiveTimeZone(timeZone?: string): string {
const explicit = timeZone ?? process.env.TZ;
return explicit && isValidTimeZone(explicit)
? explicit
: Intl.DateTimeFormat().resolvedOptions().timeZone;
: (hostTimeZone ??= Intl.DateTimeFormat().resolvedOptions().timeZone);
}
function formatOffset(offsetRaw: string): string {
@@ -26,18 +37,25 @@ function formatOffset(offsetRaw: string): string {
}
function getTimestampParts(date: Date, timeZone?: string) {
const fmt = new Intl.DateTimeFormat("en", {
timeZone: resolveEffectiveTimeZone(timeZone),
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: false,
fractionalSecondDigits: 3 as 1 | 2 | 3,
timeZoneName: "longOffset",
});
const effectiveTimeZone = resolveEffectiveTimeZone(timeZone);
let fmt = timestampFormatterCache.get(effectiveTimeZone);
if (!fmt) {
// Log timestamps are formatted on hot paths; Intl construction is much
// costlier than formatToParts, while timezone rules remain process-stable.
fmt = new Intl.DateTimeFormat("en", {
timeZone: effectiveTimeZone,
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: false,
fractionalSecondDigits: 3 as 1 | 2 | 3,
timeZoneName: "longOffset",
});
timestampFormatterCache.set(effectiveTimeZone, fmt);
}
const parts = Object.fromEntries(fmt.formatToParts(date).map((part) => [part.type, part.value]));
return {