@alanszp/business-days-date-fns 4.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/.eslintrc.js +93 -0
  2. package/.gitignore +3 -0
  3. package/.npmignore +3 -0
  4. package/LICENSE +21 -0
  5. package/README.MD +51 -0
  6. package/babel.config.js +7 -0
  7. package/dist/cache/index.d.ts +1 -0
  8. package/dist/cache/index.js +17 -0
  9. package/dist/cache/index.js.map +1 -0
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.js +6 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/utils/addBusinessDays.d.ts +1 -0
  14. package/dist/utils/addBusinessDays.js +42 -0
  15. package/dist/utils/addBusinessDays.js.map +1 -0
  16. package/dist/utils/addBusinessDays.test.d.ts +1 -0
  17. package/dist/utils/addBusinessDays.test.js +94 -0
  18. package/dist/utils/addBusinessDays.test.js.map +1 -0
  19. package/dist/utils/differenceInBusinessDay.test.d.ts +1 -0
  20. package/dist/utils/differenceInBusinessDay.test.js +96 -0
  21. package/dist/utils/differenceInBusinessDay.test.js.map +1 -0
  22. package/dist/utils/differenceInBusinessDays.d.ts +1 -0
  23. package/dist/utils/differenceInBusinessDays.js +34 -0
  24. package/dist/utils/differenceInBusinessDays.js.map +1 -0
  25. package/dist/utils/isBusinessDay.d.ts +1 -0
  26. package/dist/utils/isBusinessDay.js +16 -0
  27. package/dist/utils/isBusinessDay.js.map +1 -0
  28. package/dist/utils/isBusinessDay.test.d.ts +1 -0
  29. package/dist/utils/isBusinessDay.test.js +34 -0
  30. package/dist/utils/isBusinessDay.test.js.map +1 -0
  31. package/dist/utils/isNonBusinessDay.d.ts +1 -0
  32. package/dist/utils/isNonBusinessDay.js +17 -0
  33. package/dist/utils/isNonBusinessDay.js.map +1 -0
  34. package/dist/utils/isNonBusinessDay.test.d.ts +1 -0
  35. package/dist/utils/isNonBusinessDay.test.js +52 -0
  36. package/dist/utils/isNonBusinessDay.test.js.map +1 -0
  37. package/dist/utils/requiredArgs.d.ts +1 -0
  38. package/dist/utils/requiredArgs.js +10 -0
  39. package/dist/utils/requiredArgs.js.map +1 -0
  40. package/dist/utils/subBusinessDays.d.ts +1 -0
  41. package/dist/utils/subBusinessDays.js +14 -0
  42. package/dist/utils/subBusinessDays.js.map +1 -0
  43. package/dist/utils/subBusinessDays.test.d.ts +1 -0
  44. package/dist/utils/subBusinessDays.test.js +69 -0
  45. package/dist/utils/subBusinessDays.test.js.map +1 -0
  46. package/dist/utils/withNonBusinessDays.d.ts +11 -0
  47. package/dist/utils/withNonBusinessDays.js +45 -0
  48. package/dist/utils/withNonBusinessDays.js.map +1 -0
  49. package/dist/utils/withNonBusinessDays.test.d.ts +1 -0
  50. package/dist/utils/withNonBusinessDays.test.js +73 -0
  51. package/dist/utils/withNonBusinessDays.test.js.map +1 -0
  52. package/dist/utils/wrapperNonBusinessDays.d.ts +3 -0
  53. package/dist/utils/wrapperNonBusinessDays.js +70 -0
  54. package/dist/utils/wrapperNonBusinessDays.js.map +1 -0
  55. package/header.png +0 -0
  56. package/jest.config.js +10 -0
  57. package/package.json +39 -0
  58. package/src/cache/index.ts +13 -0
  59. package/src/index.ts +1 -0
  60. package/src/utils/addBusinessDays.test.ts +131 -0
  61. package/src/utils/addBusinessDays.ts +46 -0
  62. package/src/utils/differenceInBusinessDay.test.ts +176 -0
  63. package/src/utils/differenceInBusinessDays.ts +37 -0
  64. package/src/utils/isBusinessDay.test.ts +47 -0
  65. package/src/utils/isBusinessDay.ts +18 -0
  66. package/src/utils/isNonBusinessDay.test.ts +69 -0
  67. package/src/utils/isNonBusinessDay.ts +17 -0
  68. package/src/utils/requiredArgs.ts +5 -0
  69. package/src/utils/subBusinessDays.test.ts +99 -0
  70. package/src/utils/subBusinessDays.ts +10 -0
  71. package/src/utils/withNonBusinessDays.test.ts +82 -0
  72. package/src/utils/withNonBusinessDays.ts +87 -0
  73. package/src/utils/wrapperNonBusinessDays.ts +78 -0
  74. package/tsconfig.json +15 -0
@@ -0,0 +1,131 @@
1
+ import assert from "assert";
2
+ import { addBusinessDays } from "./addBusinessDays";
3
+
4
+ describe("addBusinessDays", () => {
5
+ it("should return 2 next days", () => {
6
+ const result = addBusinessDays(
7
+ [new Date("2022-01-20")],
8
+ new Date("2022-01-19"),
9
+ 1
10
+ );
11
+ expect(result).toEqual(new Date("2022-01-21"));
12
+ });
13
+
14
+ it("should return next monday", () => {
15
+ const result = addBusinessDays(
16
+ [new Date("2022-01-20"), new Date("2022-01-21")],
17
+ new Date("2022-01-19"),
18
+ 1
19
+ );
20
+ expect(result).toEqual(new Date("2022-01-24"));
21
+ });
22
+
23
+ it("should return next monday when you start on weekend", () => {
24
+ const result = addBusinessDays([], new Date("2022-01-21"), 1);
25
+ expect(result).toEqual(new Date("2022-01-24"));
26
+ });
27
+
28
+ // original tests
29
+
30
+ it("adds the given number of business days", () => {
31
+ const result = addBusinessDays([], new Date(2014, 8 /* Sep */, 1), 10);
32
+ expect(result).toEqual(new Date(2014, 8 /* Sep */, 15));
33
+ });
34
+
35
+ it("handles negative amount", () => {
36
+ const result = addBusinessDays([], new Date(2014, 8 /* Sep */, 15), -10);
37
+ expect(result).toEqual(new Date(2014, 8 /* Sep */, 1));
38
+ });
39
+
40
+ it("returns the Monday when 1 day is added on the Friday", () => {
41
+ expect(
42
+ addBusinessDays([], new Date(2020, 0 /* Jan */, 10), 1) // Friday
43
+ ).toEqual(
44
+ new Date(2020, 0 /* Jan */, 13) // Monday
45
+ );
46
+ });
47
+
48
+ it("returns the Monday when 1 day is added on the Saturday", () => {
49
+ expect(
50
+ addBusinessDays([], new Date(2020, 0 /* Jan */, 11), 1) // Saturday
51
+ ).toEqual(
52
+ new Date(2020, 0 /* Jan */, 13) // Monday
53
+ );
54
+ });
55
+
56
+ it("returns the Monday when 1 day is added on the Sunday", () => {
57
+ expect(
58
+ addBusinessDays([], new Date(2020, 0 /* Jan */, 12), 1) // Sunday
59
+ ).toEqual(
60
+ new Date(2020, 0 /* Jan */, 13) // Monday
61
+ );
62
+ });
63
+
64
+ it("can handle a large number of business days", () => {
65
+ // @ts-ignore
66
+ if (typeof global.timeout === "function") {
67
+ // @ts-ignore
68
+ global.timeout(500 /* 500 ms test timeout */);
69
+ }
70
+
71
+ const result = addBusinessDays([], new Date(2014, 0 /* Jan */, 1), 3387885);
72
+ expect(result).toEqual(new Date(15000, 0 /* Jan */, 1));
73
+ });
74
+
75
+ it("accepts a timestamp", () => {
76
+ const result = addBusinessDays(
77
+ [],
78
+ new Date(2014, 8 /* Sep */, 1).getTime(),
79
+ 10
80
+ );
81
+ expect(result).toEqual(new Date(2014, 8 /* Sep */, 15));
82
+ });
83
+
84
+ it("converts a fractional number to an integer", () => {
85
+ const result = addBusinessDays([], new Date(2014, 8 /* Sep */, 1), 10.5);
86
+ expect(result).toEqual(new Date(2014, 8 /* Sep */, 15));
87
+ });
88
+
89
+ it("implicitly converts number arguments", () => {
90
+ // @ts-ignore
91
+ const result = addBusinessDays([], new Date(2014, 8 /* Sep */, 1), "10");
92
+ expect(result).toEqual(new Date(2014, 8 /* Sep */, 15));
93
+ });
94
+
95
+ it("does not mutate the original date", () => {
96
+ const date = new Date(2014, 8 /* Sep */, 1);
97
+ addBusinessDays([], date, 11);
98
+ expect(date).toEqual(new Date(2014, 8 /* Sep */, 1));
99
+ });
100
+
101
+ it("returns `Invalid Date` if the given date is invalid", () => {
102
+ const result = addBusinessDays([], new Date(NaN), 10);
103
+ assert(result instanceof Date && Number.isNaN(result.getTime()));
104
+ });
105
+
106
+ it("throws TypeError exception if passed less than 2 arguments", () => {
107
+ try {
108
+ assert.throws(addBusinessDays.bind(null), TypeError);
109
+
110
+ assert.throws(addBusinessDays.bind(null, 1), TypeError);
111
+ } catch {}
112
+ });
113
+
114
+ it("starting from a weekend day should land on a weekday when reducing a divisible by 5", () => {
115
+ const substractResult = addBusinessDays([], new Date(2019, 7, 18), -5);
116
+ expect(substractResult).toEqual(new Date(2019, 7, 12));
117
+
118
+ const subtractResultWeekend = addBusinessDays(
119
+ [],
120
+ new Date(2019, 7, 17),
121
+ -5
122
+ );
123
+ expect(subtractResultWeekend).toEqual(new Date(2019, 7, 12));
124
+
125
+ const addResult = addBusinessDays([], new Date(2019, 7, 18), 5);
126
+ expect(addResult).toEqual(new Date(2019, 7, 23));
127
+
128
+ const addResultWeekend = addBusinessDays([], new Date(2019, 7, 17), 5);
129
+ expect(addResultWeekend).toEqual(new Date(2019, 7, 23));
130
+ });
131
+ });
@@ -0,0 +1,46 @@
1
+ import toDate from "date-fns/toDate";
2
+ import isSunday from "date-fns/isSunday";
3
+ import isSaturday from "date-fns/isSaturday";
4
+ import { toInteger } from "lodash";
5
+ import { isNonBusinessDay } from "./isNonBusinessDay";
6
+ import { requiredArgs } from "./requiredArgs";
7
+
8
+ export function addBusinessDays(
9
+ nonBusinessDays: Date[],
10
+ dirtyDate: Date | number,
11
+ dirtyAmount: number
12
+ ): Date {
13
+ requiredArgs(2, [dirtyDate, dirtyAmount]);
14
+
15
+ const date = toDate(dirtyDate);
16
+ const startedOnWeekend = isNonBusinessDay(nonBusinessDays, date);
17
+ const amount = toInteger(dirtyAmount);
18
+
19
+ if (Number.isNaN(amount)) return new Date(Number.NaN);
20
+
21
+ const hours = date.getHours();
22
+ const sign = amount < 0 ? -1 : 1;
23
+ const fullWeeks = toInteger(amount / 5);
24
+
25
+ date.setDate(date.getDate() + fullWeeks * 7);
26
+
27
+ let restDays = Math.abs(amount % 5);
28
+
29
+ while (restDays > 0) {
30
+ date.setDate(date.getDate() + sign);
31
+ if (!isNonBusinessDay(nonBusinessDays, date)) restDays -= 1;
32
+ }
33
+
34
+ if (
35
+ startedOnWeekend &&
36
+ isNonBusinessDay(nonBusinessDays, date) &&
37
+ amount !== 0
38
+ ) {
39
+ if (isSaturday(date)) date.setDate(date.getDate() + (sign < 0 ? 2 : -1));
40
+ if (isSunday(date)) date.setDate(date.getDate() + (sign < 0 ? 1 : -2));
41
+ }
42
+
43
+ date.setHours(hours);
44
+
45
+ return date;
46
+ }
@@ -0,0 +1,176 @@
1
+ import assert from "assert";
2
+ import { differenceInBusinessDays } from "./differenceInBusinessDays";
3
+
4
+ describe("differenceInBusinessDays", () => {
5
+ it("should return 2 difference day taking weekend days", () => {
6
+ const result = differenceInBusinessDays(
7
+ [new Date("2022-01-20"), new Date("2022-01-21")],
8
+ new Date("2022-01-25"),
9
+ new Date("2022-01-19")
10
+ );
11
+ expect(result).toBe(2);
12
+ });
13
+
14
+ it("should return 2 difference", () => {
15
+ const result = differenceInBusinessDays(
16
+ [new Date("2022-01-19")],
17
+ new Date("2022-01-21"),
18
+ new Date("2022-01-18")
19
+ );
20
+ expect(result).toBe(2);
21
+ });
22
+
23
+ // date-fns original tests
24
+
25
+ it("returns the number of business days between the given dates, excluding weekends", () => {
26
+ const result = differenceInBusinessDays(
27
+ [],
28
+ new Date(2014, 6 /* Jul */, 18),
29
+ new Date(2014, 0 /* Jan */, 10)
30
+ );
31
+ expect(result).toEqual(135);
32
+ });
33
+
34
+ it("can handle long ranges", () => {
35
+ // @ts-ignore
36
+ if (typeof global.timeout === "function") {
37
+ // @ts-ignore
38
+ global.timeout(500 /* 500 ms test timeout */);
39
+ }
40
+
41
+ const result = differenceInBusinessDays(
42
+ [],
43
+ new Date(15000, 0 /* Jan */, 1),
44
+ new Date(2014, 0 /* Jan */, 1)
45
+ );
46
+ expect(result).toEqual(3387885);
47
+ });
48
+
49
+ it("the same except given first date falls on a weekend", () => {
50
+ const result = differenceInBusinessDays(
51
+ [],
52
+ new Date(2019, 6 /* Jul */, 20),
53
+ new Date(2019, 6 /* Jul */, 18)
54
+ );
55
+ expect(result).toEqual(2);
56
+ });
57
+
58
+ it("the same except given second date falls on a weekend", () => {
59
+ const result = differenceInBusinessDays(
60
+ [],
61
+ new Date(2019, 6 /* Jul */, 23),
62
+ new Date(2019, 6 /* Jul */, 20)
63
+ );
64
+ expect(result).toEqual(1);
65
+ });
66
+
67
+ it("the same except both given dates fall on a weekend", () => {
68
+ const result = differenceInBusinessDays(
69
+ [],
70
+ new Date(2019, 6 /* Jul */, 28),
71
+ new Date(2019, 6 /* Jul */, 20)
72
+ );
73
+ expect(result).toEqual(5);
74
+ });
75
+
76
+ it("returns a negative number if the time value of the first date is smaller", () => {
77
+ const result = differenceInBusinessDays(
78
+ [],
79
+ new Date(2014, 0 /* Jan */, 10),
80
+ new Date(2014, 6 /* Jul */, 20)
81
+ );
82
+ expect(result).toEqual(-135);
83
+ });
84
+
85
+ it("accepts timestamps", () => {
86
+ const result = differenceInBusinessDays(
87
+ [],
88
+ new Date(2014, 6, 18).getTime(),
89
+ new Date(2014, 0, 10).getTime()
90
+ );
91
+ expect(result).toEqual(135);
92
+ });
93
+
94
+ it("the difference is less than a day, but the given dates are in different calendar days", () => {
95
+ const result = differenceInBusinessDays(
96
+ [],
97
+ new Date(2014, 8 /* Sep */, 5, 0, 0),
98
+ new Date(2014, 8 /* Sep */, 4, 23, 59)
99
+ );
100
+ expect(result).toEqual(1);
101
+ });
102
+
103
+ it("the same for the swapped dates", () => {
104
+ const result = differenceInBusinessDays(
105
+ [],
106
+ new Date(2014, 8 /* Sep */, 4, 23, 59),
107
+ new Date(2014, 8 /* Sep */, 5, 0, 0)
108
+ );
109
+ expect(result).toEqual(-1);
110
+ });
111
+
112
+ it("the time values of the given dates are the same", () => {
113
+ const result = differenceInBusinessDays(
114
+ [],
115
+ new Date(2014, 8 /* Sep */, 5, 0, 0),
116
+ new Date(2014, 8 /* Sep */, 4, 0, 0)
117
+ );
118
+ expect(result).toEqual(1);
119
+ });
120
+
121
+ it("the given dates are the same", () => {
122
+ const result = differenceInBusinessDays(
123
+ [],
124
+ new Date(2014, 8 /* Sep */, 5, 0, 0),
125
+ new Date(2014, 8 /* Sep */, 5, 0, 0)
126
+ );
127
+ expect(result).toEqual(0);
128
+ });
129
+
130
+ it("does not return -0 when the given dates are the same", () => {
131
+ // eslint-disable-next-line unicorn/consistent-function-scoping
132
+ function isNegativeZero(x: number) {
133
+ return x === 0 && 1 / x < 0;
134
+ }
135
+
136
+ const result = differenceInBusinessDays(
137
+ [],
138
+ new Date(2014, 8 /* Sep */, 5, 0, 0),
139
+ new Date(2014, 8 /* Sep */, 5, 0, 0)
140
+ );
141
+
142
+ const resultIsNegative = isNegativeZero(result);
143
+ expect(resultIsNegative).toBeFalsy();
144
+ });
145
+
146
+ it("returns NaN if the first date is `Invalid Date`", () => {
147
+ const result = differenceInBusinessDays(
148
+ [],
149
+ new Date(NaN),
150
+ new Date(2017, 0 /* Jan */, 1)
151
+ );
152
+ expect(Number.isNaN(result)).toBeTruthy();
153
+ });
154
+
155
+ it("returns NaN if the second date is `Invalid Date`", () => {
156
+ const result = differenceInBusinessDays(
157
+ [],
158
+ new Date(2017, 0 /* Jan */, 1),
159
+ new Date(NaN)
160
+ );
161
+ expect(Number.isNaN(result)).toBeTruthy();
162
+ });
163
+
164
+ it("returns NaN if the both dates are `Invalid Date`", () => {
165
+ const result = differenceInBusinessDays([], new Date(NaN), new Date(NaN));
166
+ expect(Number.isNaN(result)).toBeTruthy();
167
+ });
168
+
169
+ it("throws TypeError exception if passed less than 2 arguments", () => {
170
+ try {
171
+ assert.throws(differenceInBusinessDays.bind(null), TypeError);
172
+
173
+ assert.throws(differenceInBusinessDays.bind(null, 1), TypeError);
174
+ } catch {}
175
+ });
176
+ });
@@ -0,0 +1,37 @@
1
+ import differenceInCalendarDays from "date-fns/differenceInCalendarDays";
2
+ import addDays from "date-fns/addDays";
3
+ import isSameDay from "date-fns/isSameDay";
4
+ import isValid from "date-fns/isValid";
5
+ import toInteger from "lodash/toInteger";
6
+ import toDate from "date-fns/toDate";
7
+ import { requiredArgs } from "./requiredArgs";
8
+ import { isNonBusinessDay } from "./isNonBusinessDay";
9
+
10
+ export function differenceInBusinessDays(
11
+ nonBusinessDays: Date[],
12
+ dirtyDateLeft: Date | number,
13
+ dirtyDateRight: Date | number
14
+ ): number {
15
+ // eslint-disable-next-line prefer-rest-params
16
+ requiredArgs(2, [dirtyDateLeft, dirtyDateRight]);
17
+
18
+ const dateLeft = toDate(dirtyDateLeft);
19
+ let dateRight = toDate(dirtyDateRight);
20
+
21
+ if (!isValid(dateLeft) || !isValid(dateRight)) return Number.NaN;
22
+
23
+ const calendarDifference = differenceInCalendarDays(dateLeft, dateRight);
24
+ const sign = calendarDifference < 0 ? -1 : 1;
25
+
26
+ const weeks = toInteger(calendarDifference / 7);
27
+
28
+ let result = weeks * 5;
29
+ dateRight = addDays(dateRight, weeks * 7);
30
+
31
+ while (!isSameDay(dateLeft, dateRight)) {
32
+ result += isNonBusinessDay(nonBusinessDays, dateRight) ? 0 : sign;
33
+ dateRight = addDays(dateRight, sign);
34
+ }
35
+
36
+ return result === 0 ? 0 : result;
37
+ }
@@ -0,0 +1,47 @@
1
+ import assert from "assert";
2
+ import { parse } from "date-fns";
3
+ import { isBusinessDay } from "./isBusinessDay";
4
+
5
+ describe("isNonBusinessDay", () => {
6
+ it("should return is non business day", () => {
7
+ const result = isBusinessDay(
8
+ [new Date("2022-01-01"), new Date("2022-01-02")],
9
+ new Date("2022-01-01")
10
+ );
11
+
12
+ expect(result).toBeFalsy();
13
+ });
14
+
15
+ it("should return is a business day", () => {
16
+ const result = isBusinessDay(
17
+ [new Date("2022-01-01"), new Date("2022-01-02")],
18
+ new Date("2022-01-03")
19
+ );
20
+
21
+ expect(result).toBeTruthy();
22
+ });
23
+
24
+ it("should work properly using hh:mm:ss", () => {
25
+ const mondayLate = isBusinessDay(
26
+ [],
27
+ parse("2022-01-24T23:59:59", "yyyy-MM-dd HH:mm:ss", new Date())
28
+ );
29
+ const fridayLate = isBusinessDay(
30
+ [parse("2022-01-28T23:59:59", "yyyy-MM-dd HH:mm:ss", new Date())],
31
+ parse("2022-01-28T23:59:59", "yyyy-MM-dd HH:mm:ss", new Date())
32
+ );
33
+
34
+ expect(mondayLate).toBeTruthy();
35
+ expect(fridayLate).toBeTruthy();
36
+ });
37
+
38
+ it("throws TypeError exception if passed less than 2 arguments", () => {
39
+ try {
40
+ // @ts-ignore
41
+ isBusinessDay([new Date("2022-01-01"), new Date("2022-01-02")]);
42
+
43
+ assert.throws(isBusinessDay.bind(null), TypeError);
44
+ assert.throws(isBusinessDay.bind(null, 1), TypeError);
45
+ } catch {}
46
+ });
47
+ });
@@ -0,0 +1,18 @@
1
+ import { isWeekend, toDate } from "date-fns";
2
+ import isSameDay from "date-fns/isSameDay";
3
+ import { requiredArgs } from "./requiredArgs";
4
+
5
+ export function isBusinessDay(
6
+ nonBusinessDays: Date[],
7
+ dirtyDate: Date | number
8
+ ): boolean {
9
+ requiredArgs(1, [dirtyDate]);
10
+
11
+ const date = toDate(dirtyDate);
12
+
13
+ return (
14
+ !nonBusinessDays.some((nonBusinessDay) =>
15
+ isSameDay(nonBusinessDay, date)
16
+ ) && !isWeekend(date)
17
+ );
18
+ }
@@ -0,0 +1,69 @@
1
+ import assert from "assert";
2
+ import { parse } from "date-fns";
3
+ import { isNonBusinessDay } from "./isNonBusinessDay";
4
+
5
+ describe("isNonBusinessDay", () => {
6
+ it("should return true because is part of NBD", () => {
7
+ const result = isNonBusinessDay(
8
+ [new Date("2022-01-01"), new Date("2022-01-02")],
9
+ new Date("2022-01-01")
10
+ );
11
+
12
+ expect(result).toBe(true);
13
+ });
14
+
15
+ it("should return true because weekend", () => {
16
+ const saturday = isNonBusinessDay([], new Date("2022-01-01"));
17
+ const sunday = isNonBusinessDay([], new Date("2022-01-02"));
18
+
19
+ expect(saturday).toBeTruthy();
20
+ expect(sunday).toBeTruthy();
21
+ });
22
+
23
+ it("should return false because are part of the week", () => {
24
+ const monday = isNonBusinessDay([], new Date("2022-01-03"));
25
+ const tuesday = isNonBusinessDay([], new Date("2022-01-04"));
26
+ const wednesday = isNonBusinessDay([], new Date("2022-01-05"));
27
+ const thursday = isNonBusinessDay([], new Date("2022-01-06"));
28
+ const friday = isNonBusinessDay([], new Date("2022-01-07"));
29
+
30
+ expect(monday).toBeFalsy();
31
+ expect(tuesday).toBeFalsy();
32
+ expect(wednesday).toBeFalsy();
33
+ expect(thursday).toBeFalsy();
34
+ expect(friday).toBeFalsy();
35
+ });
36
+
37
+ it("should work properly using hh:mm:ss", () => {
38
+ const sundayLate = isNonBusinessDay(
39
+ [],
40
+ parse("2022-01-23T23:59:59", "yyyy-MM-dd HH:mm:ss", new Date())
41
+ );
42
+ const dayOffLate = isNonBusinessDay(
43
+ [parse("2022-01-24T23:59:59", "yyyy-MM-dd HH:mm:ss", new Date())],
44
+ parse("2022-01-24T23:59:59", "yyyy-MM-dd HH:mm:ss", new Date())
45
+ );
46
+
47
+ expect(sundayLate).toBeFalsy();
48
+ expect(dayOffLate).toBeFalsy();
49
+ });
50
+
51
+ it("should return false because is not part of is part of NBD", () => {
52
+ const result = isNonBusinessDay(
53
+ [new Date("2022-01-01"), new Date("2022-01-02")],
54
+ new Date("2022-01-03")
55
+ );
56
+
57
+ expect(result).toBe(false);
58
+ });
59
+
60
+ it("throws TypeError exception if passed less than 2 arguments", () => {
61
+ try {
62
+ // @ts-ignore
63
+ isNonBusinessDay([new Date("2022-01-01"), new Date("2022-01-02")]);
64
+
65
+ assert.throws(isNonBusinessDay.bind(null), TypeError);
66
+ assert.throws(isNonBusinessDay.bind(null, 1), TypeError);
67
+ } catch {}
68
+ });
69
+ });
@@ -0,0 +1,17 @@
1
+ import { isWeekend, toDate } from "date-fns";
2
+ import isSameDay from "date-fns/isSameDay";
3
+ import { requiredArgs } from "./requiredArgs";
4
+
5
+ export function isNonBusinessDay(
6
+ nonBusinessDays: Date[],
7
+ dirtyDate: Date
8
+ ): boolean {
9
+ requiredArgs(1, [dirtyDate]);
10
+
11
+ const date = toDate(dirtyDate);
12
+
13
+ return (
14
+ nonBusinessDays.some((nonBusinessDay) => isSameDay(nonBusinessDay, date)) ||
15
+ isWeekend(date)
16
+ );
17
+ }
@@ -0,0 +1,5 @@
1
+ export function requiredArgs(required: number, args: unknown[]): void {
2
+ if (args.length < required) {
3
+ throw new TypeError(`${required} argument${required > 1 ? "s" : ""} required, but only ${args.length} present`);
4
+ }
5
+ }
@@ -0,0 +1,99 @@
1
+ import assert from "assert";
2
+ import { subBusinessDays } from "./subBusinessDays";
3
+
4
+ describe("subBusinessDay", () => {
5
+ it("should return 2 next days", () => {
6
+ const result = subBusinessDays(
7
+ [new Date("2022-01-20")],
8
+ new Date("2022-01-21"),
9
+ 1
10
+ );
11
+ expect(result).toEqual(new Date("2022-01-19"));
12
+ });
13
+
14
+ it("should return next monday", () => {
15
+ const result = subBusinessDays(
16
+ [new Date("2022-01-20"), new Date("2022-01-21")],
17
+ new Date("2022-01-24"),
18
+ 1
19
+ );
20
+ expect(result).toEqual(new Date("2022-01-19"));
21
+ });
22
+
23
+ it("should return next monday when you start on weekend", () => {
24
+ const result = subBusinessDays([], new Date("2022-01-24"), 1);
25
+ expect(result).toEqual(new Date("2022-01-21"));
26
+ });
27
+
28
+ it("substract the given number of business days", () => {
29
+ const result = subBusinessDays([], new Date(2014, 8 /* Sep */, 1), 10);
30
+ expect(result).toEqual(new Date(2014, 7 /* Aug */, 18));
31
+ });
32
+
33
+ it("handles negative amount", () => {
34
+ const result = subBusinessDays([], new Date(2014, 7 /* Sep */, 18), -10);
35
+ expect(result).toEqual(new Date(2014, 8 /* Sep */, 1));
36
+ });
37
+
38
+ it("can handle a large number of business days", () => {
39
+ // @ts-ignore
40
+ if (typeof global.timeout === "function") {
41
+ // @ts-ignore
42
+ global.timeout(500 /* 500 ms test timeout */);
43
+ }
44
+
45
+ const result = subBusinessDays(
46
+ [],
47
+ new Date(15000, 0 /* Jan */, 1),
48
+ 3387885
49
+ );
50
+ expect(result).toEqual(new Date(2014, 0 /* Jan */, 1));
51
+ });
52
+
53
+ it("accepts a timestamp", () => {
54
+ const result = subBusinessDays(
55
+ [],
56
+ new Date(2014, 8 /* Sep */, 1).getTime(),
57
+ 10
58
+ );
59
+ expect(result).toEqual(new Date(2014, 7 /* Aug */, 18));
60
+ });
61
+
62
+ it("converts a fractional number to an integer", () => {
63
+ const result = subBusinessDays([], new Date(2014, 8 /* Sep */, 1), 10.5);
64
+ expect(result).toEqual(new Date(2014, 7 /* Aug */, 18));
65
+ });
66
+
67
+ it("implicitly converts number arguments", () => {
68
+ const result = subBusinessDays(
69
+ [],
70
+ new Date(2014, 8 /* Sep */, 1),
71
+ // @ts-ignore
72
+ "10"
73
+ );
74
+ expect(result).toEqual(new Date(2014, 7 /* Aug */, 18));
75
+ });
76
+
77
+ it("does not mutate the original date", () => {
78
+ const date = new Date(2014, 8 /* Sep */, 1);
79
+ subBusinessDays([], date, 11);
80
+ expect(date).toEqual(new Date(2014, 8 /* Sep */, 1));
81
+ });
82
+
83
+ it("returns `Invalid Date` if the given date is invalid", () => {
84
+ const result = subBusinessDays([], new Date(NaN), 10);
85
+ expect(
86
+ result instanceof Date && Number.isNaN(result.getTime())
87
+ ).toBeTruthy();
88
+ });
89
+
90
+ it("throws TypeError exception if passed less than 2 arguments", () => {
91
+ try {
92
+ assert.throws(subBusinessDays.bind(null), TypeError);
93
+ assert.throws(
94
+ subBusinessDays.bind(null, new Date(2014, 8 /* Sep */, 1)),
95
+ TypeError
96
+ );
97
+ } catch {}
98
+ });
99
+ });
@@ -0,0 +1,10 @@
1
+ import { toInteger } from "lodash";
2
+ import { addBusinessDays } from "./addBusinessDays";
3
+ import { requiredArgs } from "./requiredArgs";
4
+
5
+ export function subBusinessDays(nonBusinessDays: Date[], dirtyDate: Date | number, dirtyAmount: number): Date {
6
+ // eslint-disable-next-line prefer-rest-params
7
+ requiredArgs(2, [dirtyDate, dirtyAmount]);
8
+ const amount = toInteger(dirtyAmount);
9
+ return addBusinessDays(nonBusinessDays, dirtyDate, -amount);
10
+ }