// Plain UTC calendar-date math, shared by the scheduled-todo server logic // and its client components. Deliberately UTC-based rather than local-time // -- Prisma's `@db.Date` columns round-trip as UTC-midnight `Date`s, and // `rrule`'s occurrence math is documented to want the same, so keeping // every date here anchored to UTC midnight avoids DST/timezone drift // between "today" on the server and an occurrence date from the database. /** Truncates a Date to UTC midnight of the same calendar day. */ export function startOfUTCDate(date: Date): Date { return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate())); } /** Adds (or subtracts, if negative) whole days, staying UTC-midnight-aligned. */ export function addUTCDays(date: Date, days: number): Date { const d = startOfUTCDate(date); d.setUTCDate(d.getUTCDate() + days); return d; } /** Monday of the calendar week containing `date` (Mon–Sun weeks). */ export function getWeekStart(date: Date): Date { const d = startOfUTCDate(date); const day = d.getUTCDay(); // 0 = Sun .. 6 = Sat const diffToMonday = day === 0 ? -6 : 1 - day; return addUTCDays(d, diffToMonday); } /** "YYYY-MM-DD", used as both a display value and a stable map/comparison key. */ export function toDateKey(date: Date): string { return date.toISOString().slice(0, 10); } export function isSameUTCDate(a: Date, b: Date): boolean { return toDateKey(a) === toDateKey(b); }