Files
openclaw/src/logging/timestamps.ts

76 lines
2.2 KiB
TypeScript

export function isValidTimeZone(tz: string): boolean {
try {
new Intl.DateTimeFormat("en", { timeZone: tz });
return true;
} catch {
return false;
}
}
export type TimestampStyle = "short" | "medium" | "long";
export type FormatTimestampOptions = {
style?: TimestampStyle;
timeZone?: string;
};
function resolveEffectiveTimeZone(timeZone?: string): string {
const explicit = timeZone ?? process.env.TZ;
return explicit && isValidTimeZone(explicit)
? explicit
: Intl.DateTimeFormat().resolvedOptions().timeZone;
}
function formatOffset(offsetRaw: string): string {
return offsetRaw === "GMT" ? "+00:00" : offsetRaw.slice(3);
}
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 parts = Object.fromEntries(fmt.formatToParts(date).map((part) => [part.type, part.value]));
return {
year: parts.year,
month: parts.month,
day: parts.day,
hour: parts.hour,
minute: parts.minute,
second: parts.second,
fractionalSecond: parts.fractionalSecond,
offset: formatOffset(parts.timeZoneName ?? "GMT"),
};
}
export function formatTimestamp(date: Date, options?: FormatTimestampOptions): string {
const style = options?.style ?? "medium";
const parts = getTimestampParts(date, options?.timeZone);
switch (style) {
case "short":
return `${parts.hour}:${parts.minute}:${parts.second}${parts.offset}`;
case "medium":
return `${parts.hour}:${parts.minute}:${parts.second}.${parts.fractionalSecond}${parts.offset}`;
case "long":
return `${parts.year}-${parts.month}-${parts.day}T${parts.hour}:${parts.minute}:${parts.second}.${parts.fractionalSecond}${parts.offset}`;
}
}
/**
* @deprecated Use formatTimestamp from "./timestamps.js" instead.
* This function will be removed in a future version.
*/
export function formatLocalIsoWithOffset(now: Date, timeZone?: string): string {
return formatTimestamp(now, { style: "long", timeZone });
}