@f-o-t/datetime 0.1.0

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.
@@ -0,0 +1,167 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { InvalidDateError } from "../errors";
3
+ import type { DateInput } from "../types";
4
+ import { DateTime } from "./datetime";
5
+ import { datetime } from "./factory";
6
+
7
+ describe("datetime factory function", () => {
8
+ describe("basic usage", () => {
9
+ test("creates DateTime instance without arguments (current time)", () => {
10
+ const dt = datetime();
11
+ expect(dt).toBeInstanceOf(DateTime);
12
+ expect(dt.isValid()).toBe(true);
13
+
14
+ // Should be close to current time (within 100ms)
15
+ const now = Date.now();
16
+ expect(Math.abs(dt.valueOf() - now)).toBeLessThan(100);
17
+ });
18
+
19
+ test("creates DateTime from Date object", () => {
20
+ const date = new Date("2024-01-15T10:30:00Z");
21
+ const dt = datetime(date);
22
+
23
+ expect(dt).toBeInstanceOf(DateTime);
24
+ expect(dt.isValid()).toBe(true);
25
+ expect(dt.toISO()).toBe("2024-01-15T10:30:00.000Z");
26
+ });
27
+
28
+ test("creates DateTime from ISO string", () => {
29
+ const dt = datetime("2024-01-15T10:30:00Z");
30
+
31
+ expect(dt).toBeInstanceOf(DateTime);
32
+ expect(dt.isValid()).toBe(true);
33
+ expect(dt.toISO()).toBe("2024-01-15T10:30:00.000Z");
34
+ });
35
+
36
+ test("creates DateTime from timestamp", () => {
37
+ const timestamp = 1705315800000; // 2024-01-15T10:30:00Z
38
+ const dt = datetime(timestamp);
39
+
40
+ expect(dt).toBeInstanceOf(DateTime);
41
+ expect(dt.isValid()).toBe(true);
42
+ expect(dt.valueOf()).toBe(timestamp);
43
+ });
44
+
45
+ test("creates DateTime from another DateTime", () => {
46
+ const dt1 = datetime("2024-01-15T10:30:00Z");
47
+ const dt2 = datetime(dt1);
48
+
49
+ expect(dt2).toBeInstanceOf(DateTime);
50
+ expect(dt2.isValid()).toBe(true);
51
+ expect(dt2.toISO()).toBe(dt1.toISO());
52
+ expect(dt2.valueOf()).toBe(dt1.valueOf());
53
+ });
54
+ });
55
+
56
+ describe("edge cases", () => {
57
+ test("creates invalid DateTime from invalid date string", () => {
58
+ const dt = datetime("invalid");
59
+
60
+ expect(dt).toBeInstanceOf(DateTime);
61
+ expect(dt.isValid()).toBe(false);
62
+ });
63
+
64
+ test("creates invalid DateTime from NaN", () => {
65
+ const dt = datetime(NaN);
66
+
67
+ expect(dt).toBeInstanceOf(DateTime);
68
+ expect(dt.isValid()).toBe(false);
69
+ });
70
+
71
+ test("creates invalid DateTime from invalid Date object", () => {
72
+ const dt = datetime(new Date("invalid"));
73
+
74
+ expect(dt).toBeInstanceOf(DateTime);
75
+ expect(dt.isValid()).toBe(false);
76
+ });
77
+
78
+ test("throws InvalidDateError for non-DateInput types", () => {
79
+ expect(() => datetime({} as any)).toThrow(InvalidDateError);
80
+ expect(() => datetime([] as any)).toThrow(InvalidDateError);
81
+ expect(() => datetime(true as any)).toThrow(InvalidDateError);
82
+ expect(() => datetime(null as any)).toThrow(InvalidDateError);
83
+ });
84
+ });
85
+
86
+ describe("immutability", () => {
87
+ test("creates independent instances", () => {
88
+ const dt1 = datetime("2024-01-15T10:30:00Z");
89
+ const dt2 = datetime(dt1);
90
+ const dt3 = dt2.addDays(1);
91
+
92
+ expect(dt1.toISO()).toBe("2024-01-15T10:30:00.000Z");
93
+ expect(dt2.toISO()).toBe("2024-01-15T10:30:00.000Z");
94
+ expect(dt3.toISO()).toBe("2024-01-16T10:30:00.000Z");
95
+ });
96
+
97
+ test("does not mutate input Date object", () => {
98
+ const date = new Date("2024-01-15T10:30:00Z");
99
+ const originalTime = date.getTime();
100
+ const dt = datetime(date);
101
+
102
+ dt.addDays(1);
103
+
104
+ expect(date.getTime()).toBe(originalTime);
105
+ });
106
+ });
107
+
108
+ describe("equivalence to constructor", () => {
109
+ test("produces same result as constructor", () => {
110
+ const inputs: Array<DateInput | undefined> = [
111
+ undefined,
112
+ new Date("2024-01-15T10:30:00Z"),
113
+ "2024-01-15T10:30:00Z",
114
+ 1705315800000,
115
+ ];
116
+
117
+ for (const input of inputs) {
118
+ const factory = datetime(input);
119
+ const constructor = new DateTime(input);
120
+
121
+ expect(factory.valueOf()).toBe(constructor.valueOf());
122
+ expect(factory.isValid()).toBe(constructor.isValid());
123
+ }
124
+ });
125
+
126
+ test("throws same errors as constructor", () => {
127
+ const invalidInputs = [{}, [], true, null];
128
+
129
+ for (const input of invalidInputs) {
130
+ expect(() => datetime(input as any)).toThrow(InvalidDateError);
131
+ expect(() => new DateTime(input as any)).toThrow(InvalidDateError);
132
+ }
133
+ });
134
+ });
135
+
136
+ describe("chaining", () => {
137
+ test("can chain operations after factory creation", () => {
138
+ const dt = datetime("2024-01-15T10:30:00Z")
139
+ .addDays(5)
140
+ .addHours(3)
141
+ .subtractMinutes(15);
142
+
143
+ expect(dt.toISO()).toBe("2024-01-20T13:15:00.000Z");
144
+ });
145
+
146
+ test("can use comparison methods", () => {
147
+ const dt1 = datetime("2024-01-15T10:30:00Z");
148
+ const dt2 = datetime("2024-01-16T10:30:00Z");
149
+
150
+ expect(dt1.isBefore(dt2)).toBe(true);
151
+ expect(dt2.isAfter(dt1)).toBe(true);
152
+ expect(dt1.isSame(dt1)).toBe(true);
153
+ });
154
+
155
+ test("can use getter methods", () => {
156
+ const dt = datetime("2024-01-15T10:30:45.123Z");
157
+
158
+ expect(dt.year()).toBe(2024);
159
+ expect(dt.month()).toBe(0); // January is 0
160
+ expect(dt.date()).toBe(15);
161
+ expect(dt.hour()).toBe(10);
162
+ expect(dt.minute()).toBe(30);
163
+ expect(dt.second()).toBe(45);
164
+ expect(dt.millisecond()).toBe(123);
165
+ });
166
+ });
167
+ });
@@ -0,0 +1,32 @@
1
+ import type { DateInput } from "../types.ts";
2
+ import { DateTime } from "./datetime.ts";
3
+
4
+ /**
5
+ * Factory function to create a DateTime instance
6
+ * Provides a convenient alternative to using the constructor
7
+ *
8
+ * @param input - Date input (Date, ISO string, timestamp, DateTime, or undefined for current time)
9
+ * @returns A new DateTime instance
10
+ * @throws {InvalidDateError} When input fails validation
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * // Create with current time
15
+ * const now = datetime();
16
+ *
17
+ * // Create from Date object
18
+ * const dt1 = datetime(new Date());
19
+ *
20
+ * // Create from ISO string
21
+ * const dt2 = datetime("2024-01-15T10:30:00Z");
22
+ *
23
+ * // Create from timestamp
24
+ * const dt3 = datetime(1705315800000);
25
+ *
26
+ * // Create from another DateTime
27
+ * const dt4 = datetime(dt1);
28
+ * ```
29
+ */
30
+ export function datetime(input?: DateInput): DateTime {
31
+ return new DateTime(input);
32
+ }
package/src/errors.ts ADDED
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Base error class for all DateTime-related errors
3
+ */
4
+ export class DateTimeError extends Error {
5
+ constructor(message: string) {
6
+ super(message);
7
+ this.name = "DateTimeError";
8
+ // Maintains proper stack trace for where our error was thrown (only available on V8)
9
+ if (Error.captureStackTrace) {
10
+ Error.captureStackTrace(this, this.constructor);
11
+ }
12
+ }
13
+ }
14
+
15
+ /**
16
+ * Error thrown when an invalid date is provided
17
+ */
18
+ export class InvalidDateError extends DateTimeError {
19
+ constructor(
20
+ message = "Invalid date",
21
+ public readonly input?: unknown,
22
+ ) {
23
+ super(message);
24
+ this.name = "InvalidDateError";
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Error thrown when a date string doesn't match the expected format
30
+ */
31
+ export class InvalidFormatError extends DateTimeError {
32
+ constructor(
33
+ message: string,
34
+ public readonly input?: string,
35
+ public readonly expectedFormat?: string,
36
+ ) {
37
+ super(message);
38
+ this.name = "InvalidFormatError";
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Error thrown when an invalid timezone is specified
44
+ */
45
+ export class InvalidTimezoneError extends DateTimeError {
46
+ constructor(
47
+ message: string,
48
+ public readonly timezone?: string,
49
+ ) {
50
+ super(message);
51
+ this.name = "InvalidTimezoneError";
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Error thrown when a plugin operation fails
57
+ */
58
+ export class PluginError extends DateTimeError {
59
+ constructor(
60
+ message: string,
61
+ public readonly pluginName?: string,
62
+ ) {
63
+ super(message);
64
+ this.name = "PluginError";
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Error thrown when attempting to use functionality that requires a plugin that isn't installed
70
+ */
71
+ export class MissingPluginError extends PluginError {
72
+ constructor(
73
+ public readonly requiredPlugin: string,
74
+ message?: string,
75
+ ) {
76
+ super(
77
+ message || `Missing required plugin: ${requiredPlugin}`,
78
+ requiredPlugin,
79
+ );
80
+ this.name = "MissingPluginError";
81
+ }
82
+ }
package/src/index.ts ADDED
@@ -0,0 +1,20 @@
1
+ // Core exports
2
+ export { DateTime } from "./core/datetime.ts";
3
+ export { datetime } from "./core/factory.ts";
4
+ // Error exports
5
+ export { InvalidDateError, PluginError } from "./errors.ts";
6
+ // Plugin utilities
7
+ export { createPlugin, isPlugin, isValidPluginName } from "./plugins/index.ts";
8
+
9
+ // Schema exports
10
+ export { DateInputSchema } from "./schemas.ts";
11
+ // Type exports
12
+ export type {
13
+ DateInput,
14
+ DateTimeClass,
15
+ DateTimeConfig,
16
+ DateTimePlugin,
17
+ FormatOptions,
18
+ ParseOptions,
19
+ TimeUnit,
20
+ } from "./types.ts";
@@ -0,0 +1,225 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import { DateTime } from "../../core/datetime";
3
+ import { businessDaysPlugin } from "./index";
4
+
5
+ describe("Business Days Plugin", () => {
6
+ // Install plugin before running tests
7
+ DateTime.extend(businessDaysPlugin);
8
+
9
+ describe("isWeekday()", () => {
10
+ it("should return true for Monday", () => {
11
+ // 2024-01-15 is a Monday
12
+ const dt = new DateTime("2024-01-15T12:00:00.000Z");
13
+ expect((dt as any).isWeekday()).toBe(true);
14
+ });
15
+
16
+ it("should return true for Tuesday", () => {
17
+ // 2024-01-16 is a Tuesday
18
+ const dt = new DateTime("2024-01-16T12:00:00.000Z");
19
+ expect((dt as any).isWeekday()).toBe(true);
20
+ });
21
+
22
+ it("should return true for Wednesday", () => {
23
+ // 2024-01-17 is a Wednesday
24
+ const dt = new DateTime("2024-01-17T12:00:00.000Z");
25
+ expect((dt as any).isWeekday()).toBe(true);
26
+ });
27
+
28
+ it("should return true for Thursday", () => {
29
+ // 2024-01-18 is a Thursday
30
+ const dt = new DateTime("2024-01-18T12:00:00.000Z");
31
+ expect((dt as any).isWeekday()).toBe(true);
32
+ });
33
+
34
+ it("should return true for Friday", () => {
35
+ // 2024-01-19 is a Friday
36
+ const dt = new DateTime("2024-01-19T12:00:00.000Z");
37
+ expect((dt as any).isWeekday()).toBe(true);
38
+ });
39
+
40
+ it("should return false for Saturday", () => {
41
+ // 2024-01-20 is a Saturday
42
+ const dt = new DateTime("2024-01-20T12:00:00.000Z");
43
+ expect((dt as any).isWeekday()).toBe(false);
44
+ });
45
+
46
+ it("should return false for Sunday", () => {
47
+ // 2024-01-21 is a Sunday
48
+ const dt = new DateTime("2024-01-21T12:00:00.000Z");
49
+ expect((dt as any).isWeekday()).toBe(false);
50
+ });
51
+ });
52
+
53
+ describe("isWeekend()", () => {
54
+ it("should return false for Monday", () => {
55
+ const dt = new DateTime("2024-01-15T12:00:00.000Z");
56
+ expect((dt as any).isWeekend()).toBe(false);
57
+ });
58
+
59
+ it("should return false for Friday", () => {
60
+ const dt = new DateTime("2024-01-19T12:00:00.000Z");
61
+ expect((dt as any).isWeekend()).toBe(false);
62
+ });
63
+
64
+ it("should return true for Saturday", () => {
65
+ const dt = new DateTime("2024-01-20T12:00:00.000Z");
66
+ expect((dt as any).isWeekend()).toBe(true);
67
+ });
68
+
69
+ it("should return true for Sunday", () => {
70
+ const dt = new DateTime("2024-01-21T12:00:00.000Z");
71
+ expect((dt as any).isWeekend()).toBe(true);
72
+ });
73
+ });
74
+
75
+ describe("addBusinessDays()", () => {
76
+ it("should add business days correctly", () => {
77
+ // Monday + 1 business day = Tuesday
78
+ const monday = new DateTime("2024-01-15T12:00:00.000Z");
79
+ const tuesday = (monday as any).addBusinessDays(1);
80
+ expect(tuesday.date()).toBe(16);
81
+ });
82
+
83
+ it("should skip weekends when adding business days", () => {
84
+ // Friday + 1 business day = Monday
85
+ const friday = new DateTime("2024-01-19T12:00:00.000Z");
86
+ const monday = (friday as any).addBusinessDays(1);
87
+ expect(monday.date()).toBe(22);
88
+ });
89
+
90
+ it("should handle multiple business days across weekends", () => {
91
+ // Friday + 3 business days = Wednesday (skip Sat, Sun, Mon, Tue, Wed)
92
+ const friday = new DateTime("2024-01-19T12:00:00.000Z");
93
+ const wednesday = (friday as any).addBusinessDays(3);
94
+ expect(wednesday.date()).toBe(24);
95
+ });
96
+
97
+ it("should handle adding from Saturday", () => {
98
+ // Saturday + 1 business day = Monday
99
+ const saturday = new DateTime("2024-01-20T12:00:00.000Z");
100
+ const monday = (saturday as any).addBusinessDays(1);
101
+ expect(monday.date()).toBe(22);
102
+ });
103
+
104
+ it("should handle adding from Sunday", () => {
105
+ // Sunday + 1 business day = Monday
106
+ const sunday = new DateTime("2024-01-21T12:00:00.000Z");
107
+ const monday = (sunday as any).addBusinessDays(1);
108
+ expect(monday.date()).toBe(22);
109
+ });
110
+
111
+ it("should handle adding 0 business days", () => {
112
+ const dt = new DateTime("2024-01-15T12:00:00.000Z");
113
+ const result = (dt as any).addBusinessDays(0);
114
+ expect(result.valueOf()).toBe(dt.valueOf());
115
+ });
116
+
117
+ it("should preserve time when adding business days", () => {
118
+ const dt = new DateTime("2024-01-15T14:30:45.123Z");
119
+ const result = (dt as any).addBusinessDays(1);
120
+ expect(result.hour()).toBe(14);
121
+ expect(result.minute()).toBe(30);
122
+ expect(result.second()).toBe(45);
123
+ expect(result.millisecond()).toBe(123);
124
+ });
125
+ });
126
+
127
+ describe("subtractBusinessDays()", () => {
128
+ it("should subtract business days correctly", () => {
129
+ // Tuesday - 1 business day = Monday
130
+ const tuesday = new DateTime("2024-01-16T12:00:00.000Z");
131
+ const monday = (tuesday as any).subtractBusinessDays(1);
132
+ expect(monday.date()).toBe(15);
133
+ });
134
+
135
+ it("should skip weekends when subtracting business days", () => {
136
+ // Monday - 1 business day = Friday
137
+ const monday = new DateTime("2024-01-22T12:00:00.000Z");
138
+ const friday = (monday as any).subtractBusinessDays(1);
139
+ expect(friday.date()).toBe(19);
140
+ });
141
+
142
+ it("should handle multiple business days across weekends", () => {
143
+ // Wednesday - 3 business days = Friday (previous week)
144
+ const wednesday = new DateTime("2024-01-24T12:00:00.000Z");
145
+ const friday = (wednesday as any).subtractBusinessDays(3);
146
+ expect(friday.date()).toBe(19);
147
+ });
148
+
149
+ it("should handle subtracting from Saturday", () => {
150
+ // Saturday - 1 business day = Friday
151
+ const saturday = new DateTime("2024-01-20T12:00:00.000Z");
152
+ const friday = (saturday as any).subtractBusinessDays(1);
153
+ expect(friday.date()).toBe(19);
154
+ });
155
+
156
+ it("should handle subtracting from Sunday", () => {
157
+ // Sunday - 1 business day = Friday
158
+ const sunday = new DateTime("2024-01-21T12:00:00.000Z");
159
+ const friday = (sunday as any).subtractBusinessDays(1);
160
+ expect(friday.date()).toBe(19);
161
+ });
162
+
163
+ it("should handle subtracting 0 business days", () => {
164
+ const dt = new DateTime("2024-01-15T12:00:00.000Z");
165
+ const result = (dt as any).subtractBusinessDays(0);
166
+ expect(result.valueOf()).toBe(dt.valueOf());
167
+ });
168
+ });
169
+
170
+ describe("diffBusinessDays()", () => {
171
+ it("should calculate business days between two weekdays", () => {
172
+ // Monday to Friday = 4 business days
173
+ const monday = new DateTime("2024-01-15T12:00:00.000Z");
174
+ const friday = new DateTime("2024-01-19T12:00:00.000Z");
175
+ expect((monday as any).diffBusinessDays(friday)).toBe(4);
176
+ });
177
+
178
+ it("should exclude weekends in calculation", () => {
179
+ // Friday to next Monday = 1 business day
180
+ const friday = new DateTime("2024-01-19T12:00:00.000Z");
181
+ const monday = new DateTime("2024-01-22T12:00:00.000Z");
182
+ expect((friday as any).diffBusinessDays(monday)).toBe(1);
183
+ });
184
+
185
+ it("should return negative values when going backwards", () => {
186
+ const friday = new DateTime("2024-01-19T12:00:00.000Z");
187
+ const monday = new DateTime("2024-01-15T12:00:00.000Z");
188
+ expect((friday as any).diffBusinessDays(monday)).toBe(-4);
189
+ });
190
+
191
+ it("should return 0 for same day", () => {
192
+ const dt1 = new DateTime("2024-01-15T12:00:00.000Z");
193
+ const dt2 = new DateTime("2024-01-15T18:00:00.000Z");
194
+ expect((dt1 as any).diffBusinessDays(dt2)).toBe(0);
195
+ });
196
+
197
+ it("should handle weekend dates", () => {
198
+ // Saturday to Sunday = 0 business days
199
+ const saturday = new DateTime("2024-01-20T12:00:00.000Z");
200
+ const sunday = new DateTime("2024-01-21T12:00:00.000Z");
201
+ expect((saturday as any).diffBusinessDays(sunday)).toBe(0);
202
+ });
203
+
204
+ it("should handle crossing multiple weeks", () => {
205
+ // Monday to Monday (2 weeks) = 10 business days
206
+ const monday1 = new DateTime("2024-01-15T12:00:00.000Z");
207
+ const monday2 = new DateTime("2024-01-29T12:00:00.000Z");
208
+ expect((monday1 as any).diffBusinessDays(monday2)).toBe(10);
209
+ });
210
+ });
211
+
212
+ describe("Chaining", () => {
213
+ it("should chain business day methods with other DateTime methods", () => {
214
+ const dt = new DateTime("2024-01-15T12:00:00.000Z");
215
+ const result = (dt as any).addBusinessDays(5).addHours(2);
216
+ expect(result).toBeInstanceOf(DateTime);
217
+ });
218
+
219
+ it("should work with arithmetic operations", () => {
220
+ const dt = new DateTime("2024-01-15T12:00:00.000Z");
221
+ const result = (dt as any).addBusinessDays(3).subtractBusinessDays(1);
222
+ expect((dt as any).diffBusinessDays(result)).toBe(2);
223
+ });
224
+ });
225
+ });
@@ -0,0 +1,126 @@
1
+ import type { DateTime } from "../../core/datetime";
2
+ import type { DateTimeClass } from "../../types";
3
+ import { createPlugin } from "../plugin-base";
4
+
5
+ /**
6
+ * Checks if a given day of week is a weekday (Monday-Friday)
7
+ * @param dayOfWeek - Day of week (0=Sunday, 6=Saturday)
8
+ * @returns true if weekday, false otherwise
9
+ */
10
+ function isWeekdayDay(dayOfWeek: number): boolean {
11
+ return dayOfWeek >= 1 && dayOfWeek <= 5;
12
+ }
13
+
14
+ /**
15
+ * Extended DateTime interface with business days methods
16
+ */
17
+ declare module "../../core/datetime" {
18
+ interface DateTime {
19
+ /**
20
+ * Checks if this date is a weekday (Monday-Friday)
21
+ * @returns true if weekday, false otherwise
22
+ */
23
+ isWeekday(): boolean;
24
+
25
+ /**
26
+ * Checks if this date is a weekend (Saturday-Sunday)
27
+ * @returns true if weekend, false otherwise
28
+ */
29
+ isWeekend(): boolean;
30
+
31
+ /**
32
+ * Adds business days to this date
33
+ * Skips weekends (Saturday and Sunday)
34
+ * @param n - Number of business days to add
35
+ * @returns New DateTime instance with business days added
36
+ */
37
+ addBusinessDays(n: number): DateTime;
38
+
39
+ /**
40
+ * Subtracts business days from this date
41
+ * Skips weekends (Saturday and Sunday)
42
+ * @param n - Number of business days to subtract
43
+ * @returns New DateTime instance with business days subtracted
44
+ */
45
+ subtractBusinessDays(n: number): DateTime;
46
+
47
+ /**
48
+ * Calculates the number of business days between this date and another
49
+ * Excludes weekends from the calculation
50
+ * @param other - DateTime instance to compare against
51
+ * @returns Number of business days (positive if other is after, negative if before)
52
+ */
53
+ diffBusinessDays(other: DateTime): number;
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Business Days plugin for DateTime
59
+ * Adds methods for working with business days (weekdays only)
60
+ * Week is defined as Monday-Friday (weekdays), Saturday-Sunday (weekend)
61
+ */
62
+ export const businessDaysPlugin = createPlugin(
63
+ "business-days",
64
+ (DateTimeClass: DateTimeClass) => {
65
+ // Add instance methods
66
+ DateTimeClass.prototype.isWeekday = function (): boolean {
67
+ const dayOfWeek = this.day(); // 0=Sunday, 6=Saturday
68
+ return isWeekdayDay(dayOfWeek);
69
+ };
70
+
71
+ DateTimeClass.prototype.isWeekend = function (): boolean {
72
+ const dayOfWeek = this.day();
73
+ return dayOfWeek === 0 || dayOfWeek === 6;
74
+ };
75
+
76
+ DateTimeClass.prototype.addBusinessDays = function (n: number): DateTime {
77
+ if (n === 0) {
78
+ return this;
79
+ }
80
+
81
+ let current = new DateTimeClass(this.valueOf());
82
+ let daysToAdd = Math.abs(n);
83
+ const direction = n > 0 ? 1 : -1;
84
+
85
+ while (daysToAdd > 0) {
86
+ // Move one day in the specified direction
87
+ current = current.addDays(direction);
88
+
89
+ // Only count weekdays
90
+ if ((current as any).isWeekday()) {
91
+ daysToAdd--;
92
+ }
93
+ }
94
+
95
+ return current;
96
+ };
97
+
98
+ DateTimeClass.prototype.subtractBusinessDays = function (
99
+ n: number,
100
+ ): DateTime {
101
+ return (this as any).addBusinessDays(-n);
102
+ };
103
+
104
+ DateTimeClass.prototype.diffBusinessDays = function (
105
+ other: DateTime,
106
+ ): number {
107
+ // Get start and end dates (normalized to start of day for consistency)
108
+ const start = this.valueOf() < other.valueOf() ? this : other;
109
+ const end = this.valueOf() < other.valueOf() ? other : this;
110
+ const isReversed = this.valueOf() > other.valueOf();
111
+
112
+ let businessDays = 0;
113
+ let current = new DateTimeClass(start.valueOf());
114
+
115
+ // Iterate through each day and count weekdays
116
+ while (current.startOfDay().valueOf() < end.startOfDay().valueOf()) {
117
+ if ((current as any).isWeekday()) {
118
+ businessDays++;
119
+ }
120
+ current = current.addDays(1);
121
+ }
122
+
123
+ return isReversed ? -businessDays : businessDays;
124
+ };
125
+ },
126
+ );