diff --git a/src/shared/utils/time-utils/get-node-reset-days/get-node-reset-days.util.ts b/src/shared/utils/time-utils/get-node-reset-days/get-node-reset-days.util.ts index 60817b47..62386ab9 100644 --- a/src/shared/utils/time-utils/get-node-reset-days/get-node-reset-days.util.ts +++ b/src/shared/utils/time-utils/get-node-reset-days/get-node-reset-days.util.ts @@ -4,14 +4,13 @@ import dayjs from 'dayjs' export function getNodeResetDaysUtil(targetDay: number): number { const today = dayjs() + const nextMonth = today.add(1, 'month') - const targetThisMonth = today.date(targetDay) - const targetNextMonth = today.add(1, 'month').date(targetDay) - - const correctedThisMonth = targetThisMonth.isValid() ? targetThisMonth : today.endOf('month') - const correctedNextMonth = targetNextMonth.isValid() - ? targetNextMonth - : today.add(1, 'month').endOf('month') + // dayjs silently rolls overflowing days into the next month (e.g. Feb 30 -> + // Mar 2) and keeps `isValid()` truthy, so clamp the target day to the number + // of days in the respective month to land on the last day instead. + const correctedThisMonth = today.date(Math.min(targetDay, today.daysInMonth())) + const correctedNextMonth = nextMonth.date(Math.min(targetDay, nextMonth.daysInMonth())) const daysToThisMonth = correctedThisMonth.diff(today, 'day') const daysToNextMonth = correctedNextMonth.diff(today, 'day') @@ -28,15 +27,21 @@ export function getNodeResetDaysUtil(targetDay: number): number { export function getNodeResetPeriodUtil(targetDay: number): string { const today = dayjs() + const prevMonth = today.subtract(1, 'month') + const nextMonth = today.add(1, 'month') - const targetThisMonth = today.date(targetDay) - const correctedThisMonth = targetThisMonth.isValid() ? targetThisMonth : today.endOf('month') + // Clamp the target day independently for each month, otherwise deriving the + // previous/next reset date by adding or subtracting a month can land on the + // wrong day when the adjacent month has a different number of days. + const correctedPrevMonth = prevMonth.date(Math.min(targetDay, prevMonth.daysInMonth())) + const correctedThisMonth = today.date(Math.min(targetDay, today.daysInMonth())) + const correctedNextMonth = nextMonth.date(Math.min(targetDay, nextMonth.daysInMonth())) const isPastTargetDay = today.date() > targetDay - const startDate = isPastTargetDay ? correctedThisMonth : correctedThisMonth.subtract(1, 'month') + const startDate = isPastTargetDay ? correctedThisMonth : correctedPrevMonth - const endDate = isPastTargetDay ? correctedThisMonth.add(1, 'month') : correctedThisMonth + const endDate = isPastTargetDay ? correctedNextMonth : correctedThisMonth return `${startDate.format('D MMMM')} – ${endDate.format('D MMMM')}` }