/** Normalize to local midnight; invalid input falls back to today. */ export function startOfLocalDay(d: Date): Date { if (Number.isNaN(d.getTime())) { const t = new Date(); return new Date(t.getFullYear(), t.getMonth(), t.getDate(), 0, 0, 0, 0); } return new Date(d.getFullYear(), d.getMonth(), d.getDate(), 0, 0, 0, 0); } /** Local calendar bounds for a date (browser timezone). */ export function getLocalDayIsoRange(day: Date): { from: string; to: string } { const start = startOfLocalDay(day); const end = new Date(start.getFullYear(), start.getMonth(), start.getDate() + 1, 0, 0, 0, 0); return { from: start.toISOString(), to: end.toISOString() }; } export function toDateInputValue(d: Date): string { const y = d.getFullYear(); const m = String(d.getMonth() + 1).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0'); return `${y}-${m}-${day}`; } export function parseDateInput(value: string): Date { const [y, m, d] = value.split('-').map(Number); return new Date(y, m - 1, d, 0, 0, 0, 0); } export function combineLocalDateAndTime(day: Date, timeHHmm: string): Date { const [h, min] = timeHHmm.split(':').map(Number); return new Date(day.getFullYear(), day.getMonth(), day.getDate(), h, min, 0, 0); } export function formatTimeForInput(d: Date): string { const h = String(d.getHours()).padStart(2, '0'); const m = String(d.getMinutes()).padStart(2, '0'); return `${h}:${m}`; } export function isSameLocalCalendarDay(a: Date, b: Date): boolean { return ( a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate() ); } export function formatHourLabel(hour: number): string { const d = new Date(2000, 0, 1, hour, 0, 0, 0); return d.toLocaleTimeString(undefined, { hour: 'numeric', hour12: true }); } /** Local midnight + delta calendar days. */ export function addCalendarDays(day: Date, delta: number): Date { return new Date(day.getFullYear(), day.getMonth(), day.getDate() + delta, 0, 0, 0, 0); } /** Compare two calendar days at local midnight (ordering by date only). */ export function compareLocalDayStart(a: Date, b: Date): number { const ta = new Date(a.getFullYear(), a.getMonth(), a.getDate()).getTime(); const tb = new Date(b.getFullYear(), b.getMonth(), b.getDate()).getTime(); return ta - tb; }