chronos-ts 1.1.0 → 2.0.1
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.
- package/README.md +249 -443
- package/dist/core/chronos.d.ts +460 -0
- package/dist/core/chronos.js +1259 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.js +19 -0
- package/dist/core/interval.d.ts +289 -0
- package/dist/core/interval.js +689 -0
- package/dist/core/period-collection.d.ts +205 -0
- package/dist/core/period-collection.js +562 -0
- package/dist/core/period.d.ts +428 -0
- package/dist/core/period.js +1007 -0
- package/dist/core/timezone.d.ts +289 -0
- package/dist/core/timezone.js +671 -0
- package/dist/index.d.ts +50 -4
- package/dist/index.js +148 -22
- package/dist/locales/index.d.ts +66 -0
- package/dist/locales/index.js +847 -0
- package/dist/types/index.d.ts +428 -0
- package/dist/types/index.js +71 -0
- package/dist/utils/index.d.ts +127 -0
- package/dist/utils/index.js +656 -0
- package/package.json +19 -3
- package/dist/interval.d.ts +0 -61
- package/dist/interval.js +0 -82
- package/dist/period.d.ts +0 -196
- package/dist/period.js +0 -365
- package/dist/precision.d.ts +0 -24
- package/dist/precision.js +0 -46
- package/dist/utils.d.ts +0 -190
- package/dist/utils.js +0 -374
|
@@ -0,0 +1,1007 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ChronosPeriod - Date range iteration
|
|
4
|
+
* @module ChronosPeriod
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.ChronosPeriod = void 0;
|
|
8
|
+
const utils_1 = require("../utils");
|
|
9
|
+
const locales_1 = require("../locales");
|
|
10
|
+
const chronos_1 = require("./chronos");
|
|
11
|
+
const interval_1 = require("./interval");
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// ChronosPeriod Class
|
|
14
|
+
// ============================================================================
|
|
15
|
+
/**
|
|
16
|
+
* ChronosPeriod - Represents a date range with iteration capabilities
|
|
17
|
+
*
|
|
18
|
+
* Inspired by CarbonPeriod, this class provides powerful date range
|
|
19
|
+
* iteration with support for various interval types, filters, and
|
|
20
|
+
* recurrence patterns.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* // Basic iteration
|
|
25
|
+
* const period = ChronosPeriod.create('2024-01-01', '2024-01-31');
|
|
26
|
+
* for (const date of period) {
|
|
27
|
+
* console.log(date.format('YYYY-MM-DD'));
|
|
28
|
+
* }
|
|
29
|
+
*
|
|
30
|
+
* // With custom interval
|
|
31
|
+
* const weekly = ChronosPeriod.create('2024-01-01', '2024-03-31')
|
|
32
|
+
* .setInterval(ChronosInterval.weeks(1));
|
|
33
|
+
*
|
|
34
|
+
* // With filters
|
|
35
|
+
* const weekdays = period.filter(date => date.dayOfWeek < 6);
|
|
36
|
+
*
|
|
37
|
+
* // Recurrence
|
|
38
|
+
* const recur = ChronosPeriod.recur('2024-01-01')
|
|
39
|
+
* .every(1, 'month')
|
|
40
|
+
* .times(12);
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
class ChronosPeriod {
|
|
44
|
+
// ============================================================================
|
|
45
|
+
// Constructor
|
|
46
|
+
// ============================================================================
|
|
47
|
+
/**
|
|
48
|
+
* Create a new ChronosPeriod
|
|
49
|
+
*/
|
|
50
|
+
constructor(start, end, interval, options = {}) {
|
|
51
|
+
var _a, _b, _c;
|
|
52
|
+
this._start = chronos_1.Chronos.parse(start);
|
|
53
|
+
this._end = end !== undefined ? chronos_1.Chronos.parse(end) : null;
|
|
54
|
+
this._interval =
|
|
55
|
+
interval instanceof interval_1.ChronosInterval
|
|
56
|
+
? interval
|
|
57
|
+
: interval_1.ChronosInterval.create(interval || { days: 1 });
|
|
58
|
+
this._recurrences = null;
|
|
59
|
+
this._options = {
|
|
60
|
+
excludeStart: (_a = options.excludeStart) !== null && _a !== void 0 ? _a : false,
|
|
61
|
+
excludeEnd: (_b = options.excludeEnd) !== null && _b !== void 0 ? _b : false,
|
|
62
|
+
immutable: (_c = options.immutable) !== null && _c !== void 0 ? _c : true,
|
|
63
|
+
};
|
|
64
|
+
this._filters = [];
|
|
65
|
+
this._current = 0;
|
|
66
|
+
this._locale = (0, locales_1.getLocale)('en');
|
|
67
|
+
}
|
|
68
|
+
// ============================================================================
|
|
69
|
+
// Static Factory Methods
|
|
70
|
+
// ============================================================================
|
|
71
|
+
/**
|
|
72
|
+
* Create a period between two dates
|
|
73
|
+
*/
|
|
74
|
+
static create(start, end, interval) {
|
|
75
|
+
return new ChronosPeriod(start, end, interval);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Create a period from a start date with recurrences
|
|
79
|
+
*/
|
|
80
|
+
static recur(start, interval) {
|
|
81
|
+
return new ChronosPeriod(start, undefined, interval);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Create a period for a specific number of days
|
|
85
|
+
*/
|
|
86
|
+
static days(start, count) {
|
|
87
|
+
const startDate = chronos_1.Chronos.parse(start);
|
|
88
|
+
const endDate = startDate.addDays(count - 1);
|
|
89
|
+
return new ChronosPeriod(startDate, endDate, { days: 1 });
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Create a period for a specific number of weeks
|
|
93
|
+
*/
|
|
94
|
+
static weeks(start, count) {
|
|
95
|
+
const startDate = chronos_1.Chronos.parse(start);
|
|
96
|
+
const endDate = startDate.addWeeks(count);
|
|
97
|
+
return new ChronosPeriod(startDate, endDate, { weeks: 1 });
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Create a period for a specific number of months
|
|
101
|
+
*/
|
|
102
|
+
static months(start, count) {
|
|
103
|
+
const startDate = chronos_1.Chronos.parse(start);
|
|
104
|
+
const endDate = startDate.addMonths(count);
|
|
105
|
+
return new ChronosPeriod(startDate, endDate, { months: 1 });
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Create a period for a specific number of years
|
|
109
|
+
*/
|
|
110
|
+
static years(start, count) {
|
|
111
|
+
const startDate = chronos_1.Chronos.parse(start);
|
|
112
|
+
const endDate = startDate.addYears(count);
|
|
113
|
+
return new ChronosPeriod(startDate, endDate, { years: 1 });
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Create a period for the current month
|
|
117
|
+
*/
|
|
118
|
+
static currentMonth() {
|
|
119
|
+
const now = chronos_1.Chronos.now();
|
|
120
|
+
return new ChronosPeriod(now.startOf('month'), now.endOf('month'), {
|
|
121
|
+
days: 1,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Create a period for the current year
|
|
126
|
+
*/
|
|
127
|
+
static currentYear() {
|
|
128
|
+
const now = chronos_1.Chronos.now();
|
|
129
|
+
return new ChronosPeriod(now.startOf('year'), now.endOf('year'), {
|
|
130
|
+
days: 1,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Create a period for the current week
|
|
135
|
+
*/
|
|
136
|
+
static currentWeek() {
|
|
137
|
+
const now = chronos_1.Chronos.now();
|
|
138
|
+
return new ChronosPeriod(now.startOf('week'), now.endOf('week'), {
|
|
139
|
+
days: 1,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Create a period for the current quarter
|
|
144
|
+
*/
|
|
145
|
+
static currentQuarter() {
|
|
146
|
+
const now = chronos_1.Chronos.now();
|
|
147
|
+
return new ChronosPeriod(now.startOf('quarter'), now.endOf('quarter'), {
|
|
148
|
+
days: 1,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
// ============================================================================
|
|
152
|
+
// Convenience Aliases (thisWeek, thisMonth, lastWeek, etc.)
|
|
153
|
+
// ============================================================================
|
|
154
|
+
/**
|
|
155
|
+
* Alias for currentWeek()
|
|
156
|
+
*/
|
|
157
|
+
static thisWeek() {
|
|
158
|
+
return ChronosPeriod.currentWeek();
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Alias for currentMonth()
|
|
162
|
+
*/
|
|
163
|
+
static thisMonth() {
|
|
164
|
+
return ChronosPeriod.currentMonth();
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Alias for currentYear()
|
|
168
|
+
*/
|
|
169
|
+
static thisYear() {
|
|
170
|
+
return ChronosPeriod.currentYear();
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Alias for currentQuarter()
|
|
174
|
+
*/
|
|
175
|
+
static thisQuarter() {
|
|
176
|
+
return ChronosPeriod.currentQuarter();
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Create a period for the previous week
|
|
180
|
+
*/
|
|
181
|
+
static lastWeek() {
|
|
182
|
+
const now = chronos_1.Chronos.now().subtract({ weeks: 1 });
|
|
183
|
+
return new ChronosPeriod(now.startOf('week'), now.endOf('week'), {
|
|
184
|
+
days: 1,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Create a period for the previous month
|
|
189
|
+
*/
|
|
190
|
+
static lastMonth() {
|
|
191
|
+
const now = chronos_1.Chronos.now().subtract({ months: 1 });
|
|
192
|
+
return new ChronosPeriod(now.startOf('month'), now.endOf('month'), {
|
|
193
|
+
days: 1,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Create a period for the previous year
|
|
198
|
+
*/
|
|
199
|
+
static lastYear() {
|
|
200
|
+
const now = chronos_1.Chronos.now().subtract({ years: 1 });
|
|
201
|
+
return new ChronosPeriod(now.startOf('year'), now.endOf('year'), {
|
|
202
|
+
days: 1,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Create a period for the previous quarter
|
|
207
|
+
*/
|
|
208
|
+
static lastQuarter() {
|
|
209
|
+
const now = chronos_1.Chronos.now().subtract({ months: 3 });
|
|
210
|
+
return new ChronosPeriod(now.startOf('quarter'), now.endOf('quarter'), {
|
|
211
|
+
days: 1,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Create a period for the next week
|
|
216
|
+
*/
|
|
217
|
+
static nextWeek() {
|
|
218
|
+
const now = chronos_1.Chronos.now().add({ weeks: 1 });
|
|
219
|
+
return new ChronosPeriod(now.startOf('week'), now.endOf('week'), {
|
|
220
|
+
days: 1,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Create a period for the next month
|
|
225
|
+
*/
|
|
226
|
+
static nextMonth() {
|
|
227
|
+
const now = chronos_1.Chronos.now().add({ months: 1 });
|
|
228
|
+
return new ChronosPeriod(now.startOf('month'), now.endOf('month'), {
|
|
229
|
+
days: 1,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Create a period for the next year
|
|
234
|
+
*/
|
|
235
|
+
static nextYear() {
|
|
236
|
+
const now = chronos_1.Chronos.now().add({ years: 1 });
|
|
237
|
+
return new ChronosPeriod(now.startOf('year'), now.endOf('year'), {
|
|
238
|
+
days: 1,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Create a period for the next quarter
|
|
243
|
+
*/
|
|
244
|
+
static nextQuarter() {
|
|
245
|
+
const now = chronos_1.Chronos.now().add({ months: 3 });
|
|
246
|
+
return new ChronosPeriod(now.startOf('quarter'), now.endOf('quarter'), {
|
|
247
|
+
days: 1,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Create a period between two dates (alias for create)
|
|
252
|
+
*/
|
|
253
|
+
static between(start, end, interval) {
|
|
254
|
+
return ChronosPeriod.create(start, end, interval);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Create a period from an ISO 8601 repeating interval string
|
|
258
|
+
* @example
|
|
259
|
+
* ```typescript
|
|
260
|
+
* ChronosPeriod.fromISO('R5/2024-01-01/P1D') // 5 recurrences, daily from 2024-01-01
|
|
261
|
+
* ChronosPeriod.fromISO('2024-01-01/2024-01-31') // Date range
|
|
262
|
+
* ChronosPeriod.fromISO('2024-01-01/P1M') // From date with duration
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
265
|
+
static fromISO(iso) {
|
|
266
|
+
// Pattern for repeating interval: R[n]/start/duration or R[n]/start/end
|
|
267
|
+
const repeatMatch = iso.match(/^R(\d*)\/([\d\-T:Z]+)\/(P.+|[\d\-T:Z]+)$/);
|
|
268
|
+
if (repeatMatch) {
|
|
269
|
+
const recurrences = repeatMatch[1]
|
|
270
|
+
? parseInt(repeatMatch[1], 10)
|
|
271
|
+
: Infinity;
|
|
272
|
+
const start = chronos_1.Chronos.parse(repeatMatch[2]);
|
|
273
|
+
const durationOrEnd = repeatMatch[3];
|
|
274
|
+
if (durationOrEnd.startsWith('P')) {
|
|
275
|
+
const interval = interval_1.ChronosInterval.fromISO(durationOrEnd);
|
|
276
|
+
return new ChronosPeriod(start, undefined, interval).times(recurrences);
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
const end = chronos_1.Chronos.parse(durationOrEnd);
|
|
280
|
+
return new ChronosPeriod(start, end).times(recurrences);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// Pattern for date range: start/end or start/duration
|
|
284
|
+
const rangeMatch = iso.match(/^([\d\-T:Z]+)\/(P.+|[\d\-T:Z]+)$/);
|
|
285
|
+
if (rangeMatch) {
|
|
286
|
+
const start = chronos_1.Chronos.parse(rangeMatch[1]);
|
|
287
|
+
const durationOrEnd = rangeMatch[2];
|
|
288
|
+
if (durationOrEnd.startsWith('P')) {
|
|
289
|
+
const interval = interval_1.ChronosInterval.fromISO(durationOrEnd);
|
|
290
|
+
const end = start.add(interval.toDuration());
|
|
291
|
+
return new ChronosPeriod(start, end, interval);
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
const end = chronos_1.Chronos.parse(durationOrEnd);
|
|
295
|
+
return new ChronosPeriod(start, end);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
throw new Error(`Invalid ISO 8601 period: ${iso}`);
|
|
299
|
+
}
|
|
300
|
+
// ============================================================================
|
|
301
|
+
// Getters
|
|
302
|
+
// ============================================================================
|
|
303
|
+
/**
|
|
304
|
+
* Get the start date
|
|
305
|
+
*/
|
|
306
|
+
get start() {
|
|
307
|
+
return this._start;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Get the end date
|
|
311
|
+
*/
|
|
312
|
+
get end() {
|
|
313
|
+
return this._end;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Get the interval
|
|
317
|
+
*/
|
|
318
|
+
get interval() {
|
|
319
|
+
return this._interval;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Get the number of recurrences
|
|
323
|
+
*/
|
|
324
|
+
get recurrences() {
|
|
325
|
+
return this._recurrences;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Check if the period includes the start boundary
|
|
329
|
+
*/
|
|
330
|
+
get includesStart() {
|
|
331
|
+
return !this._options.excludeStart;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Check if the period includes the end boundary
|
|
335
|
+
*/
|
|
336
|
+
get includesEnd() {
|
|
337
|
+
return !this._options.excludeEnd;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Check if the period has an end date
|
|
341
|
+
*/
|
|
342
|
+
get hasEnd() {
|
|
343
|
+
return this._end !== null || this._recurrences !== null;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Check if the period is unbounded
|
|
347
|
+
*/
|
|
348
|
+
get isUnbounded() {
|
|
349
|
+
return this._end === null && this._recurrences === null;
|
|
350
|
+
}
|
|
351
|
+
// ============================================================================
|
|
352
|
+
// Setters (Fluent Interface)
|
|
353
|
+
// ============================================================================
|
|
354
|
+
/**
|
|
355
|
+
* Set the start date
|
|
356
|
+
*/
|
|
357
|
+
setStart(start) {
|
|
358
|
+
const period = this._cloneForModification();
|
|
359
|
+
period._start = chronos_1.Chronos.parse(start);
|
|
360
|
+
return period;
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Set the end date
|
|
364
|
+
*/
|
|
365
|
+
setEnd(end) {
|
|
366
|
+
const period = this._cloneForModification();
|
|
367
|
+
period._end = chronos_1.Chronos.parse(end);
|
|
368
|
+
return period;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Set the interval
|
|
372
|
+
*/
|
|
373
|
+
setInterval(interval) {
|
|
374
|
+
const period = this._cloneForModification();
|
|
375
|
+
period._interval =
|
|
376
|
+
interval instanceof interval_1.ChronosInterval
|
|
377
|
+
? interval
|
|
378
|
+
: interval_1.ChronosInterval.create(interval);
|
|
379
|
+
return period;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Set the number of recurrences
|
|
383
|
+
*/
|
|
384
|
+
times(count) {
|
|
385
|
+
const period = this._cloneForModification();
|
|
386
|
+
period._recurrences = count;
|
|
387
|
+
return period;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Set interval by unit
|
|
391
|
+
*/
|
|
392
|
+
every(amount, unit) {
|
|
393
|
+
const normalizedUnit = (0, utils_1.normalizeUnit)(unit);
|
|
394
|
+
const duration = {};
|
|
395
|
+
switch (normalizedUnit) {
|
|
396
|
+
case 'millisecond':
|
|
397
|
+
duration.milliseconds = amount;
|
|
398
|
+
break;
|
|
399
|
+
case 'second':
|
|
400
|
+
duration.seconds = amount;
|
|
401
|
+
break;
|
|
402
|
+
case 'minute':
|
|
403
|
+
duration.minutes = amount;
|
|
404
|
+
break;
|
|
405
|
+
case 'hour':
|
|
406
|
+
duration.hours = amount;
|
|
407
|
+
break;
|
|
408
|
+
case 'day':
|
|
409
|
+
duration.days = amount;
|
|
410
|
+
break;
|
|
411
|
+
case 'week':
|
|
412
|
+
duration.weeks = amount;
|
|
413
|
+
break;
|
|
414
|
+
case 'month':
|
|
415
|
+
duration.months = amount;
|
|
416
|
+
break;
|
|
417
|
+
case 'quarter':
|
|
418
|
+
duration.months = amount * 3;
|
|
419
|
+
break;
|
|
420
|
+
case 'year':
|
|
421
|
+
duration.years = amount;
|
|
422
|
+
break;
|
|
423
|
+
default:
|
|
424
|
+
duration.days = amount;
|
|
425
|
+
}
|
|
426
|
+
return this.setInterval(duration);
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Exclude the start boundary
|
|
430
|
+
*/
|
|
431
|
+
excludeStart() {
|
|
432
|
+
const period = this._cloneForModification();
|
|
433
|
+
period._options.excludeStart = true;
|
|
434
|
+
return period;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Exclude the end boundary
|
|
438
|
+
*/
|
|
439
|
+
excludeEnd() {
|
|
440
|
+
const period = this._cloneForModification();
|
|
441
|
+
period._options.excludeEnd = true;
|
|
442
|
+
return period;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Include the start boundary
|
|
446
|
+
*/
|
|
447
|
+
includeStart() {
|
|
448
|
+
const period = this._cloneForModification();
|
|
449
|
+
period._options.excludeStart = false;
|
|
450
|
+
return period;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Include the end boundary
|
|
454
|
+
*/
|
|
455
|
+
includeEnd() {
|
|
456
|
+
const period = this._cloneForModification();
|
|
457
|
+
period._options.excludeEnd = false;
|
|
458
|
+
return period;
|
|
459
|
+
}
|
|
460
|
+
// ============================================================================
|
|
461
|
+
// Filters
|
|
462
|
+
// ============================================================================
|
|
463
|
+
/**
|
|
464
|
+
* Add a filter function
|
|
465
|
+
*/
|
|
466
|
+
filter(fn) {
|
|
467
|
+
const period = this._cloneForModification();
|
|
468
|
+
period._filters.push(fn);
|
|
469
|
+
return period;
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Filter to only include weekdays
|
|
473
|
+
*/
|
|
474
|
+
weekdays() {
|
|
475
|
+
return this.filter((date) => date.dayOfWeek !== 0 && date.dayOfWeek !== 6);
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Alias for weekdays()
|
|
479
|
+
*/
|
|
480
|
+
filterWeekdays() {
|
|
481
|
+
return this.weekdays();
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Filter to only include weekends
|
|
485
|
+
*/
|
|
486
|
+
weekends() {
|
|
487
|
+
return this.filter((date) => date.dayOfWeek === 0 || date.dayOfWeek === 6);
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Alias for weekends()
|
|
491
|
+
*/
|
|
492
|
+
filterWeekends() {
|
|
493
|
+
return this.weekends();
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Filter to only include specific days of week
|
|
497
|
+
*/
|
|
498
|
+
onlyDays(...days) {
|
|
499
|
+
return this.filter((date) => days.includes(date.dayOfWeek));
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Filter to exclude specific days of week
|
|
503
|
+
*/
|
|
504
|
+
exceptDays(...days) {
|
|
505
|
+
return this.filter((date) => !days.includes(date.dayOfWeek));
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Filter to only include specific months
|
|
509
|
+
*/
|
|
510
|
+
onlyMonths(...months) {
|
|
511
|
+
return this.filter((date) => months.includes(date.month));
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Filter to exclude specific months
|
|
515
|
+
*/
|
|
516
|
+
exceptMonths(...months) {
|
|
517
|
+
return this.filter((date) => !months.includes(date.month));
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Clear all filters
|
|
521
|
+
*/
|
|
522
|
+
clearFilters() {
|
|
523
|
+
const period = this._cloneForModification();
|
|
524
|
+
period._filters = [];
|
|
525
|
+
return period;
|
|
526
|
+
}
|
|
527
|
+
// ============================================================================
|
|
528
|
+
// Iteration
|
|
529
|
+
// ============================================================================
|
|
530
|
+
/**
|
|
531
|
+
* Get all dates in the period as an array
|
|
532
|
+
*/
|
|
533
|
+
toArray() {
|
|
534
|
+
return [...this];
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Iterate over the period
|
|
538
|
+
*/
|
|
539
|
+
*[Symbol.iterator]() {
|
|
540
|
+
let current = this._start.clone();
|
|
541
|
+
let count = 0;
|
|
542
|
+
// Handle excludeStart
|
|
543
|
+
if (this._options.excludeStart) {
|
|
544
|
+
current = this._applyInterval(current);
|
|
545
|
+
count++;
|
|
546
|
+
}
|
|
547
|
+
while (this._shouldContinue(current, count)) {
|
|
548
|
+
// Apply filters
|
|
549
|
+
if (this._passesFilters(current, count)) {
|
|
550
|
+
yield this._options.immutable ? current.clone() : current;
|
|
551
|
+
}
|
|
552
|
+
current = this._applyInterval(current);
|
|
553
|
+
count++;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Apply the interval to a date
|
|
558
|
+
*/
|
|
559
|
+
_applyInterval(date) {
|
|
560
|
+
return date.add(this._interval.toDuration());
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Check if iteration should continue
|
|
564
|
+
*/
|
|
565
|
+
_shouldContinue(date, count) {
|
|
566
|
+
// Check recurrence limit
|
|
567
|
+
if (this._recurrences !== null && count >= this._recurrences) {
|
|
568
|
+
return false;
|
|
569
|
+
}
|
|
570
|
+
// Check end date
|
|
571
|
+
if (this._end !== null) {
|
|
572
|
+
if (this._options.excludeEnd) {
|
|
573
|
+
return date.isBefore(this._end);
|
|
574
|
+
}
|
|
575
|
+
return date.isSameOrBefore(this._end);
|
|
576
|
+
}
|
|
577
|
+
// No end - check for unbounded
|
|
578
|
+
if (this._recurrences === null) {
|
|
579
|
+
// Prevent infinite iteration
|
|
580
|
+
if (count > 10000) {
|
|
581
|
+
throw new Error('ChronosPeriod: Maximum iteration limit reached. Set an end date or recurrence limit.');
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
return true;
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Check if a date passes all filters
|
|
588
|
+
*/
|
|
589
|
+
_passesFilters(date, key) {
|
|
590
|
+
return this._filters.every((filter) => filter(date, key));
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Get count of dates in the period
|
|
594
|
+
*/
|
|
595
|
+
count() {
|
|
596
|
+
return this.toArray().length;
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Get the first date in the period
|
|
600
|
+
*/
|
|
601
|
+
first() {
|
|
602
|
+
const iterator = this[Symbol.iterator]();
|
|
603
|
+
const result = iterator.next();
|
|
604
|
+
return result.done ? null : result.value;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Get the last date in the period
|
|
608
|
+
*/
|
|
609
|
+
last() {
|
|
610
|
+
const array = this.toArray();
|
|
611
|
+
return array.length > 0 ? array[array.length - 1] : null;
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Get a date at a specific index
|
|
615
|
+
*/
|
|
616
|
+
nth(index) {
|
|
617
|
+
let count = 0;
|
|
618
|
+
for (const date of this) {
|
|
619
|
+
if (count === index) {
|
|
620
|
+
return date;
|
|
621
|
+
}
|
|
622
|
+
count++;
|
|
623
|
+
}
|
|
624
|
+
return null;
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Check if a date is within the period
|
|
628
|
+
*/
|
|
629
|
+
contains(date) {
|
|
630
|
+
const target = chronos_1.Chronos.parse(date);
|
|
631
|
+
return this.toArray().some((d) => d.isSame(target, 'day'));
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* For each iteration
|
|
635
|
+
*/
|
|
636
|
+
forEach(callback) {
|
|
637
|
+
let index = 0;
|
|
638
|
+
for (const date of this) {
|
|
639
|
+
callback(date, index);
|
|
640
|
+
index++;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Map dates to another type
|
|
645
|
+
*/
|
|
646
|
+
map(callback) {
|
|
647
|
+
const result = [];
|
|
648
|
+
let index = 0;
|
|
649
|
+
for (const date of this) {
|
|
650
|
+
result.push(callback(date, index));
|
|
651
|
+
index++;
|
|
652
|
+
}
|
|
653
|
+
return result;
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* Reduce dates to a single value
|
|
657
|
+
*/
|
|
658
|
+
reduce(callback, initial) {
|
|
659
|
+
let acc = initial;
|
|
660
|
+
let index = 0;
|
|
661
|
+
for (const date of this) {
|
|
662
|
+
acc = callback(acc, date, index);
|
|
663
|
+
index++;
|
|
664
|
+
}
|
|
665
|
+
return acc;
|
|
666
|
+
}
|
|
667
|
+
// ============================================================================
|
|
668
|
+
// Range Operations
|
|
669
|
+
// ============================================================================
|
|
670
|
+
/**
|
|
671
|
+
* Check if two periods overlap
|
|
672
|
+
*/
|
|
673
|
+
overlaps(other) {
|
|
674
|
+
var _a, _b;
|
|
675
|
+
const thisEnd = (_a = this._end) !== null && _a !== void 0 ? _a : this.last();
|
|
676
|
+
const otherEnd = (_b = other._end) !== null && _b !== void 0 ? _b : other.last();
|
|
677
|
+
if (!thisEnd || !otherEnd) {
|
|
678
|
+
return true; // Unbounded periods always overlap
|
|
679
|
+
}
|
|
680
|
+
return (this._start.isSameOrBefore(otherEnd) &&
|
|
681
|
+
thisEnd.isSameOrAfter(other._start));
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Get the intersection of two periods
|
|
685
|
+
*/
|
|
686
|
+
intersect(other) {
|
|
687
|
+
var _a, _b;
|
|
688
|
+
if (!this.overlaps(other)) {
|
|
689
|
+
return null;
|
|
690
|
+
}
|
|
691
|
+
const start = this._start.isAfter(other._start)
|
|
692
|
+
? this._start
|
|
693
|
+
: other._start;
|
|
694
|
+
const thisEnd = (_a = this._end) !== null && _a !== void 0 ? _a : this.last();
|
|
695
|
+
const otherEnd = (_b = other._end) !== null && _b !== void 0 ? _b : other.last();
|
|
696
|
+
if (!thisEnd || !otherEnd) {
|
|
697
|
+
return new ChronosPeriod(start, undefined, this._interval);
|
|
698
|
+
}
|
|
699
|
+
const end = thisEnd.isBefore(otherEnd) ? thisEnd : otherEnd;
|
|
700
|
+
return new ChronosPeriod(start, end, this._interval);
|
|
701
|
+
}
|
|
702
|
+
/**
|
|
703
|
+
* Get the union of two periods
|
|
704
|
+
*/
|
|
705
|
+
union(other) {
|
|
706
|
+
var _a, _b;
|
|
707
|
+
if (!this.overlaps(other) && !this._adjacentTo(other)) {
|
|
708
|
+
return null;
|
|
709
|
+
}
|
|
710
|
+
const start = this._start.isBefore(other._start)
|
|
711
|
+
? this._start
|
|
712
|
+
: other._start;
|
|
713
|
+
const thisEnd = (_a = this._end) !== null && _a !== void 0 ? _a : this.last();
|
|
714
|
+
const otherEnd = (_b = other._end) !== null && _b !== void 0 ? _b : other.last();
|
|
715
|
+
if (!thisEnd || !otherEnd) {
|
|
716
|
+
return new ChronosPeriod(start, undefined, this._interval);
|
|
717
|
+
}
|
|
718
|
+
const end = thisEnd.isAfter(otherEnd) ? thisEnd : otherEnd;
|
|
719
|
+
return new ChronosPeriod(start, end, this._interval);
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Get the difference between two periods
|
|
723
|
+
*/
|
|
724
|
+
diff(other) {
|
|
725
|
+
var _a, _b;
|
|
726
|
+
if (!this.overlaps(other)) {
|
|
727
|
+
return [this.clone()];
|
|
728
|
+
}
|
|
729
|
+
const results = [];
|
|
730
|
+
const thisEnd = (_a = this._end) !== null && _a !== void 0 ? _a : this.last();
|
|
731
|
+
// Before the other period starts
|
|
732
|
+
if (this._start.isBefore(other._start)) {
|
|
733
|
+
results.push(new ChronosPeriod(this._start, other._start.subtract(this._interval.toDuration()), this._interval));
|
|
734
|
+
}
|
|
735
|
+
// After the other period ends
|
|
736
|
+
const otherEnd = (_b = other._end) !== null && _b !== void 0 ? _b : other.last();
|
|
737
|
+
if (otherEnd && thisEnd && thisEnd.isAfter(otherEnd)) {
|
|
738
|
+
results.push(new ChronosPeriod(otherEnd.add(this._interval.toDuration()), thisEnd, this._interval));
|
|
739
|
+
}
|
|
740
|
+
return results;
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Check if this period is adjacent to another
|
|
744
|
+
*/
|
|
745
|
+
_adjacentTo(other) {
|
|
746
|
+
var _a, _b;
|
|
747
|
+
const thisEnd = (_a = this._end) !== null && _a !== void 0 ? _a : this.last();
|
|
748
|
+
const otherEnd = (_b = other._end) !== null && _b !== void 0 ? _b : other.last();
|
|
749
|
+
if (!thisEnd || !otherEnd) {
|
|
750
|
+
return false;
|
|
751
|
+
}
|
|
752
|
+
return (thisEnd.add(this._interval.toDuration()).isSame(other._start) ||
|
|
753
|
+
otherEnd.add(other._interval.toDuration()).isSame(this._start));
|
|
754
|
+
}
|
|
755
|
+
// ============================================================================
|
|
756
|
+
// Duration
|
|
757
|
+
// ============================================================================
|
|
758
|
+
/**
|
|
759
|
+
* Get the duration of the period
|
|
760
|
+
*/
|
|
761
|
+
duration() {
|
|
762
|
+
if (this._end === null) {
|
|
763
|
+
throw new Error('Cannot get duration of unbounded period');
|
|
764
|
+
}
|
|
765
|
+
return interval_1.ChronosInterval.between(this._start.toDate(), this._end.toDate());
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Get the number of days in the period
|
|
769
|
+
*/
|
|
770
|
+
days() {
|
|
771
|
+
if (this._end === null) {
|
|
772
|
+
throw new Error('Cannot get days of unbounded period');
|
|
773
|
+
}
|
|
774
|
+
return Math.abs(this._start.diff(this._end, 'day'));
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* Get the number of weeks in the period
|
|
778
|
+
*/
|
|
779
|
+
weeks() {
|
|
780
|
+
if (this._end === null) {
|
|
781
|
+
throw new Error('Cannot get weeks of unbounded period');
|
|
782
|
+
}
|
|
783
|
+
return Math.abs(this._start.diff(this._end, 'week'));
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Get the number of months in the period
|
|
787
|
+
*/
|
|
788
|
+
monthCount() {
|
|
789
|
+
if (this._end === null) {
|
|
790
|
+
throw new Error('Cannot get months of unbounded period');
|
|
791
|
+
}
|
|
792
|
+
return Math.abs(this._start.diff(this._end, 'month'));
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* Get the number of years in the period
|
|
796
|
+
*/
|
|
797
|
+
yearCount() {
|
|
798
|
+
if (this._end === null) {
|
|
799
|
+
throw new Error('Cannot get years of unbounded period');
|
|
800
|
+
}
|
|
801
|
+
return Math.abs(this._start.diff(this._end, 'year'));
|
|
802
|
+
}
|
|
803
|
+
// ============================================================================
|
|
804
|
+
// Splitting
|
|
805
|
+
// ============================================================================
|
|
806
|
+
/**
|
|
807
|
+
* Split the period into chunks
|
|
808
|
+
*/
|
|
809
|
+
split(count) {
|
|
810
|
+
if (this._end === null) {
|
|
811
|
+
throw new Error('Cannot split unbounded period');
|
|
812
|
+
}
|
|
813
|
+
const totalDays = this.days();
|
|
814
|
+
const daysPerChunk = Math.ceil(totalDays / count);
|
|
815
|
+
const chunks = [];
|
|
816
|
+
let current = this._start.clone();
|
|
817
|
+
for (let i = 0; i < count && current.isSameOrBefore(this._end); i++) {
|
|
818
|
+
const chunkEnd = current.addDays(daysPerChunk - 1);
|
|
819
|
+
const end = chunkEnd.isAfter(this._end) ? this._end : chunkEnd;
|
|
820
|
+
chunks.push(new ChronosPeriod(current, end, this._interval));
|
|
821
|
+
current = end.addDays(1);
|
|
822
|
+
}
|
|
823
|
+
return chunks;
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* Split by a specific interval
|
|
827
|
+
*/
|
|
828
|
+
splitBy(interval) {
|
|
829
|
+
if (this._end === null) {
|
|
830
|
+
throw new Error('Cannot split unbounded period');
|
|
831
|
+
}
|
|
832
|
+
const splitInterval = interval instanceof interval_1.ChronosInterval
|
|
833
|
+
? interval
|
|
834
|
+
: interval_1.ChronosInterval.create(interval);
|
|
835
|
+
const chunks = [];
|
|
836
|
+
let current = this._start.clone();
|
|
837
|
+
while (current.isSameOrBefore(this._end)) {
|
|
838
|
+
const chunkEnd = current
|
|
839
|
+
.add(splitInterval.toDuration())
|
|
840
|
+
.subtract({ days: 1 });
|
|
841
|
+
const end = chunkEnd.isAfter(this._end) ? this._end : chunkEnd;
|
|
842
|
+
chunks.push(new ChronosPeriod(current, end, this._interval));
|
|
843
|
+
current = current.add(splitInterval.toDuration());
|
|
844
|
+
}
|
|
845
|
+
return chunks;
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* Split the period by a specified number of days
|
|
849
|
+
*/
|
|
850
|
+
splitByDays(days) {
|
|
851
|
+
return this.splitBy({ days });
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* Split the period by a specified number of weeks
|
|
855
|
+
*/
|
|
856
|
+
splitByWeeks(weeks) {
|
|
857
|
+
return this.splitBy({ weeks });
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* Split the period by a specified number of months
|
|
861
|
+
*/
|
|
862
|
+
splitByMonths(months) {
|
|
863
|
+
return this.splitBy({ months });
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Split the period by a specified number of years
|
|
867
|
+
*/
|
|
868
|
+
splitByYears(years) {
|
|
869
|
+
return this.splitBy({ years });
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* Skip specific dates from the period iteration
|
|
873
|
+
* @param dates - Dates to exclude from iteration
|
|
874
|
+
*/
|
|
875
|
+
skip(dates) {
|
|
876
|
+
const skipDates = dates.map((d) => chronos_1.Chronos.parse(d).format('YYYY-MM-DD'));
|
|
877
|
+
return this.filter((date) => !skipDates.includes(date.format('YYYY-MM-DD')));
|
|
878
|
+
}
|
|
879
|
+
// ============================================================================
|
|
880
|
+
// Formatting
|
|
881
|
+
// ============================================================================
|
|
882
|
+
/**
|
|
883
|
+
* Convert to ISO 8601 string
|
|
884
|
+
*/
|
|
885
|
+
toISO() {
|
|
886
|
+
let iso = '';
|
|
887
|
+
if (this._recurrences !== null && this._recurrences !== Infinity) {
|
|
888
|
+
iso += `R${this._recurrences}/`;
|
|
889
|
+
}
|
|
890
|
+
else if (this._recurrences === Infinity) {
|
|
891
|
+
iso += 'R/';
|
|
892
|
+
}
|
|
893
|
+
iso += this._start.toISOString().split('T')[0];
|
|
894
|
+
iso += '/';
|
|
895
|
+
if (this._end) {
|
|
896
|
+
iso += this._end.toISOString().split('T')[0];
|
|
897
|
+
}
|
|
898
|
+
else {
|
|
899
|
+
iso += this._interval.toISO();
|
|
900
|
+
}
|
|
901
|
+
return iso;
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* Convert to string
|
|
905
|
+
*/
|
|
906
|
+
toString() {
|
|
907
|
+
const start = this._start.format('YYYY-MM-DD');
|
|
908
|
+
const end = this._end ? this._end.format('YYYY-MM-DD') : '...';
|
|
909
|
+
return `${start} to ${end}`;
|
|
910
|
+
}
|
|
911
|
+
/**
|
|
912
|
+
* Convert to human-readable string
|
|
913
|
+
*/
|
|
914
|
+
forHumans() {
|
|
915
|
+
const count = this.count();
|
|
916
|
+
const start = this._start.format('MMMM D, YYYY');
|
|
917
|
+
const end = this._end ? this._end.format('MMMM D, YYYY') : 'indefinitely';
|
|
918
|
+
return `${count} dates from ${start} to ${end}`;
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* Convert to JSON
|
|
922
|
+
*/
|
|
923
|
+
toJSON() {
|
|
924
|
+
var _a, _b;
|
|
925
|
+
return {
|
|
926
|
+
start: this._start.toISOString(),
|
|
927
|
+
end: (_b = (_a = this._end) === null || _a === void 0 ? void 0 : _a.toISOString()) !== null && _b !== void 0 ? _b : null,
|
|
928
|
+
interval: this._interval.toISO(),
|
|
929
|
+
recurrences: this._recurrences,
|
|
930
|
+
options: this._options,
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
// ============================================================================
|
|
934
|
+
// Cloning and Locale
|
|
935
|
+
// ============================================================================
|
|
936
|
+
/**
|
|
937
|
+
* Clone this period
|
|
938
|
+
*/
|
|
939
|
+
clone() {
|
|
940
|
+
var _a;
|
|
941
|
+
const period = new ChronosPeriod(this._start, (_a = this._end) !== null && _a !== void 0 ? _a : undefined, this._interval, Object.assign({}, this._options));
|
|
942
|
+
period._recurrences = this._recurrences;
|
|
943
|
+
period._filters = [...this._filters];
|
|
944
|
+
period._locale = this._locale;
|
|
945
|
+
return period;
|
|
946
|
+
}
|
|
947
|
+
/**
|
|
948
|
+
* Clone for modification (respects immutable option)
|
|
949
|
+
*/
|
|
950
|
+
_cloneForModification() {
|
|
951
|
+
return this._options.immutable ? this.clone() : this;
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* Set locale for this period
|
|
955
|
+
*/
|
|
956
|
+
locale(code) {
|
|
957
|
+
const period = this._cloneForModification();
|
|
958
|
+
period._locale = (0, locales_1.getLocale)(code);
|
|
959
|
+
return period;
|
|
960
|
+
}
|
|
961
|
+
// ============================================================================
|
|
962
|
+
// Static Helpers
|
|
963
|
+
// ============================================================================
|
|
964
|
+
/**
|
|
965
|
+
* Create a period for a specific month
|
|
966
|
+
*/
|
|
967
|
+
static month(year, month) {
|
|
968
|
+
const start = chronos_1.Chronos.create(year, month, 1);
|
|
969
|
+
const end = start.endOf('month');
|
|
970
|
+
return new ChronosPeriod(start, end, { days: 1 });
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* Create a period for a specific year
|
|
974
|
+
*/
|
|
975
|
+
static year(year) {
|
|
976
|
+
const start = chronos_1.Chronos.create(year, 1, 1);
|
|
977
|
+
const end = chronos_1.Chronos.create(year, 12, 31);
|
|
978
|
+
return new ChronosPeriod(start, end, { days: 1 });
|
|
979
|
+
}
|
|
980
|
+
/**
|
|
981
|
+
* Create a period for a specific quarter
|
|
982
|
+
*/
|
|
983
|
+
static quarter(year, quarter) {
|
|
984
|
+
const startMonth = (quarter - 1) * 3 + 1;
|
|
985
|
+
const start = chronos_1.Chronos.create(year, startMonth, 1);
|
|
986
|
+
const end = start.endOf('quarter');
|
|
987
|
+
return new ChronosPeriod(start, end, { days: 1 });
|
|
988
|
+
}
|
|
989
|
+
/**
|
|
990
|
+
* Create a period between two dates as weekdays only
|
|
991
|
+
*/
|
|
992
|
+
static weekdaysBetween(start, end) {
|
|
993
|
+
return ChronosPeriod.create(start, end).weekdays();
|
|
994
|
+
}
|
|
995
|
+
/**
|
|
996
|
+
* Create a period with business days only (weekdays, can add holidays filter)
|
|
997
|
+
*/
|
|
998
|
+
static businessDays(start, end, holidays) {
|
|
999
|
+
let period = ChronosPeriod.create(start, end).weekdays();
|
|
1000
|
+
if (holidays && holidays.length > 0) {
|
|
1001
|
+
const holidayDates = holidays.map((h) => chronos_1.Chronos.parse(h).format('YYYY-MM-DD'));
|
|
1002
|
+
period = period.filter((date) => !holidayDates.includes(date.format('YYYY-MM-DD')));
|
|
1003
|
+
}
|
|
1004
|
+
return period;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
exports.ChronosPeriod = ChronosPeriod;
|