ts-time-utils 1.1.0 → 3.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.
Files changed (92) hide show
  1. package/README.md +567 -12
  2. package/dist/calculate.d.ts +7 -2
  3. package/dist/calculate.d.ts.map +1 -1
  4. package/dist/calculate.js +13 -3
  5. package/dist/calendar.d.ts +103 -0
  6. package/dist/calendar.d.ts.map +1 -1
  7. package/dist/calendar.js +224 -0
  8. package/dist/chain.d.ts +269 -0
  9. package/dist/chain.d.ts.map +1 -0
  10. package/dist/chain.js +422 -0
  11. package/dist/compare.d.ts +217 -0
  12. package/dist/compare.d.ts.map +1 -0
  13. package/dist/compare.js +417 -0
  14. package/dist/cron.d.ts +82 -0
  15. package/dist/cron.d.ts.map +1 -0
  16. package/dist/cron.js +294 -0
  17. package/dist/esm/calculate.d.ts +7 -2
  18. package/dist/esm/calculate.d.ts.map +1 -1
  19. package/dist/esm/calculate.js +13 -3
  20. package/dist/esm/calendar.d.ts +103 -0
  21. package/dist/esm/calendar.d.ts.map +1 -1
  22. package/dist/esm/calendar.js +224 -0
  23. package/dist/esm/chain.d.ts +269 -0
  24. package/dist/esm/chain.d.ts.map +1 -0
  25. package/dist/esm/chain.js +422 -0
  26. package/dist/esm/compare.d.ts +217 -0
  27. package/dist/esm/compare.d.ts.map +1 -0
  28. package/dist/esm/compare.js +417 -0
  29. package/dist/esm/cron.d.ts +82 -0
  30. package/dist/esm/cron.d.ts.map +1 -0
  31. package/dist/esm/cron.js +294 -0
  32. package/dist/esm/fiscal.d.ts +195 -0
  33. package/dist/esm/fiscal.d.ts.map +1 -0
  34. package/dist/esm/fiscal.js +295 -0
  35. package/dist/esm/format.d.ts +65 -0
  36. package/dist/esm/format.d.ts.map +1 -1
  37. package/dist/esm/format.js +202 -0
  38. package/dist/esm/holidays.d.ts +62 -0
  39. package/dist/esm/holidays.d.ts.map +1 -0
  40. package/dist/esm/holidays.js +793 -0
  41. package/dist/esm/index.d.ts +18 -6
  42. package/dist/esm/index.d.ts.map +1 -1
  43. package/dist/esm/index.js +20 -6
  44. package/dist/esm/iterate.d.ts +212 -0
  45. package/dist/esm/iterate.d.ts.map +1 -0
  46. package/dist/esm/iterate.js +409 -0
  47. package/dist/esm/parse.d.ts +45 -0
  48. package/dist/esm/parse.d.ts.map +1 -1
  49. package/dist/esm/parse.js +207 -0
  50. package/dist/esm/plugins.d.ts +129 -0
  51. package/dist/esm/plugins.d.ts.map +1 -0
  52. package/dist/esm/plugins.js +173 -0
  53. package/dist/esm/timezone.d.ts +52 -0
  54. package/dist/esm/timezone.d.ts.map +1 -1
  55. package/dist/esm/timezone.js +171 -0
  56. package/dist/esm/validate.d.ts +51 -0
  57. package/dist/esm/validate.d.ts.map +1 -1
  58. package/dist/esm/validate.js +92 -0
  59. package/dist/esm/workingHours.d.ts +70 -0
  60. package/dist/esm/workingHours.d.ts.map +1 -1
  61. package/dist/esm/workingHours.js +161 -0
  62. package/dist/fiscal.d.ts +195 -0
  63. package/dist/fiscal.d.ts.map +1 -0
  64. package/dist/fiscal.js +295 -0
  65. package/dist/format.d.ts +65 -0
  66. package/dist/format.d.ts.map +1 -1
  67. package/dist/format.js +202 -0
  68. package/dist/holidays.d.ts +62 -0
  69. package/dist/holidays.d.ts.map +1 -0
  70. package/dist/holidays.js +793 -0
  71. package/dist/index.d.ts +18 -6
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js +20 -6
  74. package/dist/iterate.d.ts +212 -0
  75. package/dist/iterate.d.ts.map +1 -0
  76. package/dist/iterate.js +409 -0
  77. package/dist/parse.d.ts +45 -0
  78. package/dist/parse.d.ts.map +1 -1
  79. package/dist/parse.js +207 -0
  80. package/dist/plugins.d.ts +129 -0
  81. package/dist/plugins.d.ts.map +1 -0
  82. package/dist/plugins.js +173 -0
  83. package/dist/timezone.d.ts +52 -0
  84. package/dist/timezone.d.ts.map +1 -1
  85. package/dist/timezone.js +171 -0
  86. package/dist/validate.d.ts +51 -0
  87. package/dist/validate.d.ts.map +1 -1
  88. package/dist/validate.js +92 -0
  89. package/dist/workingHours.d.ts +70 -0
  90. package/dist/workingHours.d.ts.map +1 -1
  91. package/dist/workingHours.js +161 -0
  92. package/package.json +40 -1
@@ -0,0 +1,409 @@
1
+ /**
2
+ * @fileoverview Date iteration utilities for generating date sequences
3
+ */
4
+ /**
5
+ * Generate an array of dates for each day in a range
6
+ * @param start - Start date (inclusive)
7
+ * @param end - End date (inclusive)
8
+ * @returns Array of dates, one per day
9
+ * @example
10
+ * eachDay(new Date('2024-01-01'), new Date('2024-01-05'))
11
+ * // [Jan 1, Jan 2, Jan 3, Jan 4, Jan 5]
12
+ */
13
+ export function eachDay(start, end) {
14
+ const result = [];
15
+ const current = new Date(start.getFullYear(), start.getMonth(), start.getDate());
16
+ const endDate = new Date(end.getFullYear(), end.getMonth(), end.getDate());
17
+ while (current <= endDate) {
18
+ result.push(new Date(current));
19
+ current.setDate(current.getDate() + 1);
20
+ }
21
+ return result;
22
+ }
23
+ /**
24
+ * Generate an array of dates for each weekday (Mon-Fri) in a range
25
+ * @param start - Start date (inclusive)
26
+ * @param end - End date (inclusive)
27
+ * @returns Array of weekday dates
28
+ * @example
29
+ * eachWeekday(new Date('2024-01-01'), new Date('2024-01-07'))
30
+ * // [Jan 1 (Mon), Jan 2 (Tue), Jan 3 (Wed), Jan 4 (Thu), Jan 5 (Fri)]
31
+ */
32
+ export function eachWeekday(start, end) {
33
+ const result = [];
34
+ const current = new Date(start.getFullYear(), start.getMonth(), start.getDate());
35
+ const endDate = new Date(end.getFullYear(), end.getMonth(), end.getDate());
36
+ while (current <= endDate) {
37
+ const day = current.getDay();
38
+ if (day !== 0 && day !== 6) {
39
+ result.push(new Date(current));
40
+ }
41
+ current.setDate(current.getDate() + 1);
42
+ }
43
+ return result;
44
+ }
45
+ /**
46
+ * Generate an array of dates for each weekend day (Sat-Sun) in a range
47
+ * @param start - Start date (inclusive)
48
+ * @param end - End date (inclusive)
49
+ * @returns Array of weekend dates
50
+ */
51
+ export function eachWeekend(start, end) {
52
+ const result = [];
53
+ const current = new Date(start.getFullYear(), start.getMonth(), start.getDate());
54
+ const endDate = new Date(end.getFullYear(), end.getMonth(), end.getDate());
55
+ while (current <= endDate) {
56
+ const day = current.getDay();
57
+ if (day === 0 || day === 6) {
58
+ result.push(new Date(current));
59
+ }
60
+ current.setDate(current.getDate() + 1);
61
+ }
62
+ return result;
63
+ }
64
+ /**
65
+ * Generate an array of dates for each week start in a range
66
+ * @param start - Start date (inclusive)
67
+ * @param end - End date (inclusive)
68
+ * @param weekStartsOn - Day week starts on (0=Sunday, 1=Monday, default: 0)
69
+ * @returns Array of week start dates
70
+ * @example
71
+ * eachWeek(new Date('2024-01-01'), new Date('2024-01-31'))
72
+ * // [Jan 7, Jan 14, Jan 21, Jan 28] (Sundays)
73
+ */
74
+ export function eachWeek(start, end, weekStartsOn = 0) {
75
+ const result = [];
76
+ const current = new Date(start.getFullYear(), start.getMonth(), start.getDate());
77
+ const endDate = new Date(end.getFullYear(), end.getMonth(), end.getDate());
78
+ // Move to first week start on or after start date
79
+ const dayDiff = (current.getDay() - weekStartsOn + 7) % 7;
80
+ if (dayDiff > 0) {
81
+ current.setDate(current.getDate() + (7 - dayDiff));
82
+ }
83
+ while (current <= endDate) {
84
+ result.push(new Date(current));
85
+ current.setDate(current.getDate() + 7);
86
+ }
87
+ return result;
88
+ }
89
+ /**
90
+ * Generate an array of dates for the first day of each month in a range
91
+ * @param start - Start date (inclusive)
92
+ * @param end - End date (inclusive)
93
+ * @returns Array of first-of-month dates
94
+ * @example
95
+ * eachMonth(new Date('2024-01-15'), new Date('2024-04-15'))
96
+ * // [Feb 1, Mar 1, Apr 1]
97
+ */
98
+ export function eachMonth(start, end) {
99
+ const result = [];
100
+ const current = new Date(start.getFullYear(), start.getMonth() + 1, 1);
101
+ const endDate = new Date(end.getFullYear(), end.getMonth(), end.getDate());
102
+ while (current <= endDate) {
103
+ result.push(new Date(current));
104
+ current.setMonth(current.getMonth() + 1);
105
+ }
106
+ return result;
107
+ }
108
+ /**
109
+ * Generate an array of dates for the first day of each quarter in a range
110
+ * @param start - Start date (inclusive)
111
+ * @param end - End date (inclusive)
112
+ * @returns Array of quarter start dates
113
+ */
114
+ export function eachQuarter(start, end) {
115
+ const result = [];
116
+ // Start from beginning of next quarter after start date
117
+ const startMonth = start.getMonth();
118
+ const nextQuarterMonth = Math.ceil((startMonth + 1) / 3) * 3;
119
+ const current = new Date(nextQuarterMonth > 11 ? start.getFullYear() + 1 : start.getFullYear(), nextQuarterMonth % 12, 1);
120
+ const endDate = new Date(end.getFullYear(), end.getMonth(), end.getDate());
121
+ while (current <= endDate) {
122
+ result.push(new Date(current));
123
+ current.setMonth(current.getMonth() + 3);
124
+ }
125
+ return result;
126
+ }
127
+ /**
128
+ * Generate an array of dates for January 1st of each year in a range
129
+ * @param start - Start date (inclusive)
130
+ * @param end - End date (inclusive)
131
+ * @returns Array of year start dates
132
+ */
133
+ export function eachYear(start, end) {
134
+ const result = [];
135
+ const startYear = start.getMonth() === 0 && start.getDate() === 1
136
+ ? start.getFullYear()
137
+ : start.getFullYear() + 1;
138
+ const endYear = end.getFullYear();
139
+ for (let year = startYear; year <= endYear; year++) {
140
+ result.push(new Date(year, 0, 1));
141
+ }
142
+ return result;
143
+ }
144
+ /**
145
+ * Generate an array of dates at regular hour intervals
146
+ * @param start - Start date/time (inclusive)
147
+ * @param end - End date/time (inclusive)
148
+ * @param step - Hour interval (default: 1)
149
+ * @returns Array of dates at each interval
150
+ * @example
151
+ * eachHour(new Date('2024-01-01T09:00'), new Date('2024-01-01T12:00'))
152
+ * // [9:00, 10:00, 11:00, 12:00]
153
+ */
154
+ export function eachHour(start, end, step = 1) {
155
+ const result = [];
156
+ const current = new Date(start);
157
+ current.setMinutes(0, 0, 0);
158
+ while (current <= end) {
159
+ result.push(new Date(current));
160
+ current.setHours(current.getHours() + step);
161
+ }
162
+ return result;
163
+ }
164
+ /**
165
+ * Generate an array of dates at regular minute intervals
166
+ * @param start - Start date/time (inclusive)
167
+ * @param end - End date/time (inclusive)
168
+ * @param step - Minute interval (default: 1)
169
+ * @returns Array of dates at each interval
170
+ * @example
171
+ * eachMinute(new Date('2024-01-01T09:00'), new Date('2024-01-01T09:05'))
172
+ * // [9:00, 9:01, 9:02, 9:03, 9:04, 9:05]
173
+ */
174
+ export function eachMinute(start, end, step = 1) {
175
+ const result = [];
176
+ const current = new Date(start);
177
+ current.setSeconds(0, 0);
178
+ while (current <= end) {
179
+ result.push(new Date(current));
180
+ current.setMinutes(current.getMinutes() + step);
181
+ }
182
+ return result;
183
+ }
184
+ /**
185
+ * Generate an array of dates for a specific day of the week in a range
186
+ * @param start - Start date (inclusive)
187
+ * @param end - End date (inclusive)
188
+ * @param dayOfWeek - Day of week (0=Sunday, 1=Monday, ..., 6=Saturday)
189
+ * @returns Array of dates for that day of week
190
+ * @example
191
+ * eachDayOfWeek(new Date('2024-01-01'), new Date('2024-01-31'), 1)
192
+ * // All Mondays in January 2024
193
+ */
194
+ export function eachDayOfWeek(start, end, dayOfWeek) {
195
+ const result = [];
196
+ const current = new Date(start.getFullYear(), start.getMonth(), start.getDate());
197
+ const endDate = new Date(end.getFullYear(), end.getMonth(), end.getDate());
198
+ // Move to first occurrence of dayOfWeek
199
+ const diff = (dayOfWeek - current.getDay() + 7) % 7;
200
+ current.setDate(current.getDate() + diff);
201
+ while (current <= endDate) {
202
+ result.push(new Date(current));
203
+ current.setDate(current.getDate() + 7);
204
+ }
205
+ return result;
206
+ }
207
+ /**
208
+ * Generate dates at a custom interval
209
+ * @param start - Start date (inclusive)
210
+ * @param end - End date (inclusive)
211
+ * @param interval - Interval configuration
212
+ * @returns Array of dates at each interval
213
+ * @example
214
+ * eachInterval(start, end, { days: 3 }) // Every 3 days
215
+ * eachInterval(start, end, { weeks: 2 }) // Every 2 weeks
216
+ * eachInterval(start, end, { hours: 6 }) // Every 6 hours
217
+ */
218
+ export function eachInterval(start, end, interval) {
219
+ const result = [];
220
+ const current = new Date(start);
221
+ while (current <= end) {
222
+ result.push(new Date(current));
223
+ if (interval.years) {
224
+ current.setFullYear(current.getFullYear() + interval.years);
225
+ }
226
+ if (interval.months) {
227
+ current.setMonth(current.getMonth() + interval.months);
228
+ }
229
+ if (interval.weeks) {
230
+ current.setDate(current.getDate() + interval.weeks * 7);
231
+ }
232
+ if (interval.days) {
233
+ current.setDate(current.getDate() + interval.days);
234
+ }
235
+ if (interval.hours) {
236
+ current.setHours(current.getHours() + interval.hours);
237
+ }
238
+ if (interval.minutes) {
239
+ current.setMinutes(current.getMinutes() + interval.minutes);
240
+ }
241
+ if (interval.seconds) {
242
+ current.setSeconds(current.getSeconds() + interval.seconds);
243
+ }
244
+ }
245
+ return result;
246
+ }
247
+ /**
248
+ * Count the number of days in a range
249
+ * @param start - Start date (inclusive)
250
+ * @param end - End date (inclusive)
251
+ * @returns Number of days
252
+ */
253
+ export function countDays(start, end) {
254
+ const startDay = new Date(start.getFullYear(), start.getMonth(), start.getDate());
255
+ const endDay = new Date(end.getFullYear(), end.getMonth(), end.getDate());
256
+ return Math.round((endDay.getTime() - startDay.getTime()) / 86400000) + 1;
257
+ }
258
+ /**
259
+ * Count the number of weekdays in a range
260
+ * @param start - Start date (inclusive)
261
+ * @param end - End date (inclusive)
262
+ * @returns Number of weekdays
263
+ */
264
+ export function countWeekdays(start, end) {
265
+ return eachWeekday(start, end).length;
266
+ }
267
+ /**
268
+ * Count the number of weekend days in a range
269
+ * @param start - Start date (inclusive)
270
+ * @param end - End date (inclusive)
271
+ * @returns Number of weekend days
272
+ */
273
+ export function countWeekendDays(start, end) {
274
+ return eachWeekend(start, end).length;
275
+ }
276
+ /**
277
+ * Count the number of weeks (complete or partial) in a range
278
+ * @param start - Start date (inclusive)
279
+ * @param end - End date (inclusive)
280
+ * @returns Number of weeks
281
+ */
282
+ export function countWeeks(start, end) {
283
+ const days = countDays(start, end);
284
+ return Math.ceil(days / 7);
285
+ }
286
+ /**
287
+ * Count the number of months in a range
288
+ * @param start - Start date (inclusive)
289
+ * @param end - End date (inclusive)
290
+ * @returns Number of months (partial months count as 1)
291
+ */
292
+ export function countMonths(start, end) {
293
+ const yearDiff = end.getFullYear() - start.getFullYear();
294
+ const monthDiff = end.getMonth() - start.getMonth();
295
+ return yearDiff * 12 + monthDiff + 1;
296
+ }
297
+ /**
298
+ * Iterator for lazy date generation (memory efficient for large ranges)
299
+ * @param start - Start date (inclusive)
300
+ * @param end - End date (inclusive)
301
+ * @param step - Step function to advance the date
302
+ * @yields Date objects
303
+ */
304
+ export function* iterateDates(start, end, step = (d) => d.setDate(d.getDate() + 1)) {
305
+ const current = new Date(start);
306
+ while (current <= end) {
307
+ yield new Date(current);
308
+ step(current);
309
+ }
310
+ }
311
+ /**
312
+ * Create a lazy day iterator
313
+ * @param start - Start date
314
+ * @param end - End date
315
+ * @yields Each day in the range
316
+ */
317
+ export function* iterateDays(start, end) {
318
+ yield* iterateDates(start, end, (d) => d.setDate(d.getDate() + 1));
319
+ }
320
+ /**
321
+ * Create a lazy weekday iterator
322
+ * @param start - Start date
323
+ * @param end - End date
324
+ * @yields Each weekday in the range
325
+ */
326
+ export function* iterateWeekdays(start, end) {
327
+ const current = new Date(start.getFullYear(), start.getMonth(), start.getDate());
328
+ while (current <= end) {
329
+ const day = current.getDay();
330
+ if (day !== 0 && day !== 6) {
331
+ yield new Date(current);
332
+ }
333
+ current.setDate(current.getDate() + 1);
334
+ }
335
+ }
336
+ /**
337
+ * Create a lazy month iterator
338
+ * @param start - Start date
339
+ * @param end - End date
340
+ * @yields First day of each month in the range
341
+ */
342
+ export function* iterateMonths(start, end) {
343
+ const current = new Date(start.getFullYear(), start.getMonth(), 1);
344
+ while (current <= end) {
345
+ yield new Date(current);
346
+ current.setMonth(current.getMonth() + 1);
347
+ }
348
+ }
349
+ /**
350
+ * Generate dates by applying a filter to a range
351
+ * @param start - Start date
352
+ * @param end - End date
353
+ * @param filter - Filter function (return true to include date)
354
+ * @returns Array of filtered dates
355
+ * @example
356
+ * // Get all 15th days of each month
357
+ * filterDays(start, end, d => d.getDate() === 15)
358
+ */
359
+ export function filterDays(start, end, filter) {
360
+ const result = [];
361
+ for (const date of iterateDays(start, end)) {
362
+ if (filter(date)) {
363
+ result.push(date);
364
+ }
365
+ }
366
+ return result;
367
+ }
368
+ /**
369
+ * Generate the last day of each month in a range
370
+ * @param start - Start date
371
+ * @param end - End date
372
+ * @returns Array of last-of-month dates
373
+ */
374
+ export function eachMonthEnd(start, end) {
375
+ const result = [];
376
+ const current = new Date(start.getFullYear(), start.getMonth() + 1, 0);
377
+ const endDate = new Date(end.getFullYear(), end.getMonth(), end.getDate());
378
+ while (current <= endDate) {
379
+ result.push(new Date(current));
380
+ current.setMonth(current.getMonth() + 2);
381
+ current.setDate(0); // Last day of previous month
382
+ }
383
+ return result;
384
+ }
385
+ /**
386
+ * Generate specific day of each month in a range
387
+ * @param start - Start date
388
+ * @param end - End date
389
+ * @param dayOfMonth - Day of month (1-31, will cap at month's max)
390
+ * @returns Array of dates
391
+ * @example
392
+ * eachNthDayOfMonth(start, end, 15) // 15th of each month
393
+ * eachNthDayOfMonth(start, end, 31) // Last day of short months, 31st otherwise
394
+ */
395
+ export function eachNthDayOfMonth(start, end, dayOfMonth) {
396
+ const result = [];
397
+ let current = new Date(start.getFullYear(), start.getMonth(), 1);
398
+ const endDate = new Date(end.getFullYear(), end.getMonth(), end.getDate());
399
+ while (current <= endDate) {
400
+ const daysInMonth = new Date(current.getFullYear(), current.getMonth() + 1, 0).getDate();
401
+ const actualDay = Math.min(dayOfMonth, daysInMonth);
402
+ const date = new Date(current.getFullYear(), current.getMonth(), actualDay);
403
+ if (date >= start && date <= endDate) {
404
+ result.push(date);
405
+ }
406
+ current.setMonth(current.getMonth() + 1);
407
+ }
408
+ return result;
409
+ }
package/dist/parse.d.ts CHANGED
@@ -28,4 +28,49 @@ export declare function parseCustomFormat(dateString: string, format: string): D
28
28
  * @param formats - array of format patterns to try
29
29
  */
30
30
  export declare function parseManyFormats(dateString: string, formats: string[]): Date | null;
31
+ /**
32
+ * Parse an ISO 8601 duration string (e.g., "P1Y2M3DT4H5M6S")
33
+ * @param duration - ISO 8601 duration string
34
+ * @returns object with parsed components
35
+ */
36
+ export declare function parseISO8601Duration(duration: string): {
37
+ years: number;
38
+ months: number;
39
+ weeks: number;
40
+ days: number;
41
+ hours: number;
42
+ minutes: number;
43
+ seconds: number;
44
+ } | null;
45
+ /**
46
+ * Convert ISO 8601 duration to milliseconds (approximate for months/years)
47
+ * @param duration - ISO 8601 duration string
48
+ */
49
+ export declare function parseISO8601DurationToMs(duration: string): number | null;
50
+ /**
51
+ * Parse a time string (e.g., "14:30", "2:30 PM", "14:30:45")
52
+ * @param timeString - time string to parse
53
+ * @returns object with hours, minutes, seconds, or null if invalid
54
+ */
55
+ export declare function parseTime(timeString: string): {
56
+ hours: number;
57
+ minutes: number;
58
+ seconds: number;
59
+ } | null;
60
+ /**
61
+ * Guess the date format of a date string
62
+ * @param dateString - date string to analyze
63
+ * @returns detected format pattern or null
64
+ */
65
+ export declare function guessDateFormat(dateString: string): string | null;
66
+ /**
67
+ * Parse a date string using auto-detected format
68
+ * @param dateString - date string to parse
69
+ */
70
+ export declare function parseAutoFormat(dateString: string): Date | null;
71
+ /**
72
+ * Parse a date from a natural language date range endpoint
73
+ * @param input - string like "end of month", "start of year", "beginning of week"
74
+ */
75
+ export declare function parseRangeEndpoint(input: string): Date | null;
31
76
  //# sourceMappingURL=parse.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAuDpE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CA6C5D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAiBvD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAmDjF;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,GAAG,IAAI,CAMnF"}
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAuDpE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CA6C5D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAiBvD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAmDjF;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,GAAG,IAAI,CAMnF;AAqCD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,IAAI,CA4CP;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAqBxE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,IAAI,CAuCP;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAoCjE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAmB/D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CA2C7D"}
package/dist/parse.js CHANGED
@@ -215,3 +215,210 @@ function addTimeUnits(date, amount, unit) {
215
215
  function subtractTimeUnits(date, amount, unit) {
216
216
  return addTimeUnits(date, -amount, unit);
217
217
  }
218
+ /**
219
+ * Parse an ISO 8601 duration string (e.g., "P1Y2M3DT4H5M6S")
220
+ * @param duration - ISO 8601 duration string
221
+ * @returns object with parsed components
222
+ */
223
+ export function parseISO8601Duration(duration) {
224
+ // ISO 8601 duration format: P[n]Y[n]M[n]DT[n]H[n]M[n]S or P[n]W
225
+ const result = {
226
+ years: 0,
227
+ months: 0,
228
+ weeks: 0,
229
+ days: 0,
230
+ hours: 0,
231
+ minutes: 0,
232
+ seconds: 0,
233
+ };
234
+ const normalized = duration.toUpperCase().trim();
235
+ if (!normalized.startsWith('P')) {
236
+ return null;
237
+ }
238
+ // Handle week format: P[n]W
239
+ const weekMatch = normalized.match(/^P(\d+)W$/);
240
+ if (weekMatch) {
241
+ result.weeks = parseInt(weekMatch[1]);
242
+ return result;
243
+ }
244
+ // Full format: P[n]Y[n]M[n]DT[n]H[n]M[n]S
245
+ const fullMatch = normalized.match(/^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/);
246
+ if (!fullMatch) {
247
+ return null;
248
+ }
249
+ const [, years, months, days, hours, minutes, seconds] = fullMatch;
250
+ if (years)
251
+ result.years = parseInt(years);
252
+ if (months)
253
+ result.months = parseInt(months);
254
+ if (days)
255
+ result.days = parseInt(days);
256
+ if (hours)
257
+ result.hours = parseInt(hours);
258
+ if (minutes)
259
+ result.minutes = parseInt(minutes);
260
+ if (seconds)
261
+ result.seconds = parseFloat(seconds);
262
+ return result;
263
+ }
264
+ /**
265
+ * Convert ISO 8601 duration to milliseconds (approximate for months/years)
266
+ * @param duration - ISO 8601 duration string
267
+ */
268
+ export function parseISO8601DurationToMs(duration) {
269
+ const parsed = parseISO8601Duration(duration);
270
+ if (!parsed)
271
+ return null;
272
+ const MS_PER_SECOND = 1000;
273
+ const MS_PER_MINUTE = 60 * MS_PER_SECOND;
274
+ const MS_PER_HOUR = 60 * MS_PER_MINUTE;
275
+ const MS_PER_DAY = 24 * MS_PER_HOUR;
276
+ const MS_PER_WEEK = 7 * MS_PER_DAY;
277
+ const MS_PER_MONTH = 30 * MS_PER_DAY; // Approximate
278
+ const MS_PER_YEAR = 365 * MS_PER_DAY; // Approximate
279
+ return (parsed.years * MS_PER_YEAR +
280
+ parsed.months * MS_PER_MONTH +
281
+ parsed.weeks * MS_PER_WEEK +
282
+ parsed.days * MS_PER_DAY +
283
+ parsed.hours * MS_PER_HOUR +
284
+ parsed.minutes * MS_PER_MINUTE +
285
+ parsed.seconds * MS_PER_SECOND);
286
+ }
287
+ /**
288
+ * Parse a time string (e.g., "14:30", "2:30 PM", "14:30:45")
289
+ * @param timeString - time string to parse
290
+ * @returns object with hours, minutes, seconds, or null if invalid
291
+ */
292
+ export function parseTime(timeString) {
293
+ const normalized = timeString.trim();
294
+ // 24-hour format: HH:MM or HH:MM:SS
295
+ const match24 = normalized.match(/^(\d{1,2}):(\d{2})(?::(\d{2}))?$/);
296
+ if (match24) {
297
+ const hours = parseInt(match24[1]);
298
+ const minutes = parseInt(match24[2]);
299
+ const seconds = match24[3] ? parseInt(match24[3]) : 0;
300
+ if (hours >= 0 && hours <= 23 && minutes >= 0 && minutes <= 59 && seconds >= 0 && seconds <= 59) {
301
+ return { hours, minutes, seconds };
302
+ }
303
+ return null;
304
+ }
305
+ // 12-hour format: H:MM AM/PM or HH:MM AM/PM
306
+ const match12 = normalized.match(/^(\d{1,2}):(\d{2})(?::(\d{2}))?\s*(AM|PM|am|pm)$/i);
307
+ if (match12) {
308
+ let hours = parseInt(match12[1]);
309
+ const minutes = parseInt(match12[2]);
310
+ const seconds = match12[3] ? parseInt(match12[3]) : 0;
311
+ const isPM = match12[4].toLowerCase() === 'pm';
312
+ if (hours < 1 || hours > 12 || minutes < 0 || minutes > 59 || seconds < 0 || seconds > 59) {
313
+ return null;
314
+ }
315
+ // Convert to 24-hour format
316
+ if (isPM && hours !== 12) {
317
+ hours += 12;
318
+ }
319
+ else if (!isPM && hours === 12) {
320
+ hours = 0;
321
+ }
322
+ return { hours, minutes, seconds };
323
+ }
324
+ return null;
325
+ }
326
+ /**
327
+ * Guess the date format of a date string
328
+ * @param dateString - date string to analyze
329
+ * @returns detected format pattern or null
330
+ */
331
+ export function guessDateFormat(dateString) {
332
+ const normalized = dateString.trim();
333
+ // YYYY-MM-DD
334
+ if (/^\d{4}-\d{2}-\d{2}$/.test(normalized)) {
335
+ return 'YYYY-MM-DD';
336
+ }
337
+ // DD/MM/YYYY or MM/DD/YYYY - need to analyze values
338
+ if (/^\d{2}\/\d{2}\/\d{4}$/.test(normalized)) {
339
+ const [first, second] = normalized.split('/').map(Number);
340
+ if (first > 12)
341
+ return 'DD/MM/YYYY'; // First must be day
342
+ if (second > 12)
343
+ return 'MM/DD/YYYY'; // Second must be day
344
+ // Ambiguous - default to US format
345
+ return 'MM/DD/YYYY';
346
+ }
347
+ // DD-MM-YYYY or MM-DD-YYYY
348
+ if (/^\d{2}-\d{2}-\d{4}$/.test(normalized)) {
349
+ const [first, second] = normalized.split('-').map(Number);
350
+ if (first > 12)
351
+ return 'DD-MM-YYYY';
352
+ if (second > 12)
353
+ return 'MM-DD-YYYY';
354
+ return 'MM-DD-YYYY';
355
+ }
356
+ // YYYYMMDD
357
+ if (/^\d{8}$/.test(normalized)) {
358
+ return 'YYYYMMDD';
359
+ }
360
+ // ISO 8601 with time
361
+ if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(normalized)) {
362
+ return 'ISO8601';
363
+ }
364
+ return null;
365
+ }
366
+ /**
367
+ * Parse a date string using auto-detected format
368
+ * @param dateString - date string to parse
369
+ */
370
+ export function parseAutoFormat(dateString) {
371
+ const format = guessDateFormat(dateString);
372
+ if (!format) {
373
+ return parseDate(dateString);
374
+ }
375
+ if (format === 'ISO8601') {
376
+ return parseDate(dateString);
377
+ }
378
+ if (format === 'YYYYMMDD') {
379
+ const year = parseInt(dateString.slice(0, 4));
380
+ const month = parseInt(dateString.slice(4, 6)) - 1;
381
+ const day = parseInt(dateString.slice(6, 8));
382
+ return new Date(year, month, day);
383
+ }
384
+ return parseCustomFormat(dateString, format);
385
+ }
386
+ /**
387
+ * Parse a date from a natural language date range endpoint
388
+ * @param input - string like "end of month", "start of year", "beginning of week"
389
+ */
390
+ export function parseRangeEndpoint(input) {
391
+ const now = new Date();
392
+ const lowercaseInput = input.toLowerCase().trim();
393
+ // Start/beginning of period
394
+ if (lowercaseInput.match(/^(start|beginning)\s+of\s+(this\s+)?(day|today)$/)) {
395
+ return new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0);
396
+ }
397
+ if (lowercaseInput.match(/^(start|beginning)\s+of\s+(this\s+)?week$/)) {
398
+ const day = now.getDay();
399
+ const diff = now.getDate() - day + (day === 0 ? -6 : 1); // Monday
400
+ return new Date(now.getFullYear(), now.getMonth(), diff, 0, 0, 0, 0);
401
+ }
402
+ if (lowercaseInput.match(/^(start|beginning)\s+of\s+(this\s+)?month$/)) {
403
+ return new Date(now.getFullYear(), now.getMonth(), 1, 0, 0, 0, 0);
404
+ }
405
+ if (lowercaseInput.match(/^(start|beginning)\s+of\s+(this\s+)?year$/)) {
406
+ return new Date(now.getFullYear(), 0, 1, 0, 0, 0, 0);
407
+ }
408
+ // End of period
409
+ if (lowercaseInput.match(/^end\s+of\s+(this\s+)?(day|today)$/)) {
410
+ return new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999);
411
+ }
412
+ if (lowercaseInput.match(/^end\s+of\s+(this\s+)?week$/)) {
413
+ const day = now.getDay();
414
+ const diff = now.getDate() - day + (day === 0 ? 0 : 7); // Sunday
415
+ return new Date(now.getFullYear(), now.getMonth(), diff, 23, 59, 59, 999);
416
+ }
417
+ if (lowercaseInput.match(/^end\s+of\s+(this\s+)?month$/)) {
418
+ return new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59, 999);
419
+ }
420
+ if (lowercaseInput.match(/^end\s+of\s+(this\s+)?year$/)) {
421
+ return new Date(now.getFullYear(), 11, 31, 23, 59, 59, 999);
422
+ }
423
+ return null;
424
+ }