47 lines
1.4 KiB
TypeScript
47 lines
1.4 KiB
TypeScript
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
|
|
});
|
|
}
|