/** * DateDisplay * * Deterministic date formatting for display. * Avoids Intl and toLocaleString to prevent SSR/hydration mismatches. */ export class DateDisplay { private static readonly MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; private static readonly FULL_MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; private static readonly DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; private static readonly FULL_DAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; /** * Formats a date as "MMM D, YYYY" (e.g., "Jan 1, 2024") */ static formatShort(date: Date | string): string { const d = typeof date === 'string' ? new Date(date) : date; return `${this.MONTHS[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`; } /** * Formats a date as "YYYY-MM-DD" */ static formatIso(date: Date | string): string { const d = typeof date === 'string' ? new Date(date) : date; const month = (d.getMonth() + 1).toString().padStart(2, '0'); const day = d.getDate().toString().padStart(2, '0'); return `${d.getFullYear()}-${month}-${day}`; } /** * Formats a date as "Weekday, Month Day, Year" */ static formatFull(date: Date | string): string { const d = typeof date === 'string' ? new Date(date) : date; return `${this.FULL_DAYS[d.getDay()]}, ${this.FULL_MONTHS[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`; } /** * Formats a date as "MMM YYYY" (e.g., "Jan 2024") */ static formatMonthYear(date: Date | string): string { const d = typeof date === 'string' ? new Date(date) : date; return `${this.MONTHS[d.getMonth()]} ${d.getFullYear()}`; } }