export const toYmd = (year: number, month: number, day: number) => { const mm = String(month + 1).padStart(2, '0') const dd = String(day).padStart(2, '0') return `${year}-${mm}-${dd}` } export const normalizeDate = (value: string) => value.slice(0, 10) export const parseYmd = (value: string) => { const [year, month, day] = value.split('-').map(Number) if (!year || !month || !day) return null return new Date(year, month - 1, day) } export const formatDateLongFr = (date: Date) => { const label = new Intl.DateTimeFormat('fr-FR', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' }).format(date) return label.charAt(0).toUpperCase() + label.slice(1) } export const formatWeekDayHeaderFr = (dateYmd: string) => { const parsed = parseYmd(dateYmd) if (!parsed) return dateYmd return new Intl.DateTimeFormat('fr-FR', { weekday: 'short', day: '2-digit', month: '2-digit' }).format(parsed) } export const getWeekStartDate = (date: Date) => { const copy = new Date(date) const day = copy.getDay() const diff = day === 0 ? -6 : 1 - day copy.setDate(copy.getDate() + diff) copy.setHours(0, 0, 0, 0) return copy } export const getIsoWeekNumber = (date: Date) => { const utc = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate())) const day = utc.getUTCDay() || 7 utc.setUTCDate(utc.getUTCDate() + 4 - day) const yearStart = new Date(Date.UTC(utc.getUTCFullYear(), 0, 1)) return Math.ceil((((utc.getTime() - yearStart.getTime()) / 86400000) + 1) / 7) } export const getIsoWeekYear = (date: Date) => { const utc = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate())) const day = utc.getUTCDay() || 7 utc.setUTCDate(utc.getUTCDate() + 4 - day) return utc.getUTCFullYear() } export const ymdToWeekInputValue = (dateYmd: string) => { const parsed = parseYmd(dateYmd) if (!parsed) return '' const weekDate = getWeekStartDate(parsed) const weekNumber = getIsoWeekNumber(weekDate) const weekYear = getIsoWeekYear(weekDate) return `${weekYear}-W${String(weekNumber).padStart(2, '0')}` } export const weekInputValueToYmd = (weekValue: string) => { const match = /^(\d{4})-W(\d{2})$/.exec(weekValue) if (!match) return null const year = Number(match[1]) const week = Number(match[2]) if (!Number.isInteger(year) || !Number.isInteger(week) || week < 1 || week > 53) return null const jan4 = new Date(year, 0, 4) const week1Monday = getWeekStartDate(jan4) const monday = new Date(week1Monday) monday.setDate(week1Monday.getDate() + ((week - 1) * 7)) return toYmd(monday.getFullYear(), monday.getMonth(), monday.getDate()) } export const getTodayYmd = () => { const date = new Date() return toYmd(date.getFullYear(), date.getMonth(), date.getDate()) } export const getOffsetFromTodayYmd = (offset: number) => { const date = new Date() date.setDate(date.getDate() + offset) return toYmd(date.getFullYear(), date.getMonth(), date.getDate()) } export const shiftYmd = (value: string, days: number) => { const parsed = parseYmd(value) if (!parsed) return null parsed.setDate(parsed.getDate() + days) return toYmd(parsed.getFullYear(), parsed.getMonth(), parsed.getDate()) } export const formatWeekRangeFr = (date: Date) => { const start = getWeekStartDate(date) const end = new Date(start) end.setDate(start.getDate() + 6) const weekNumber = getIsoWeekNumber(start) const formatter = new Intl.DateTimeFormat('fr-FR', { day: '2-digit', month: '2-digit', year: 'numeric' }) return `S${weekNumber} du ${formatter.format(start)} au ${formatter.format(end)}` } export const getDaysInMonth = (year: number, month: number) => { const total = new Date(year, month + 1, 0).getDate() const weekdays = ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'] return Array.from({ length: total }, (_, index) => { const day = index + 1 const dateObj = new Date(year, month, day) return { date: toYmd(year, month, day), label: String(day), weekday: weekdays[dateObj.getDay()] } }) }