ts-time-utils 1.1.0 → 2.0.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.
- package/README.md +458 -12
- package/dist/calculate.d.ts +7 -2
- package/dist/calculate.d.ts.map +1 -1
- package/dist/calculate.js +13 -3
- package/dist/calendar.d.ts +103 -0
- package/dist/calendar.d.ts.map +1 -1
- package/dist/calendar.js +224 -0
- package/dist/compare.d.ts +217 -0
- package/dist/compare.d.ts.map +1 -0
- package/dist/compare.js +417 -0
- package/dist/cron.d.ts +82 -0
- package/dist/cron.d.ts.map +1 -0
- package/dist/cron.js +294 -0
- package/dist/esm/calculate.d.ts +7 -2
- package/dist/esm/calculate.d.ts.map +1 -1
- package/dist/esm/calculate.js +13 -3
- package/dist/esm/calendar.d.ts +103 -0
- package/dist/esm/calendar.d.ts.map +1 -1
- package/dist/esm/calendar.js +224 -0
- package/dist/esm/compare.d.ts +217 -0
- package/dist/esm/compare.d.ts.map +1 -0
- package/dist/esm/compare.js +417 -0
- package/dist/esm/cron.d.ts +82 -0
- package/dist/esm/cron.d.ts.map +1 -0
- package/dist/esm/cron.js +294 -0
- package/dist/esm/fiscal.d.ts +195 -0
- package/dist/esm/fiscal.d.ts.map +1 -0
- package/dist/esm/fiscal.js +295 -0
- package/dist/esm/format.d.ts +65 -0
- package/dist/esm/format.d.ts.map +1 -1
- package/dist/esm/format.js +202 -0
- package/dist/esm/index.d.ts +13 -6
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +14 -6
- package/dist/esm/iterate.d.ts +212 -0
- package/dist/esm/iterate.d.ts.map +1 -0
- package/dist/esm/iterate.js +409 -0
- package/dist/esm/parse.d.ts +45 -0
- package/dist/esm/parse.d.ts.map +1 -1
- package/dist/esm/parse.js +207 -0
- package/dist/esm/timezone.d.ts +52 -0
- package/dist/esm/timezone.d.ts.map +1 -1
- package/dist/esm/timezone.js +171 -0
- package/dist/esm/validate.d.ts +51 -0
- package/dist/esm/validate.d.ts.map +1 -1
- package/dist/esm/validate.js +92 -0
- package/dist/esm/workingHours.d.ts +70 -0
- package/dist/esm/workingHours.d.ts.map +1 -1
- package/dist/esm/workingHours.js +161 -0
- package/dist/fiscal.d.ts +195 -0
- package/dist/fiscal.d.ts.map +1 -0
- package/dist/fiscal.js +295 -0
- package/dist/format.d.ts +65 -0
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +202 -0
- package/dist/index.d.ts +13 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -6
- package/dist/iterate.d.ts +212 -0
- package/dist/iterate.d.ts.map +1 -0
- package/dist/iterate.js +409 -0
- package/dist/parse.d.ts +45 -0
- package/dist/parse.d.ts.map +1 -1
- package/dist/parse.js +207 -0
- package/dist/timezone.d.ts +52 -0
- package/dist/timezone.d.ts.map +1 -1
- package/dist/timezone.js +171 -0
- package/dist/validate.d.ts +51 -0
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +92 -0
- package/dist/workingHours.d.ts +70 -0
- package/dist/workingHours.d.ts.map +1 -1
- package/dist/workingHours.js +161 -0
- package/package.json +30 -11
package/dist/compare.js
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Date comparison, sorting, and array manipulation utilities
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Compare two dates for sorting
|
|
6
|
+
* @param a - First date
|
|
7
|
+
* @param b - Second date
|
|
8
|
+
* @returns Negative if a < b, positive if a > b, 0 if equal
|
|
9
|
+
* @example
|
|
10
|
+
* [date3, date1, date2].sort(compareDates) // [date1, date2, date3]
|
|
11
|
+
*/
|
|
12
|
+
export function compareDates(a, b) {
|
|
13
|
+
return a.getTime() - b.getTime();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Compare two dates in reverse order for sorting
|
|
17
|
+
* @param a - First date
|
|
18
|
+
* @param b - Second date
|
|
19
|
+
* @returns Positive if a < b, negative if a > b, 0 if equal
|
|
20
|
+
* @example
|
|
21
|
+
* [date1, date3, date2].sort(compareDatesDesc) // [date3, date2, date1]
|
|
22
|
+
*/
|
|
23
|
+
export function compareDatesDesc(a, b) {
|
|
24
|
+
return b.getTime() - a.getTime();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Sort an array of dates
|
|
28
|
+
* @param dates - Array of dates to sort
|
|
29
|
+
* @param direction - Sort direction: 'asc' (oldest first) or 'desc' (newest first)
|
|
30
|
+
* @returns New sorted array (does not mutate original)
|
|
31
|
+
* @example
|
|
32
|
+
* sortDates([date3, date1, date2]) // [date1, date2, date3]
|
|
33
|
+
* sortDates([date1, date2, date3], 'desc') // [date3, date2, date1]
|
|
34
|
+
*/
|
|
35
|
+
export function sortDates(dates, direction = 'asc') {
|
|
36
|
+
const sorted = [...dates];
|
|
37
|
+
sorted.sort(direction === 'asc' ? compareDates : compareDatesDesc);
|
|
38
|
+
return sorted;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Find the minimum (earliest) date in an array
|
|
42
|
+
* @param dates - Array of dates
|
|
43
|
+
* @returns The earliest date, or undefined if array is empty
|
|
44
|
+
* @example
|
|
45
|
+
* minDate([date2, date1, date3]) // date1
|
|
46
|
+
*/
|
|
47
|
+
export function minDate(dates) {
|
|
48
|
+
if (dates.length === 0)
|
|
49
|
+
return undefined;
|
|
50
|
+
return dates.reduce((min, date) => (date < min ? date : min));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Find the maximum (latest) date in an array
|
|
54
|
+
* @param dates - Array of dates
|
|
55
|
+
* @returns The latest date, or undefined if array is empty
|
|
56
|
+
* @example
|
|
57
|
+
* maxDate([date1, date3, date2]) // date3
|
|
58
|
+
*/
|
|
59
|
+
export function maxDate(dates) {
|
|
60
|
+
if (dates.length === 0)
|
|
61
|
+
return undefined;
|
|
62
|
+
return dates.reduce((max, date) => (date > max ? date : max));
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Find the date range (min and max) in an array
|
|
66
|
+
* @param dates - Array of dates
|
|
67
|
+
* @returns Object with min and max dates, or undefined if array is empty
|
|
68
|
+
* @example
|
|
69
|
+
* dateRange([date2, date1, date3]) // { min: date1, max: date3 }
|
|
70
|
+
*/
|
|
71
|
+
export function dateExtent(dates) {
|
|
72
|
+
if (dates.length === 0)
|
|
73
|
+
return undefined;
|
|
74
|
+
let min = dates[0];
|
|
75
|
+
let max = dates[0];
|
|
76
|
+
for (const date of dates) {
|
|
77
|
+
if (date < min)
|
|
78
|
+
min = date;
|
|
79
|
+
if (date > max)
|
|
80
|
+
max = date;
|
|
81
|
+
}
|
|
82
|
+
return { min, max };
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Remove duplicate dates from an array
|
|
86
|
+
* @param dates - Array of dates
|
|
87
|
+
* @param precision - Precision for comparison: 'ms' (exact), 'second', 'minute', 'hour', 'day'
|
|
88
|
+
* @returns New array with duplicates removed (preserves first occurrence)
|
|
89
|
+
* @example
|
|
90
|
+
* uniqueDates([date1, date1Copy, date2]) // [date1, date2]
|
|
91
|
+
*/
|
|
92
|
+
export function uniqueDates(dates, precision = 'ms') {
|
|
93
|
+
const seen = new Set();
|
|
94
|
+
const result = [];
|
|
95
|
+
for (const date of dates) {
|
|
96
|
+
const key = getDateKey(date, precision);
|
|
97
|
+
if (!seen.has(key)) {
|
|
98
|
+
seen.add(key);
|
|
99
|
+
result.push(date);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get a numeric key for a date based on precision
|
|
106
|
+
*/
|
|
107
|
+
function getDateKey(date, precision) {
|
|
108
|
+
switch (precision) {
|
|
109
|
+
case 'ms':
|
|
110
|
+
return date.getTime();
|
|
111
|
+
case 'second':
|
|
112
|
+
return Math.floor(date.getTime() / 1000);
|
|
113
|
+
case 'minute':
|
|
114
|
+
return Math.floor(date.getTime() / 60000);
|
|
115
|
+
case 'hour':
|
|
116
|
+
return Math.floor(date.getTime() / 3600000);
|
|
117
|
+
case 'day':
|
|
118
|
+
return Math.floor(date.getTime() / 86400000);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Find the closest date to a target from an array of candidates
|
|
123
|
+
* @param target - The target date
|
|
124
|
+
* @param candidates - Array of candidate dates
|
|
125
|
+
* @returns The closest date, or undefined if candidates is empty
|
|
126
|
+
* @example
|
|
127
|
+
* closestDate(targetDate, [date1, date2, date3]) // closest to target
|
|
128
|
+
*/
|
|
129
|
+
export function closestDate(target, candidates) {
|
|
130
|
+
if (candidates.length === 0)
|
|
131
|
+
return undefined;
|
|
132
|
+
const targetTime = target.getTime();
|
|
133
|
+
let closest = candidates[0];
|
|
134
|
+
let minDiff = Math.abs(closest.getTime() - targetTime);
|
|
135
|
+
for (const candidate of candidates) {
|
|
136
|
+
const diff = Math.abs(candidate.getTime() - targetTime);
|
|
137
|
+
if (diff < minDiff) {
|
|
138
|
+
minDiff = diff;
|
|
139
|
+
closest = candidate;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return closest;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Find the closest future date to a target
|
|
146
|
+
* @param target - The target date
|
|
147
|
+
* @param candidates - Array of candidate dates
|
|
148
|
+
* @returns The closest future date, or undefined if none found
|
|
149
|
+
*/
|
|
150
|
+
export function closestFutureDate(target, candidates) {
|
|
151
|
+
const targetTime = target.getTime();
|
|
152
|
+
const futureDates = candidates.filter(d => d.getTime() > targetTime);
|
|
153
|
+
return minDate(futureDates);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Find the closest past date to a target
|
|
157
|
+
* @param target - The target date
|
|
158
|
+
* @param candidates - Array of candidate dates
|
|
159
|
+
* @returns The closest past date, or undefined if none found
|
|
160
|
+
*/
|
|
161
|
+
export function closestPastDate(target, candidates) {
|
|
162
|
+
const targetTime = target.getTime();
|
|
163
|
+
const pastDates = candidates.filter(d => d.getTime() < targetTime);
|
|
164
|
+
return maxDate(pastDates);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Clamp a date to be within a range
|
|
168
|
+
* @param date - The date to clamp
|
|
169
|
+
* @param min - Minimum allowed date
|
|
170
|
+
* @param max - Maximum allowed date
|
|
171
|
+
* @returns The clamped date
|
|
172
|
+
* @example
|
|
173
|
+
* clampDate(earlyDate, minDate, maxDate) // returns minDate
|
|
174
|
+
* clampDate(lateDate, minDate, maxDate) // returns maxDate
|
|
175
|
+
* clampDate(middleDate, minDate, maxDate) // returns middleDate
|
|
176
|
+
*/
|
|
177
|
+
export function clampDate(date, min, max) {
|
|
178
|
+
if (date < min)
|
|
179
|
+
return new Date(min);
|
|
180
|
+
if (date > max)
|
|
181
|
+
return new Date(max);
|
|
182
|
+
return new Date(date);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Check if a date is within a range (inclusive)
|
|
186
|
+
* @param date - The date to check
|
|
187
|
+
* @param min - Start of range
|
|
188
|
+
* @param max - End of range
|
|
189
|
+
* @returns True if date is within range
|
|
190
|
+
*/
|
|
191
|
+
export function isDateInRange(date, min, max) {
|
|
192
|
+
const time = date.getTime();
|
|
193
|
+
return time >= min.getTime() && time <= max.getTime();
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Filter dates to only those within a range
|
|
197
|
+
* @param dates - Array of dates
|
|
198
|
+
* @param min - Start of range
|
|
199
|
+
* @param max - End of range
|
|
200
|
+
* @returns New array with only dates in range
|
|
201
|
+
*/
|
|
202
|
+
export function filterDatesInRange(dates, min, max) {
|
|
203
|
+
return dates.filter(date => isDateInRange(date, min, max));
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Group dates by a key function
|
|
207
|
+
* @param dates - Array of dates
|
|
208
|
+
* @param keyFn - Function to generate group key from date
|
|
209
|
+
* @returns Map of key to array of dates
|
|
210
|
+
* @example
|
|
211
|
+
* groupDates(dates, d => d.getFullYear()) // Map { 2023 => [...], 2024 => [...] }
|
|
212
|
+
* groupDates(dates, d => d.toISOString().slice(0, 7)) // Group by month
|
|
213
|
+
*/
|
|
214
|
+
export function groupDates(dates, keyFn) {
|
|
215
|
+
const groups = new Map();
|
|
216
|
+
for (const date of dates) {
|
|
217
|
+
const key = keyFn(date);
|
|
218
|
+
const group = groups.get(key);
|
|
219
|
+
if (group) {
|
|
220
|
+
group.push(date);
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
groups.set(key, [date]);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return groups;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Group dates by year
|
|
230
|
+
* @param dates - Array of dates
|
|
231
|
+
* @returns Map of year to array of dates
|
|
232
|
+
*/
|
|
233
|
+
export function groupDatesByYear(dates) {
|
|
234
|
+
return groupDates(dates, d => d.getFullYear());
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Group dates by month (YYYY-MM format)
|
|
238
|
+
* @param dates - Array of dates
|
|
239
|
+
* @returns Map of month key to array of dates
|
|
240
|
+
*/
|
|
241
|
+
export function groupDatesByMonth(dates) {
|
|
242
|
+
return groupDates(dates, d => {
|
|
243
|
+
const year = d.getFullYear();
|
|
244
|
+
const month = String(d.getMonth() + 1).padStart(2, '0');
|
|
245
|
+
return `${year}-${month}`;
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Group dates by day (YYYY-MM-DD format)
|
|
250
|
+
* @param dates - Array of dates
|
|
251
|
+
* @returns Map of day key to array of dates
|
|
252
|
+
*/
|
|
253
|
+
export function groupDatesByDay(dates) {
|
|
254
|
+
return groupDates(dates, d => d.toISOString().slice(0, 10));
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Group dates by day of week (0-6, Sunday-Saturday)
|
|
258
|
+
* @param dates - Array of dates
|
|
259
|
+
* @returns Map of day of week to array of dates
|
|
260
|
+
*/
|
|
261
|
+
export function groupDatesByDayOfWeek(dates) {
|
|
262
|
+
return groupDates(dates, d => d.getDay());
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Calculate the median date from an array
|
|
266
|
+
* @param dates - Array of dates
|
|
267
|
+
* @returns The median date, or undefined if array is empty
|
|
268
|
+
*/
|
|
269
|
+
export function medianDate(dates) {
|
|
270
|
+
if (dates.length === 0)
|
|
271
|
+
return undefined;
|
|
272
|
+
const sorted = sortDates(dates);
|
|
273
|
+
const mid = Math.floor(sorted.length / 2);
|
|
274
|
+
if (sorted.length % 2 === 0) {
|
|
275
|
+
// Average of two middle values
|
|
276
|
+
const time1 = sorted[mid - 1].getTime();
|
|
277
|
+
const time2 = sorted[mid].getTime();
|
|
278
|
+
return new Date((time1 + time2) / 2);
|
|
279
|
+
}
|
|
280
|
+
return new Date(sorted[mid]);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Calculate the average/mean date from an array
|
|
284
|
+
* @param dates - Array of dates
|
|
285
|
+
* @returns The average date, or undefined if array is empty
|
|
286
|
+
*/
|
|
287
|
+
export function averageDate(dates) {
|
|
288
|
+
if (dates.length === 0)
|
|
289
|
+
return undefined;
|
|
290
|
+
const sum = dates.reduce((acc, date) => acc + date.getTime(), 0);
|
|
291
|
+
return new Date(sum / dates.length);
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Round a date to the nearest unit
|
|
295
|
+
* @param date - The date to round
|
|
296
|
+
* @param unit - Unit to round to
|
|
297
|
+
* @returns New rounded date
|
|
298
|
+
* @example
|
|
299
|
+
* roundDate(new Date('2024-03-15T14:37:00'), 'hour') // 2024-03-15T15:00:00
|
|
300
|
+
* roundDate(new Date('2024-03-15T14:22:00'), 'hour') // 2024-03-15T14:00:00
|
|
301
|
+
*/
|
|
302
|
+
export function roundDate(date, unit) {
|
|
303
|
+
const d = new Date(date);
|
|
304
|
+
switch (unit) {
|
|
305
|
+
case 'minute':
|
|
306
|
+
if (d.getSeconds() >= 30) {
|
|
307
|
+
d.setMinutes(d.getMinutes() + 1);
|
|
308
|
+
}
|
|
309
|
+
d.setSeconds(0, 0);
|
|
310
|
+
break;
|
|
311
|
+
case 'hour':
|
|
312
|
+
if (d.getMinutes() >= 30) {
|
|
313
|
+
d.setHours(d.getHours() + 1);
|
|
314
|
+
}
|
|
315
|
+
d.setMinutes(0, 0, 0);
|
|
316
|
+
break;
|
|
317
|
+
case 'day':
|
|
318
|
+
if (d.getHours() >= 12) {
|
|
319
|
+
d.setDate(d.getDate() + 1);
|
|
320
|
+
}
|
|
321
|
+
d.setHours(0, 0, 0, 0);
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
return d;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Snap a date to a grid interval
|
|
328
|
+
* @param date - The date to snap
|
|
329
|
+
* @param intervalMinutes - Interval in minutes (e.g., 15 for quarter-hour)
|
|
330
|
+
* @param mode - Snap mode: 'floor' (down), 'ceil' (up), or 'round' (nearest)
|
|
331
|
+
* @returns New snapped date
|
|
332
|
+
* @example
|
|
333
|
+
* snapDate(new Date('2024-03-15T14:37:00'), 15) // 2024-03-15T14:30:00
|
|
334
|
+
* snapDate(new Date('2024-03-15T14:37:00'), 15, 'ceil') // 2024-03-15T14:45:00
|
|
335
|
+
*/
|
|
336
|
+
export function snapDate(date, intervalMinutes, mode = 'round') {
|
|
337
|
+
const ms = date.getTime();
|
|
338
|
+
const intervalMs = intervalMinutes * 60 * 1000;
|
|
339
|
+
let snapped;
|
|
340
|
+
switch (mode) {
|
|
341
|
+
case 'floor':
|
|
342
|
+
snapped = Math.floor(ms / intervalMs) * intervalMs;
|
|
343
|
+
break;
|
|
344
|
+
case 'ceil':
|
|
345
|
+
snapped = Math.ceil(ms / intervalMs) * intervalMs;
|
|
346
|
+
break;
|
|
347
|
+
case 'round':
|
|
348
|
+
snapped = Math.round(ms / intervalMs) * intervalMs;
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
return new Date(snapped);
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Check if dates are in chronological order
|
|
355
|
+
* @param dates - Array of dates
|
|
356
|
+
* @param strict - If true, requires strictly increasing (no duplicates)
|
|
357
|
+
* @returns True if dates are in order
|
|
358
|
+
*/
|
|
359
|
+
export function isChronological(dates, strict = false) {
|
|
360
|
+
for (let i = 1; i < dates.length; i++) {
|
|
361
|
+
const prev = dates[i - 1].getTime();
|
|
362
|
+
const curr = dates[i].getTime();
|
|
363
|
+
if (strict ? curr <= prev : curr < prev) {
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return true;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Get the span (duration) between min and max dates
|
|
371
|
+
* @param dates - Array of dates
|
|
372
|
+
* @returns Duration in milliseconds, or 0 if less than 2 dates
|
|
373
|
+
*/
|
|
374
|
+
export function dateSpan(dates) {
|
|
375
|
+
const extent = dateExtent(dates);
|
|
376
|
+
if (!extent)
|
|
377
|
+
return 0;
|
|
378
|
+
return extent.max.getTime() - extent.min.getTime();
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Partition dates into buckets based on a predicate
|
|
382
|
+
* @param dates - Array of dates
|
|
383
|
+
* @param predicate - Function that returns true for dates in first partition
|
|
384
|
+
* @returns Tuple of [matching, non-matching] date arrays
|
|
385
|
+
*/
|
|
386
|
+
export function partitionDates(dates, predicate) {
|
|
387
|
+
const matching = [];
|
|
388
|
+
const nonMatching = [];
|
|
389
|
+
for (const date of dates) {
|
|
390
|
+
if (predicate(date)) {
|
|
391
|
+
matching.push(date);
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
nonMatching.push(date);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return [matching, nonMatching];
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Get the nth date from an array (supports negative indices)
|
|
401
|
+
* @param dates - Array of dates (will be sorted)
|
|
402
|
+
* @param n - Index (0-based, negative counts from end)
|
|
403
|
+
* @returns The nth date, or undefined if out of bounds
|
|
404
|
+
* @example
|
|
405
|
+
* nthDate(dates, 0) // earliest
|
|
406
|
+
* nthDate(dates, -1) // latest
|
|
407
|
+
* nthDate(dates, 2) // third earliest
|
|
408
|
+
*/
|
|
409
|
+
export function nthDate(dates, n) {
|
|
410
|
+
if (dates.length === 0)
|
|
411
|
+
return undefined;
|
|
412
|
+
const sorted = sortDates(dates);
|
|
413
|
+
const index = n < 0 ? sorted.length + n : n;
|
|
414
|
+
if (index < 0 || index >= sorted.length)
|
|
415
|
+
return undefined;
|
|
416
|
+
return sorted[index];
|
|
417
|
+
}
|
package/dist/cron.d.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cron expression utilities for scheduling
|
|
3
|
+
*/
|
|
4
|
+
export interface CronParts {
|
|
5
|
+
minute: string;
|
|
6
|
+
hour: string;
|
|
7
|
+
dayOfMonth: string;
|
|
8
|
+
month: string;
|
|
9
|
+
dayOfWeek: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ParsedCronField {
|
|
12
|
+
type: 'all' | 'specific' | 'range' | 'step' | 'list';
|
|
13
|
+
values: number[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Parse a cron expression into its parts
|
|
17
|
+
* @param expression - cron expression (5 fields: minute hour dayOfMonth month dayOfWeek)
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseCronExpression(expression: string): CronParts | null;
|
|
20
|
+
/**
|
|
21
|
+
* Parse a cron field into its numeric values
|
|
22
|
+
* @param field - cron field string (e.g., "star/5", "1-5", "1,2,3", "*")
|
|
23
|
+
* @param min - minimum valid value
|
|
24
|
+
* @param max - maximum valid value
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseCronField(field: string, min: number, max: number): ParsedCronField | null;
|
|
27
|
+
/**
|
|
28
|
+
* Check if a date matches a cron expression
|
|
29
|
+
* @param date - date to check
|
|
30
|
+
* @param expression - cron expression
|
|
31
|
+
*/
|
|
32
|
+
export declare function matchesCron(date: Date, expression: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Get the next date that matches a cron expression
|
|
35
|
+
* @param expression - cron expression
|
|
36
|
+
* @param after - start searching after this date (default: now)
|
|
37
|
+
* @param maxIterations - maximum iterations to prevent infinite loops
|
|
38
|
+
*/
|
|
39
|
+
export declare function getNextCronDate(expression: string, after?: Date, maxIterations?: number): Date | null;
|
|
40
|
+
/**
|
|
41
|
+
* Get the N next dates that match a cron expression
|
|
42
|
+
* @param expression - cron expression
|
|
43
|
+
* @param count - number of dates to get
|
|
44
|
+
* @param after - start searching after this date
|
|
45
|
+
*/
|
|
46
|
+
export declare function getNextCronDates(expression: string, count: number, after?: Date): Date[];
|
|
47
|
+
/**
|
|
48
|
+
* Get the previous date that matched a cron expression
|
|
49
|
+
* @param expression - cron expression
|
|
50
|
+
* @param before - start searching before this date
|
|
51
|
+
* @param maxIterations - maximum iterations to prevent infinite loops
|
|
52
|
+
*/
|
|
53
|
+
export declare function getPreviousCronDate(expression: string, before?: Date, maxIterations?: number): Date | null;
|
|
54
|
+
/**
|
|
55
|
+
* Validate a cron expression
|
|
56
|
+
* @param expression - cron expression to validate
|
|
57
|
+
*/
|
|
58
|
+
export declare function isValidCron(expression: string): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Convert a cron expression to a human-readable description
|
|
61
|
+
* @param expression - cron expression
|
|
62
|
+
*/
|
|
63
|
+
export declare function describeCron(expression: string): string | null;
|
|
64
|
+
/**
|
|
65
|
+
* Common cron expressions
|
|
66
|
+
*/
|
|
67
|
+
export declare const CRON_PRESETS: {
|
|
68
|
+
readonly everyMinute: "* * * * *";
|
|
69
|
+
readonly everyHour: "0 * * * *";
|
|
70
|
+
readonly everyDay: "0 0 * * *";
|
|
71
|
+
readonly everyDayAt9am: "0 9 * * *";
|
|
72
|
+
readonly everyDayAt6pm: "0 18 * * *";
|
|
73
|
+
readonly everyWeek: "0 0 * * 0";
|
|
74
|
+
readonly everyMonth: "0 0 1 * *";
|
|
75
|
+
readonly everyYear: "0 0 1 1 *";
|
|
76
|
+
readonly weekdays: "0 0 * * 1-5";
|
|
77
|
+
readonly weekends: "0 0 * * 0,6";
|
|
78
|
+
readonly every5Minutes: "*/5 * * * *";
|
|
79
|
+
readonly every15Minutes: "*/15 * * * *";
|
|
80
|
+
readonly every30Minutes: "*/30 * * * *";
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=cron.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.d.ts","sourceRoot":"","sources":["../src/cron.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,KAAK,GAAG,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IACrD,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAcxE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CA+D9F;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAqBnE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,KAAK,GAAE,IAAiB,EACxB,aAAa,GAAE,MAAe,GAC7B,IAAI,GAAG,IAAI,CAiCb;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,GAAE,IAAiB,GACvB,IAAI,EAAE,CAYR;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,IAAiB,EACzB,aAAa,GAAE,MAAe,GAC7B,IAAI,GAAG,IAAI,CAiCb;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAWvD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAwE9D;AAED;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;CAcf,CAAC"}
|