// Appointment times as the deck writes them, on the viewer's clock; the zone label only when it differs. const instantOf = (iso?: string): Date | undefined => { if (!iso) return undefined; const at = new Date(iso); return Number.isNaN(at.getTime()) ? undefined : at; }; const timeOf = (at: Date, zoneLabel?: string | null): string => `${at.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" })}${zoneLabel ? ` ${zoneLabel}` : ""}`; export const appointmentRowWhen = (iso?: string, zoneLabel?: string | null): string => { const at = instantOf(iso); if (!at) return ""; const day = at.toLocaleDateString("en-US", { weekday: "short", month: "short", day: "numeric" }); return `${day} ยท ${timeOf(at, zoneLabel)}`; }; export const appointmentDetailDate = (iso?: string): string => { const at = instantOf(iso); if (!at) return ""; const weekday = at.toLocaleDateString("en-US", { weekday: "short" }); const date = at.toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" }); return `${weekday} ${date}`; }; export const appointmentDetailTime = (iso?: string, zoneLabel?: string | null): string => { const at = instantOf(iso); return at ? timeOf(at, zoneLabel) : ""; }; export const appointmentShortDate = (iso?: string): string => { const at = instantOf(iso); return at ? at.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }) : ""; }; const startOfDay = (at: Date): number => new Date(at.getFullYear(), at.getMonth(), at.getDate()).getTime(); // "in 6 days", "Tomorrow", "3 months ago": a distance a patient reads at a glance, in whole calendar // days on their own clock, and in months once days stop meaning anything. export const appointmentRelativeDay = (iso?: string, now: Date = new Date()): string => { const at = instantOf(iso); if (!at) return ""; const days = Math.round((startOfDay(at) - startOfDay(now)) / 86_400_000); if (days === 0) return "Today"; if (days === 1) return "Tomorrow"; if (days === -1) return "Yesterday"; const span = Math.abs(days); const amount = span >= 60 ? `${Math.round(span / 30.44)} months` : `${span} days`; return days > 0 ? `in ${amount}` : `${amount} ago`; };