mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 08:13:50 +00:00
46 lines
2.3 KiB
TypeScript
46 lines
2.3 KiB
TypeScript
import type { AnniversaryDate, PartialDate } from "@/lib/jmap/types";
|
|
|
|
/**
|
|
* A contact's date (birthday, anniversary, created) in the UI language:
|
|
* "15. März 1988", "March 15", "1988". A date without a year (vCard
|
|
* "--03-15") or without a day shows only what it has.
|
|
*/
|
|
export function formatContactDate(dateInput: AnniversaryDate | string, locale: string): string {
|
|
const parts = contactDateParts(dateInput);
|
|
const { year, month, day } = parts;
|
|
try {
|
|
if (month && day) {
|
|
// A leap year, so 29 February survives without a year.
|
|
const d = new Date(Date.UTC(year ?? 2000, month - 1, day));
|
|
return new Intl.DateTimeFormat(locale, { timeZone: "UTC", month: "long", day: "numeric", ...(year ? { year: "numeric" } : {}) }).format(d);
|
|
}
|
|
if (month) {
|
|
const d = new Date(Date.UTC(year ?? 2000, month - 1, 1));
|
|
return new Intl.DateTimeFormat(locale, { timeZone: "UTC", month: "long", ...(year ? { year: "numeric" } : {}) }).format(d);
|
|
}
|
|
if (year) return String(year);
|
|
} catch { /* an unknown locale: below */ }
|
|
return typeof dateInput === "string" ? dateInput : JSON.stringify(dateInput);
|
|
}
|
|
|
|
/** The year, month and day a contact's date names, whichever it has. */
|
|
export function contactDateParts(dateInput: AnniversaryDate | string): { year?: number; month?: number; day?: number } {
|
|
if (typeof dateInput === "object" && dateInput !== null) {
|
|
if (dateInput["@type"] === "Timestamp" && typeof (dateInput as { utc?: unknown }).utc === "string") {
|
|
const d = new Date((dateInput as { utc: string }).utc);
|
|
return isNaN(d.getTime()) ? {} : { year: d.getUTCFullYear(), month: d.getUTCMonth() + 1, day: d.getUTCDate() };
|
|
}
|
|
const pd = dateInput as PartialDate;
|
|
return { year: pd.year, month: pd.month, day: pd.day };
|
|
}
|
|
const s = String(dateInput);
|
|
if (s.startsWith("--")) {
|
|
const [m, d] = s.substring(2).split("-");
|
|
return { month: parseInt(m, 10) || undefined, day: d ? parseInt(d, 10) || undefined : undefined };
|
|
}
|
|
const iso = /^(\d{4})-(\d{2})(?:-(\d{2}))?/.exec(s);
|
|
if (iso) return { year: Number(iso[1]), month: Number(iso[2]), day: iso[3] ? Number(iso[3]) : undefined };
|
|
const d = new Date(s);
|
|
return isNaN(d.getTime()) ? {} : { year: d.getUTCFullYear(), month: d.getUTCMonth() + 1, day: d.getUTCDate() };
|
|
}
|