/** Avance une date d’un mois, en gardant le jour du mois (ou le dernier jour si besoin). */ export function addUtcMonths(date: Date, months: number): Date { const year = date.getUTCFullYear() const month = date.getUTCMonth() + months const day = date.getUTCDate() const lastDay = new Date(Date.UTC(year, month + 1, 0)).getUTCDate() return new Date(Date.UTC( year, month, Math.min(day, lastDay), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), date.getUTCMilliseconds(), )) } /** * Recalcule la période en cours à partir de la date d’origine. * Sans fiche de paiement, les dates étaient écrites une fois (souvent +1 an) et ne bougeaient plus. */ export function rollBillingPeriod( periodStart: Date, now: Date = new Date(), ): { currentPeriodStart: Date; currentPeriodEnd: Date } { if (Number.isNaN(periodStart.getTime())) { const start = new Date(now) return { currentPeriodStart: start, currentPeriodEnd: addUtcMonths(start, 1) } } let start = new Date(periodStart) let end = addUtcMonths(start, 1) if (start.getTime() > now.getTime()) { return { currentPeriodStart: start, currentPeriodEnd: end } } let guard = 0 while (end.getTime() <= now.getTime() && guard < 240) { start = end end = addUtcMonths(start, 1) guard += 1 } return { currentPeriodStart: start, currentPeriodEnd: end } } export function periodsDiffer( a: { currentPeriodStart: Date; currentPeriodEnd: Date }, b: { currentPeriodStart: Date; currentPeriodEnd: Date }, ): boolean { return ( a.currentPeriodStart.getTime() !== b.currentPeriodStart.getTime() || a.currentPeriodEnd.getTime() !== b.currentPeriodEnd.getTime() ) }