const HAS_TIMEZONE_OFFSET = /(?:Z|[+-]\d{2}:?\d{2})$/i; function normalizeServerDateTime(value: string): string { const trimmed = value.trim(); if (!trimmed) return trimmed; return HAS_TIMEZONE_OFFSET.test(trimmed) ? trimmed : `${trimmed}Z`; } export function parseServerDateTime(value?: string | null): Date | null { if (!value) return null; const date = new Date(normalizeServerDateTime(value)); return Number.isNaN(date.getTime()) ? null : date; } export type FormatDateTimeOptions = Intl.DateTimeFormatOptions & { fallback?: string; }; export const defaultDateTimeFormatOptions: Intl.DateTimeFormatOptions = { year: "numeric", month: "short", day: "2-digit", hour: "2-digit", minute: "2-digit", timeZoneName: "short" }; export function formatDateTime(value?: string | null, options: FormatDateTimeOptions = {}): string { const fallback = options.fallback ?? "—"; if (!value) return fallback; const date = parseServerDateTime(value); if (!date) return value; const { fallback: _fallback, ...intlOptions } = options; return date.toLocaleString(undefined, { ...defaultDateTimeFormatOptions, ...intlOptions }); } export function formatDateTimeFromDate(value: Date, options: FormatDateTimeOptions = {}): string { const { fallback: _fallback, ...intlOptions } = options; return value.toLocaleString(undefined, { ...defaultDateTimeFormatOptions, ...intlOptions }); }