addBusinessDays.mjs 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import { constructFrom } from "./constructFrom.mjs";
  2. import { isSaturday } from "./isSaturday.mjs";
  3. import { isSunday } from "./isSunday.mjs";
  4. import { isWeekend } from "./isWeekend.mjs";
  5. import { toDate } from "./toDate.mjs";
  6. /**
  7. * @name addBusinessDays
  8. * @category Date Extension Helpers
  9. * @summary Add the specified number of business days (mon - fri) to the given date.
  10. *
  11. * @description
  12. * Add the specified number of business days (mon - fri) to the given date, ignoring weekends.
  13. *
  14. * @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).
  15. *
  16. * @param date - The date to be changed
  17. * @param amount - The amount of business days to be added.
  18. *
  19. * @returns The new date with the business days added
  20. *
  21. * @example
  22. * // Add 10 business days to 1 September 2014:
  23. * const result = addBusinessDays(new Date(2014, 8, 1), 10)
  24. * //=> Mon Sep 15 2014 00:00:00 (skipped weekend days)
  25. */
  26. export function addBusinessDays(date, amount) {
  27. const _date = toDate(date);
  28. const startedOnWeekend = isWeekend(_date);
  29. if (isNaN(amount)) return constructFrom(date, NaN);
  30. const hours = _date.getHours();
  31. const sign = amount < 0 ? -1 : 1;
  32. const fullWeeks = Math.trunc(amount / 5);
  33. _date.setDate(_date.getDate() + fullWeeks * 7);
  34. // Get remaining days not part of a full week
  35. let restDays = Math.abs(amount % 5);
  36. // Loops over remaining days
  37. while (restDays > 0) {
  38. _date.setDate(_date.getDate() + sign);
  39. if (!isWeekend(_date)) restDays -= 1;
  40. }
  41. // If the date is a weekend day and we reduce a dividable of
  42. // 5 from it, we land on a weekend date.
  43. // To counter this, we add days accordingly to land on the next business day
  44. if (startedOnWeekend && isWeekend(_date) && amount !== 0) {
  45. // If we're reducing days, we want to add days until we land on a weekday
  46. // If we're adding days we want to reduce days until we land on a weekday
  47. if (isSaturday(_date)) _date.setDate(_date.getDate() + (sign < 0 ? 2 : -1));
  48. if (isSunday(_date)) _date.setDate(_date.getDate() + (sign < 0 ? 1 : -2));
  49. }
  50. // Restore hours to avoid DST lag
  51. _date.setHours(hours);
  52. return _date;
  53. }
  54. // Fallback for modularized imports:
  55. export default addBusinessDays;