import type { VisibleDateRange } from '../types' export function parseCalendarDate(value: string | null | undefined): Date | null { if (!value) return null const parts = /^(\d{4})-(\d{2})-(\d{2})/.exec(value) if (!parts) return null const year = Number(parts[1]) const month = Number(parts[2]) - 1 const day = Number(parts[3]) const date = new Date(year, month, day) return date.getFullYear() === year && date.getMonth() === month && date.getDate() === day ? date : null } export function startOfLocalDay(date: Date): Date { const start = new Date(date) start.setHours(0, 0, 0, 0) return start } export function shiftLocalDays(date: Date, days: number): Date { const shifted = new Date(date) shifted.setDate(shifted.getDate() + days) return shifted } export function shiftLocalMonths(date: Date, months: number): Date { const shifted = new Date(date) const targetDay = shifted.getDate() shifted.setDate(1) shifted.setMonth(shifted.getMonth() + months) const lastDayOfTargetMonth = new Date( shifted.getFullYear(), shifted.getMonth() + 1, 0, ).getDate() shifted.setDate(Math.min(targetDay, lastDayOfTargetMonth)) return shifted } export function daysVisibleRange(date: Date, days: number): VisibleDateRange { const start = startOfLocalDay(date) const end = shiftLocalDays(start, Math.max(1, days)) return { startMs: start.getTime(), endMs: end.getTime(), } } export function monthGridVisibleRange(date: Date): VisibleDateRange { const firstDay = new Date(date.getFullYear(), date.getMonth(), 1) const gridStart = new Date(firstDay) gridStart.setDate(gridStart.getDate() - gridStart.getDay()) const lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0) const weeks = Math.ceil((firstDay.getDay() + lastDay.getDate()) / 7) const gridEnd = shiftLocalDays(gridStart, weeks * 7) return { startMs: gridStart.getTime(), endMs: gridEnd.getTime(), } }