UNPKG

2.64 kBJavaScriptView Raw
1import { constructFrom } from "./constructFrom.js";
2import { isSaturday } from "./isSaturday.js";
3import { isSunday } from "./isSunday.js";
4import { isWeekend } from "./isWeekend.js";
5import { toDate } from "./toDate.js";
6
7/**
8 * The {@link addBusinessDays} function options.
9 */
10
11/**
12 * @name addBusinessDays
13 * @category Day Helpers
14 * @summary Add the specified number of business days (mon - fri) to the given date.
15 *
16 * @description
17 * Add the specified number of business days (mon - fri) to the given date, ignoring weekends.
18 *
19 * @typeParam DateType - The `Date` type, the function operates on. Gets inferred from passed arguments. Allows to use extensions like [`UTCDate`](https://github.com/date-fns/utc).
20 * @typeParam ResultDate - The result `Date` type, it is the type returned from the context function if it is passed, or inferred from the arguments.
21 *
22 * @param date - The date to be changed
23 * @param amount - The amount of business days to be added.
24 * @param options - An object with options
25 *
26 * @returns The new date with the business days added
27 *
28 * @example
29 * // Add 10 business days to 1 September 2014:
30 * const result = addBusinessDays(new Date(2014, 8, 1), 10)
31 * //=> Mon Sep 15 2014 00:00:00 (skipped weekend days)
32 */
33export function addBusinessDays(date, amount, options) {
34 const _date = toDate(date, options?.in);
35 const startedOnWeekend = isWeekend(_date, options);
36
37 if (isNaN(amount)) return constructFrom(options?.in, NaN);
38
39 const hours = _date.getHours();
40 const sign = amount < 0 ? -1 : 1;
41 const fullWeeks = Math.trunc(amount / 5);
42
43 _date.setDate(_date.getDate() + fullWeeks * 7);
44
45 // Get remaining days not part of a full week
46 let restDays = Math.abs(amount % 5);
47
48 // Loops over remaining days
49 while (restDays > 0) {
50 _date.setDate(_date.getDate() + sign);
51 if (!isWeekend(_date, options)) restDays -= 1;
52 }
53
54 // If the date is a weekend day and we reduce a dividable of
55 // 5 from it, we land on a weekend date.
56 // To counter this, we add days accordingly to land on the next business day
57 if (startedOnWeekend && isWeekend(_date, options) && amount !== 0) {
58 // If we're reducing days, we want to add days until we land on a weekday
59 // If we're adding days we want to reduce days until we land on a weekday
60 if (isSaturday(_date, options))
61 _date.setDate(_date.getDate() + (sign < 0 ? 2 : -1));
62 if (isSunday(_date, options))
63 _date.setDate(_date.getDate() + (sign < 0 ? 1 : -2));
64 }
65
66 // Restore hours to avoid DST lag
67 _date.setHours(hours);
68
69 return _date;
70}
71
72// Fallback for modularized imports:
73export default addBusinessDays;