( date: DateArg<DateType>, amount: number, options?: AddBusinessDaysOptions<ResultDate> | undefined, )
| 41 | * //=> Mon Sep 15 2014 00:00:00 (skipped weekend days) |
| 42 | */ |
| 43 | export function addBusinessDays< |
| 44 | DateType extends Date, |
| 45 | ResultDate extends Date = DateType, |
| 46 | >( |
| 47 | date: DateArg<DateType>, |
| 48 | amount: number, |
| 49 | options?: AddBusinessDaysOptions<ResultDate> | undefined, |
| 50 | ): ResultDate { |
| 51 | const _date = toDate(date, options?.in); |
| 52 | const startedOnWeekend = isWeekend(_date, options); |
| 53 | |
| 54 | if (isNaN(amount)) return constructFrom(options?.in, NaN); |
| 55 | |
| 56 | const hours = _date.getHours(); |
| 57 | const sign = amount < 0 ? -1 : 1; |
| 58 | const fullWeeks = Math.trunc(amount / 5); |
| 59 | |
| 60 | _date.setDate(_date.getDate() + fullWeeks * 7); |
| 61 | |
| 62 | // Get remaining days not part of a full week |
| 63 | let restDays = Math.abs(amount % 5); |
| 64 | |
| 65 | // Loops over remaining days |
| 66 | while (restDays > 0) { |
| 67 | _date.setDate(_date.getDate() + sign); |
| 68 | if (!isWeekend(_date, options)) restDays -= 1; |
| 69 | } |
| 70 | |
| 71 | // If the date is a weekend day and we reduce a dividable of |
| 72 | // 5 from it, we land on a weekend date. |
| 73 | // To counter this, we add days accordingly to land on the next business day |
| 74 | if (startedOnWeekend && isWeekend(_date, options) && amount !== 0) { |
| 75 | // If we're reducing days, we want to add days until we land on a weekday |
| 76 | // If we're adding days we want to reduce days until we land on a weekday |
| 77 | if (isSaturday(_date, options)) |
| 78 | _date.setDate(_date.getDate() + (sign < 0 ? 2 : -1)); |
| 79 | if (isSunday(_date, options)) |
| 80 | _date.setDate(_date.getDate() + (sign < 0 ? 1 : -2)); |
| 81 | } |
| 82 | |
| 83 | // Restore hours to avoid DST lag |
| 84 | _date.setHours(hours); |
| 85 | |
| 86 | return _date; |
| 87 | } |
no test coverage detected