ts-time-utils 1.0.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.
Files changed (102) hide show
  1. package/README.md +682 -11
  2. package/dist/calculate.d.ts +7 -2
  3. package/dist/calculate.d.ts.map +1 -1
  4. package/dist/calculate.js +37 -13
  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/compare.d.ts +217 -0
  9. package/dist/compare.d.ts.map +1 -0
  10. package/dist/compare.js +417 -0
  11. package/dist/countdown.d.ts +217 -0
  12. package/dist/countdown.d.ts.map +1 -0
  13. package/dist/countdown.js +298 -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/dateRange.d.ts +266 -0
  18. package/dist/dateRange.d.ts.map +1 -0
  19. package/dist/dateRange.js +433 -0
  20. package/dist/esm/calculate.d.ts +7 -2
  21. package/dist/esm/calculate.d.ts.map +1 -1
  22. package/dist/esm/calculate.js +37 -13
  23. package/dist/esm/calendar.d.ts +103 -0
  24. package/dist/esm/calendar.d.ts.map +1 -1
  25. package/dist/esm/calendar.js +224 -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/countdown.d.ts +217 -0
  30. package/dist/esm/countdown.d.ts.map +1 -0
  31. package/dist/esm/countdown.js +298 -0
  32. package/dist/esm/cron.d.ts +82 -0
  33. package/dist/esm/cron.d.ts.map +1 -0
  34. package/dist/esm/cron.js +294 -0
  35. package/dist/esm/dateRange.d.ts +266 -0
  36. package/dist/esm/dateRange.d.ts.map +1 -0
  37. package/dist/esm/dateRange.js +433 -0
  38. package/dist/esm/fiscal.d.ts +195 -0
  39. package/dist/esm/fiscal.d.ts.map +1 -0
  40. package/dist/esm/fiscal.js +295 -0
  41. package/dist/esm/format.d.ts +65 -0
  42. package/dist/esm/format.d.ts.map +1 -1
  43. package/dist/esm/format.js +202 -0
  44. package/dist/esm/index.d.ts +18 -7
  45. package/dist/esm/index.d.ts.map +1 -1
  46. package/dist/esm/index.js +22 -6
  47. package/dist/esm/iterate.d.ts +212 -0
  48. package/dist/esm/iterate.d.ts.map +1 -0
  49. package/dist/esm/iterate.js +409 -0
  50. package/dist/esm/naturalLanguage.d.ts +107 -0
  51. package/dist/esm/naturalLanguage.d.ts.map +1 -0
  52. package/dist/esm/naturalLanguage.js +344 -0
  53. package/dist/esm/parse.d.ts +45 -0
  54. package/dist/esm/parse.d.ts.map +1 -1
  55. package/dist/esm/parse.js +207 -0
  56. package/dist/esm/recurrence.d.ts +149 -0
  57. package/dist/esm/recurrence.d.ts.map +1 -0
  58. package/dist/esm/recurrence.js +404 -0
  59. package/dist/esm/timezone.d.ts +52 -0
  60. package/dist/esm/timezone.d.ts.map +1 -1
  61. package/dist/esm/timezone.js +171 -0
  62. package/dist/esm/types.d.ts +21 -0
  63. package/dist/esm/types.d.ts.map +1 -1
  64. package/dist/esm/validate.d.ts +51 -0
  65. package/dist/esm/validate.d.ts.map +1 -1
  66. package/dist/esm/validate.js +92 -0
  67. package/dist/esm/workingHours.d.ts +70 -0
  68. package/dist/esm/workingHours.d.ts.map +1 -1
  69. package/dist/esm/workingHours.js +161 -0
  70. package/dist/fiscal.d.ts +195 -0
  71. package/dist/fiscal.d.ts.map +1 -0
  72. package/dist/fiscal.js +295 -0
  73. package/dist/format.d.ts +65 -0
  74. package/dist/format.d.ts.map +1 -1
  75. package/dist/format.js +202 -0
  76. package/dist/index.d.ts +18 -7
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +22 -6
  79. package/dist/iterate.d.ts +212 -0
  80. package/dist/iterate.d.ts.map +1 -0
  81. package/dist/iterate.js +409 -0
  82. package/dist/naturalLanguage.d.ts +107 -0
  83. package/dist/naturalLanguage.d.ts.map +1 -0
  84. package/dist/naturalLanguage.js +344 -0
  85. package/dist/parse.d.ts +45 -0
  86. package/dist/parse.d.ts.map +1 -1
  87. package/dist/parse.js +207 -0
  88. package/dist/recurrence.d.ts +149 -0
  89. package/dist/recurrence.d.ts.map +1 -0
  90. package/dist/recurrence.js +404 -0
  91. package/dist/timezone.d.ts +52 -0
  92. package/dist/timezone.d.ts.map +1 -1
  93. package/dist/timezone.js +171 -0
  94. package/dist/types.d.ts +21 -0
  95. package/dist/types.d.ts.map +1 -1
  96. package/dist/validate.d.ts +51 -0
  97. package/dist/validate.d.ts.map +1 -1
  98. package/dist/validate.js +92 -0
  99. package/dist/workingHours.d.ts +70 -0
  100. package/dist/workingHours.d.ts.map +1 -1
  101. package/dist/workingHours.js +161 -0
  102. package/package.json +59 -12
package/README.md CHANGED
@@ -8,7 +8,43 @@ A lightweight TypeScript utility library for time formatting, calculations, and
8
8
  - **⚡ Fast** - Zero dependencies, pure JavaScript functions
9
9
  - **🔧 TypeScript** - Full type safety and IntelliSense support
10
10
  - **🌳 Tree-shakable** - Import individual functions to minimize bundle size
11
- - **📚 Comprehensive** - 15 utility categories with 115+ functions
11
+ - **📚 Comprehensive** - 25 utility categories with 287+ functions
12
+
13
+ ### 🔄 Recurrence utilities **(NEW!)**
14
+
15
+ - RRULE-inspired recurring event patterns
16
+ - Daily, weekly, monthly, and yearly recurrences
17
+ - Complex recurrence rules with byWeekday, byMonthDay, byMonth
18
+ - Get next occurrence, all occurrences, or occurrences within range
19
+ - Human-readable recurrence descriptions
20
+ - Full support for count and until limits
21
+
22
+ ### ⏲️ Countdown & Timer utilities **(NEW!)**
23
+
24
+ - Real-time countdown timers with callbacks
25
+ - Get remaining time broken down by units
26
+ - Format countdowns as human-readable strings
27
+ - Check if dates are expired
28
+ - Calculate progress percentage between dates
29
+ - Deadline tracking with helper methods
30
+
31
+ ### 📊 Date Range utilities **(NEW!)**
32
+
33
+ - Advanced range operations (overlap, intersection, union)
34
+ - Merge overlapping ranges
35
+ - Find gaps between ranges
36
+ - Split ranges into chunks
37
+ - Expand and shrink ranges
38
+ - Subtract ranges from each other
39
+ - Check containment and sort ranges
40
+
41
+ ### 💬 Natural Language Parsing **(NEW!)**
42
+
43
+ - Parse human-friendly date strings ("tomorrow", "next Friday", "in 2 weeks")
44
+ - Extract dates from text automatically
45
+ - Context-aware date suggestions ("end of month", "EOY")
46
+ - Support for relative phrases and absolute dates
47
+ - Confidence scoring for extracted dates
12
48
 
13
49
  ### ⏱️ Duration utilities
14
50
 
@@ -34,6 +70,9 @@ A lightweight TypeScript utility library for time formatting, calculations, and
34
70
  - Get human-friendly "time ago" strings
35
71
  - Parse duration strings back to milliseconds
36
72
  - Format time in 12h/24h/ISO formats
73
+ - Custom date formatting with pattern strings (YYYY-MM-DD, etc.)
74
+ - Format date ranges and ordinals
75
+ - Calendar-friendly date formatting ("Today", "Tomorrow", "Monday")
37
76
 
38
77
  ### 🧮 Calculation utilities
39
78
 
@@ -47,7 +86,10 @@ A lightweight TypeScript utility library for time formatting, calculations, and
47
86
 
48
87
  - Validate dates and time strings
49
88
  - Check for leap years, weekends, past/future dates
50
- - Compare dates (same day, today, yesterday, etc.)
89
+ - Compare dates (same day, same week, same month, same year)
90
+ - Check relative periods (isThisWeek, isThisMonth, isThisYear)
91
+ - Business day validation with holiday support
92
+ - Check if date is within last/next N days
51
93
 
52
94
  ### 🎂 Age utilities
53
95
 
@@ -60,8 +102,12 @@ A lightweight TypeScript utility library for time formatting, calculations, and
60
102
 
61
103
  - ISO week numbers and week-based calculations
62
104
  - Quarter operations and fiscal year support
63
- - Holiday calculations (Easter, Thanksgiving, etc.)
105
+ - Holiday calculations (Easter, US federal holidays)
64
106
  - Days in month/year calculations
107
+ - Get nth occurrence of weekday in month
108
+ - US holiday functions (Thanksgiving, Memorial Day, Labor Day, etc.)
109
+ - Week start/end calculations
110
+ - Calendar grid generation
65
111
 
66
112
  ### 🔍 Parse utilities
67
113
 
@@ -69,6 +115,10 @@ A lightweight TypeScript utility library for time formatting, calculations, and
69
115
  - Relative date parsing ("tomorrow", "next week")
70
116
  - Custom format parsing with flexible patterns
71
117
  - Smart date interpretation
118
+ - ISO 8601 duration parsing (P1Y2M3DT4H5M6S)
119
+ - Time string parsing (14:30, 2:30 PM)
120
+ - Auto-detect date format
121
+ - Parse range endpoints ("end of month", "start of year")
72
122
 
73
123
  ### ⚡ Performance utilities
74
124
 
@@ -91,14 +141,22 @@ A lightweight TypeScript utility library for time formatting, calculations, and
91
141
  - Format in specific timezone
92
142
  - Convert absolute moment to zone components
93
143
  - Reinterpret wall-clock times
144
+ - Daylight Saving Time detection
145
+ - Find next DST transition
146
+ - Find common working hours across timezones
147
+ - Convert dates between timezones
94
148
 
95
149
  ### 🕘 Working hours utilities
96
150
 
97
151
  - Define working day patterns and breaks
98
152
  - Check working day/time
99
153
  - Compute working time between dates
100
- - Add working hours across days
101
- - Find next working time
154
+ - Add/subtract working hours and days
155
+ - Find next/previous working day
156
+ - Get working days in month
157
+ - Count working days between dates
158
+ - Break time detection
159
+ - Work day start/end times
102
160
 
103
161
  ### 🎯 Range preset utilities
104
162
 
@@ -117,6 +175,47 @@ A lightweight TypeScript utility library for time formatting, calculations, and
117
175
  - Internationalization (i18n) support
118
176
  - **Locale conversions** - Convert between different locales and detect locale from text
119
177
 
178
+ ### ⏰ Cron utilities **(NEW!)**
179
+
180
+ - Parse and validate cron expressions (5-field format)
181
+ - Check if a date matches a cron expression
182
+ - Get next/previous occurrence dates
183
+ - Get multiple future occurrences
184
+ - Human-readable cron descriptions
185
+ - Common cron presets (every minute, hourly, daily, weekly, etc.)
186
+ - Support for wildcards, ranges, steps, and lists
187
+
188
+ ### 📅 Fiscal Year utilities **(NEW!)**
189
+
190
+ - Configurable fiscal year start month (calendar, UK/India April, Australia July, US Federal October)
191
+ - Get fiscal year, quarter, month, and week for any date
192
+ - Calculate fiscal year/quarter start and end dates
193
+ - Track fiscal year progress and days elapsed/remaining
194
+ - Format fiscal years and quarters (FY2024, Q1 FY2024, FY2023/24)
195
+ - Common fiscal presets: CALENDAR, UK_INDIA, AUSTRALIA, US_FEDERAL
196
+
197
+ ### 🔄 Date Comparison & Sorting **(NEW!)**
198
+
199
+ - Sort date arrays ascending or descending
200
+ - Find min/max/median/average dates in arrays
201
+ - Find closest date to a target (past, future, or any)
202
+ - Clamp dates to ranges
203
+ - Remove duplicate dates with precision control
204
+ - Group dates by year, month, day, or day of week
205
+ - Round and snap dates to intervals (e.g., nearest 15 minutes)
206
+ - Check if dates are in chronological order
207
+ - Partition dates by predicate
208
+
209
+ ### 🔁 Date Iteration utilities **(NEW!)**
210
+
211
+ - Generate arrays of dates: `eachDay()`, `eachWeekday()`, `eachWeekend()`
212
+ - Iterate by period: `eachWeek()`, `eachMonth()`, `eachQuarter()`, `eachYear()`
213
+ - Time iteration: `eachHour()`, `eachMinute()`, `eachInterval()`
214
+ - Get specific days: `eachDayOfWeek()`, `eachNthDayOfMonth()`, `eachMonthEnd()`
215
+ - Count functions: `countDays()`, `countWeekdays()`, `countWeekendDays()`
216
+ - Lazy iterators for memory efficiency: `iterateDays()`, `iterateWeekdays()`, `iterateMonths()`
217
+ - Custom filtering with `filterDays()`
218
+
120
219
  ### 🧱 Constants
121
220
 
122
221
  - Milliseconds & seconds per unit
@@ -139,16 +238,20 @@ import { formatDuration, timeAgo, isValidDate } from "ts-time-utils";
139
238
  ### Import by category (better for tree-shaking)
140
239
 
141
240
  ```ts
142
- import { formatDuration, timeAgo } from "ts-time-utils/format";
241
+ import { formatDuration, timeAgo, formatDate } from "ts-time-utils/format";
143
242
  import { differenceInUnits, addTime } from "ts-time-utils/calculate";
144
- import { isValidDate, isLeapYear } from "ts-time-utils/validate";
243
+ import { isValidDate, isLeapYear, isSameWeek } from "ts-time-utils/validate";
145
244
  import { calculateAge, getNextBirthday } from "ts-time-utils/age";
146
- import { getWeekNumber, getQuarter } from "ts-time-utils/calendar";
147
- import { parseDate, parseRelativeDate } from "ts-time-utils/parse";
245
+ import {
246
+ getWeekNumber,
247
+ getQuarter,
248
+ getUSHolidays,
249
+ } from "ts-time-utils/calendar";
250
+ import { parseDate, parseRelativeDate, parseTime } from "ts-time-utils/parse";
148
251
  import { sleep, benchmark, Stopwatch } from "ts-time-utils/performance";
149
252
  import { createInterval, mergeIntervals } from "ts-time-utils/interval";
150
- import { formatInTimeZone } from "ts-time-utils/timezone";
151
- import { isWorkingTime, addWorkingHours } from "ts-time-utils/workingHours";
253
+ import { formatInTimeZone, isDST } from "ts-time-utils/timezone";
254
+ import { isWorkingTime, addWorkingDays } from "ts-time-utils/workingHours";
152
255
  import { today, lastNDays } from "ts-time-utils/rangePresets";
153
256
  import { Duration, createDuration } from "ts-time-utils/duration";
154
257
  import { serializeDate, parseJSONWithDates } from "ts-time-utils/serialize";
@@ -157,10 +260,226 @@ import {
157
260
  formatDateLocale,
158
261
  detectLocale,
159
262
  } from "ts-time-utils/locale";
263
+ import { createRecurrence, getNextOccurrence } from "ts-time-utils/recurrence";
264
+ import { createCountdown, getRemainingTime } from "ts-time-utils/countdown";
265
+ import { mergeDateRanges, findGaps } from "ts-time-utils/dateRange";
266
+ import {
267
+ parseNaturalDate,
268
+ extractDatesFromText,
269
+ } from "ts-time-utils/naturalLanguage";
270
+ // NEW: Cron utilities
271
+ import {
272
+ matchesCron,
273
+ getNextCronDate,
274
+ isValidCron,
275
+ CRON_PRESETS,
276
+ } from "ts-time-utils/cron";
277
+ // NEW: Fiscal year utilities
278
+ import {
279
+ getFiscalYear,
280
+ getFiscalQuarter,
281
+ getFiscalPeriodInfo,
282
+ FISCAL_PRESETS,
283
+ } from "ts-time-utils/fiscal";
284
+ // NEW: Date comparison & sorting
285
+ import {
286
+ sortDates,
287
+ closestDate,
288
+ groupDatesByMonth,
289
+ snapDate,
290
+ } from "ts-time-utils/compare";
291
+ // NEW: Date iteration
292
+ import {
293
+ eachDay,
294
+ eachWeekday,
295
+ countWeekdays,
296
+ iterateDays,
297
+ } from "ts-time-utils/iterate";
160
298
  ```
161
299
 
162
300
  ## 📖 Examples
163
301
 
302
+ ### Recurrence Utilities (NEW!)
303
+
304
+ ```ts
305
+ import { createRecurrence, recurrenceToString } from "ts-time-utils/recurrence";
306
+
307
+ // Daily recurrence
308
+ const daily = createRecurrence({
309
+ frequency: "daily",
310
+ interval: 2,
311
+ startDate: new Date("2024-01-01"),
312
+ count: 10,
313
+ });
314
+
315
+ const next = daily.getNextOccurrence(new Date());
316
+ const allOccurrences = daily.getAllOccurrences();
317
+
318
+ // Weekly on specific days
319
+ const weekly = createRecurrence({
320
+ frequency: "weekly",
321
+ interval: 1,
322
+ startDate: new Date("2024-01-01"),
323
+ byWeekday: [1, 3, 5], // Monday, Wednesday, Friday
324
+ });
325
+
326
+ const description = recurrenceToString(weekly.rule);
327
+ // "Every week on Monday, Wednesday, Friday"
328
+
329
+ // Monthly on the 15th
330
+ const monthly = createRecurrence({
331
+ frequency: "monthly",
332
+ interval: 1,
333
+ startDate: new Date("2024-01-01"),
334
+ byMonthDay: [15],
335
+ until: new Date("2024-12-31"),
336
+ });
337
+
338
+ const occurrencesInRange = monthly.getOccurrencesBetween(
339
+ new Date("2024-03-01"),
340
+ new Date("2024-06-30")
341
+ );
342
+ ```
343
+
344
+ ### Countdown & Timer Utilities (NEW!)
345
+
346
+ ```ts
347
+ import {
348
+ createCountdown,
349
+ getRemainingTime,
350
+ formatCountdown,
351
+ } from "ts-time-utils/countdown";
352
+
353
+ // Create a countdown timer
354
+ const countdown = createCountdown(new Date("2024-12-31T23:59:59"), {
355
+ onTick: (remaining) => {
356
+ console.log(`${remaining.days}d ${remaining.hours}h ${remaining.minutes}m`);
357
+ },
358
+ onComplete: () => {
359
+ console.log("Happy New Year!");
360
+ },
361
+ interval: 1000, // Update every second
362
+ });
363
+
364
+ countdown.start();
365
+ // Later...
366
+ countdown.stop();
367
+
368
+ // Get remaining time
369
+ const remaining = getRemainingTime(new Date("2024-12-31"));
370
+ console.log(`${remaining.days} days, ${remaining.hours} hours remaining`);
371
+
372
+ // Format countdown
373
+ const formatted = formatCountdown(new Date("2024-12-31"), {
374
+ units: ["days", "hours", "minutes"],
375
+ short: true,
376
+ });
377
+ // "45d 12h 30m"
378
+
379
+ // Progress tracking
380
+ import { getProgressPercentage } from "ts-time-utils/countdown";
381
+
382
+ const progress = getProgressPercentage(
383
+ new Date("2024-01-01"),
384
+ new Date("2024-12-31"),
385
+ new Date("2024-07-01")
386
+ );
387
+ console.log(`${progress}% complete`); // ~50%
388
+ ```
389
+
390
+ ### Date Range Utilities (NEW!)
391
+
392
+ ```ts
393
+ import {
394
+ mergeDateRanges,
395
+ findGaps,
396
+ dateRangeOverlap,
397
+ splitRange,
398
+ } from "ts-time-utils/dateRange";
399
+
400
+ // Merge overlapping ranges
401
+ const ranges = [
402
+ { start: new Date("2024-01-01"), end: new Date("2024-01-10") },
403
+ { start: new Date("2024-01-05"), end: new Date("2024-01-15") },
404
+ { start: new Date("2024-01-20"), end: new Date("2024-01-25") },
405
+ ];
406
+
407
+ const merged = mergeDateRanges(ranges);
408
+ // [
409
+ // { start: Date('2024-01-01'), end: Date('2024-01-15') },
410
+ // { start: Date('2024-01-20'), end: Date('2024-01-25') }
411
+ // ]
412
+
413
+ // Find gaps between busy times
414
+ const busyTimes = [
415
+ { start: new Date("2024-01-01T09:00"), end: new Date("2024-01-01T11:00") },
416
+ { start: new Date("2024-01-01T14:00"), end: new Date("2024-01-01T16:00") },
417
+ ];
418
+
419
+ const gaps = findGaps(busyTimes, {
420
+ start: new Date("2024-01-01T08:00"),
421
+ end: new Date("2024-01-01T18:00"),
422
+ });
423
+ // Returns available time slots
424
+
425
+ // Split into chunks
426
+ const range = {
427
+ start: new Date("2024-01-01"),
428
+ end: new Date("2024-01-31"),
429
+ };
430
+
431
+ const weeks = splitRange(range, 1, "week");
432
+ // Splits January into weekly chunks
433
+
434
+ // Check overlap
435
+ const overlap = dateRangeOverlap(
436
+ { start: new Date("2024-01-01"), end: new Date("2024-01-15") },
437
+ { start: new Date("2024-01-10"), end: new Date("2024-01-20") }
438
+ ); // true
439
+ ```
440
+
441
+ ### Natural Language Parsing (NEW!)
442
+
443
+ ```ts
444
+ import {
445
+ parseNaturalDate,
446
+ extractDatesFromText,
447
+ suggestDateFromContext,
448
+ } from "ts-time-utils/naturalLanguage";
449
+
450
+ // Parse natural language dates
451
+ parseNaturalDate("tomorrow at 3pm");
452
+ // Returns Date for tomorrow at 15:00
453
+
454
+ parseNaturalDate("next Friday");
455
+ // Returns Date for next Friday
456
+
457
+ parseNaturalDate("in 2 weeks");
458
+ // Returns Date 2 weeks from now
459
+
460
+ parseNaturalDate("3 days ago");
461
+ // Returns Date 3 days ago
462
+
463
+ // Extract dates from text
464
+ const text = "Meeting tomorrow at 3pm and lunch next Friday at noon";
465
+ const dates = extractDatesFromText(text);
466
+ // [
467
+ // { date: Date(...), text: 'tomorrow at 3pm', index: 8, confidence: 0.9 },
468
+ // { date: Date(...), text: 'next Friday at noon', index: 35, confidence: 0.85 }
469
+ // ]
470
+
471
+ // Context-aware suggestions
472
+ const suggestions = suggestDateFromContext("deadline is end of month");
473
+ // [{ date: Date(last day of current month), text: 'end of month', confidence: 0.85 }]
474
+
475
+ // Supported phrases:
476
+ // - "tomorrow", "yesterday", "today"
477
+ // - "next Monday", "last Friday"
478
+ // - "in 2 hours", "5 days ago"
479
+ // - "end of month/week/year" (or EOM/EOW/EOY)
480
+ // - "beginning of month/year"
481
+ ```
482
+
164
483
  ### Duration Utilities
165
484
 
166
485
  ```ts
@@ -428,6 +747,186 @@ const week = thisWeek();
428
747
  const quarter = quarterRange();
429
748
  ```
430
749
 
750
+ ### Cron Utilities
751
+
752
+ ```ts
753
+ import {
754
+ parseCronExpression,
755
+ matchesCron,
756
+ getNextCronDate,
757
+ getNextCronDates,
758
+ describeCron,
759
+ isValidCron,
760
+ CRON_PRESETS,
761
+ } from "ts-time-utils/cron";
762
+
763
+ // Parse a cron expression
764
+ const parsed = parseCronExpression("0 9 * * 1-5"); // 9 AM weekdays
765
+ // { minute: [0], hour: [9], dayOfMonth: [1-31], month: [1-12], dayOfWeek: [1,2,3,4,5] }
766
+
767
+ // Check if a date matches a cron expression
768
+ matchesCron("0 9 * * *", new Date("2024-01-15T09:00:00")); // true (9 AM daily)
769
+ matchesCron("0 9 * * *", new Date("2024-01-15T10:00:00")); // false
770
+
771
+ // Get next scheduled date
772
+ getNextCronDate("0 9 * * *"); // Next 9 AM
773
+ getNextCronDate("0 0 1 * *"); // Next 1st of month at midnight
774
+
775
+ // Get multiple upcoming dates
776
+ getNextCronDates("0 9 * * 1-5", 5); // Next 5 weekday 9 AMs
777
+
778
+ // Human-readable descriptions
779
+ describeCron("0 9 * * *"); // "At 09:00"
780
+ describeCron("0 9 * * 1-5"); // "At 09:00 on Monday through Friday"
781
+ describeCron("0 0 1 * *"); // "At 00:00 on day 1 of every month"
782
+
783
+ // Validate cron expressions
784
+ isValidCron("0 9 * * *"); // true
785
+ isValidCron("invalid"); // false
786
+
787
+ // Common presets
788
+ CRON_PRESETS.EVERY_MINUTE; // "* * * * *"
789
+ CRON_PRESETS.HOURLY; // "0 * * * *"
790
+ CRON_PRESETS.DAILY; // "0 0 * * *"
791
+ CRON_PRESETS.WEEKLY; // "0 0 * * 0"
792
+ CRON_PRESETS.MONTHLY; // "0 0 1 * *"
793
+ CRON_PRESETS.WEEKDAYS; // "0 0 * * 1-5"
794
+ ```
795
+
796
+ ### Fiscal Year Utilities (NEW!)
797
+
798
+ ```ts
799
+ import {
800
+ getFiscalYear,
801
+ getFiscalQuarter,
802
+ getFiscalYearStart,
803
+ getFiscalYearEnd,
804
+ getFiscalPeriodInfo,
805
+ formatFiscalYear,
806
+ FISCAL_PRESETS,
807
+ } from "ts-time-utils/fiscal";
808
+
809
+ // Default calendar year (January start)
810
+ getFiscalYear(new Date("2024-06-15")); // 2024
811
+ getFiscalQuarter(new Date("2024-06-15")); // 2
812
+
813
+ // UK/India fiscal year (April start)
814
+ getFiscalYear(new Date("2024-03-15"), FISCAL_PRESETS.UK_INDIA); // 2023
815
+ getFiscalYear(new Date("2024-04-15"), FISCAL_PRESETS.UK_INDIA); // 2024
816
+
817
+ // Australian fiscal year (July start)
818
+ getFiscalYear(new Date("2024-06-30"), FISCAL_PRESETS.AUSTRALIA); // 2023
819
+ getFiscalYear(new Date("2024-07-01"), FISCAL_PRESETS.AUSTRALIA); // 2024
820
+
821
+ // US Federal fiscal year (October start)
822
+ getFiscalYear(new Date("2024-09-30"), FISCAL_PRESETS.US_FEDERAL); // 2023
823
+ getFiscalYear(new Date("2024-10-01"), FISCAL_PRESETS.US_FEDERAL); // 2024
824
+
825
+ // Get fiscal year boundaries
826
+ getFiscalYearStart(2024, FISCAL_PRESETS.UK_INDIA); // April 1, 2024
827
+ getFiscalYearEnd(2024, FISCAL_PRESETS.UK_INDIA); // March 31, 2025
828
+
829
+ // Format fiscal years
830
+ formatFiscalYear(2024); // "FY2024"
831
+ formatFiscalYear(2024, FISCAL_PRESETS.UK_INDIA, "long"); // "FY2024/25"
832
+
833
+ // Get comprehensive fiscal info
834
+ const info = getFiscalPeriodInfo(new Date("2024-06-15"));
835
+ // { fiscalYear: 2024, fiscalQuarter: 2, fiscalMonth: 6, progress: 45.2, ... }
836
+ ```
837
+
838
+ ### Date Comparison & Sorting (NEW!)
839
+
840
+ ```ts
841
+ import {
842
+ sortDates,
843
+ minDate,
844
+ maxDate,
845
+ closestDate,
846
+ uniqueDates,
847
+ groupDatesByMonth,
848
+ snapDate,
849
+ roundDate,
850
+ medianDate,
851
+ } from "ts-time-utils/compare";
852
+
853
+ const dates = [
854
+ new Date("2024-03-15"),
855
+ new Date("2024-01-10"),
856
+ new Date("2024-06-20"),
857
+ ];
858
+
859
+ // Sort dates
860
+ sortDates(dates); // [Jan 10, Mar 15, Jun 20]
861
+ sortDates(dates, "desc"); // [Jun 20, Mar 15, Jan 10]
862
+
863
+ // Find extremes
864
+ minDate(dates); // Jan 10, 2024
865
+ maxDate(dates); // Jun 20, 2024
866
+ medianDate(dates); // Mar 15, 2024
867
+
868
+ // Find closest to target
869
+ const target = new Date("2024-04-01");
870
+ closestDate(target, dates); // Mar 15, 2024
871
+
872
+ // Remove duplicates
873
+ uniqueDates([date1, date1Copy, date2]); // [date1, date2]
874
+ uniqueDates(dates, "day"); // Unique by day precision
875
+
876
+ // Group dates
877
+ groupDatesByMonth(dates);
878
+ // Map { "2024-01" => [Jan 10], "2024-03" => [Mar 15], "2024-06" => [Jun 20] }
879
+
880
+ // Snap to intervals (e.g., 15-minute blocks)
881
+ snapDate(new Date("2024-01-15T10:37:00"), 15); // 10:30:00
882
+ snapDate(new Date("2024-01-15T10:37:00"), 15, "ceil"); // 10:45:00
883
+
884
+ // Round to nearest unit
885
+ roundDate(new Date("2024-01-15T10:37:00"), "hour"); // 11:00:00
886
+ ```
887
+
888
+ ### Date Iteration (NEW!)
889
+
890
+ ```ts
891
+ import {
892
+ eachDay,
893
+ eachWeekday,
894
+ eachWeek,
895
+ eachMonth,
896
+ countWeekdays,
897
+ eachDayOfWeek,
898
+ iterateDays,
899
+ filterDays,
900
+ } from "ts-time-utils/iterate";
901
+
902
+ const start = new Date("2024-01-01");
903
+ const end = new Date("2024-01-31");
904
+
905
+ // Generate arrays of dates
906
+ eachDay(start, end); // [Jan 1, Jan 2, ..., Jan 31] (31 dates)
907
+ eachWeekday(start, end); // All Mon-Fri dates (23 dates)
908
+ eachWeek(start, end); // [Jan 7, Jan 14, Jan 21, Jan 28] (Sundays)
909
+ eachMonth(start, new Date("2024-06-30")); // [Feb 1, Mar 1, Apr 1, May 1, Jun 1]
910
+
911
+ // Count dates
912
+ countWeekdays(start, end); // 23
913
+
914
+ // Get specific weekdays
915
+ eachDayOfWeek(start, end, 1); // All Mondays in January
916
+
917
+ // Lazy iteration (memory efficient for large ranges)
918
+ for (const date of iterateDays(start, end)) {
919
+ console.log(date);
920
+ }
921
+
922
+ // Filter days by custom predicate
923
+ filterDays(start, end, (d) => d.getDate() === 15); // [Jan 15]
924
+
925
+ // Custom intervals
926
+ eachInterval(start, end, { days: 7 }); // Every 7 days
927
+ eachInterval(start, end, { hours: 6 }); // Every 6 hours
928
+ ```
929
+
431
930
  ### Locale Utilities
432
931
 
433
932
  ```ts
@@ -623,10 +1122,173 @@ console.log(comparison.weekStartsOn);
623
1122
  ### Format Functions
624
1123
 
625
1124
  - `formatDuration(ms, options?)` - Format milliseconds to readable duration
1125
+ - `formatDurationCompact(ms)` - Format milliseconds as HH:MM:SS
626
1126
  - `timeAgo(date, options?)` - Get "time ago" string for past/future dates
627
1127
  - `formatTime(date, format?)` - Format time as 12h/24h/ISO
1128
+ - `formatDate(date, pattern?)` - Format date using patterns (YYYY-MM-DD, etc.)
1129
+ - `formatRelativeTime(date, locale?, options?)` - Format as relative time ("2 days ago")
1130
+ - `formatDateRange(start, end, options?)` - Format date ranges ("Jan 1-5, 2024")
1131
+ - `formatOrdinal(n)` - Format number as ordinal ("1st", "2nd", "3rd")
1132
+ - `formatDayOrdinal(date)` - Format day with ordinal ("1st", "15th")
1133
+ - `formatCalendarDate(date)` - Format as "Today", "Tomorrow", or day name
628
1134
  - `parseDuration(duration)` - Parse duration string to milliseconds
629
1135
 
1136
+ ### Parse Functions
1137
+
1138
+ - `parseISO8601Duration(duration)` - Parse ISO 8601 duration to object (P1Y2M3DT4H5M6S)
1139
+ - `parseISO8601DurationToMs(duration)` - Parse ISO 8601 duration to milliseconds
1140
+ - `parseTime(timeString)` - Parse time string ("14:30", "2:30 PM") to Date
1141
+ - `guessDateFormat(dateString)` - Guess the format of a date string
1142
+ - `parseAutoFormat(dateString)` - Auto-detect and parse date string
1143
+ - `parseRangeEndpoint(endpoint)` - Parse range endpoint (date string, Date, or number)
1144
+
1145
+ ### Calendar Functions
1146
+
1147
+ - `getCalendarDays(year, month)` - Get array of days for a calendar month
1148
+ - `getWeekNumber(date)` - Get ISO week number (1-53)
1149
+ - `getQuarter(date)` - Get quarter (1-4)
1150
+ - `getFirstDayOfMonth(date)` / `getLastDayOfMonth(date)` - Month boundaries
1151
+ - `getFirstDayOfWeek(date)` / `getLastDayOfWeek(date)` - Week boundaries
1152
+ - `getNthDayOfMonth(year, month, dayOfWeek, n)` - Get nth occurrence of weekday in month
1153
+ - `getStartOfWeek(date, startDay?)` - Get start of week (configurable start day)
1154
+ - `getEndOfWeek(date, startDay?)` - Get end of week (configurable start day)
1155
+ - `getWeeksInMonth(year, month)` - Count weeks in a month
1156
+
1157
+ #### US Federal Holidays
1158
+
1159
+ - `getNewYearsDay(year)` - Get New Year's Day
1160
+ - `getMLKDay(year)` - Get Martin Luther King Jr. Day (3rd Monday of January)
1161
+ - `getPresidentsDay(year)` - Get Presidents Day (3rd Monday of February)
1162
+ - `getMemorialDay(year)` - Get Memorial Day (last Monday of May)
1163
+ - `getIndependenceDay(year)` - Get Independence Day (July 4th)
1164
+ - `getLaborDay(year)` - Get Labor Day (1st Monday of September)
1165
+ - `getColumbusDay(year)` - Get Columbus Day (2nd Monday of October)
1166
+ - `getVeteransDay(year)` - Get Veterans Day (November 11th)
1167
+ - `getThanksgivingDay(year)` - Get Thanksgiving Day (4th Thursday of November)
1168
+ - `getChristmasDay(year)` - Get Christmas Day
1169
+ - `getGoodFriday(year)` - Get Good Friday
1170
+ - `getUSHolidays(year)` - Get all US federal holidays for a year
1171
+ - `isUSHoliday(date)` - Check if date is a US federal holiday
1172
+ - `getUSHolidayName(date)` - Get name of US holiday (or null)
1173
+
1174
+ ### Timezone Functions
1175
+
1176
+ - `getTimezoneOffset(timezone, date?)` - Get timezone offset in minutes
1177
+ - `convertTimezone(date, fromTz, toTz)` - Convert date between timezones
1178
+ - `getTimezoneNames()` - Get array of valid timezone names
1179
+ - `formatWithTimezone(date, timezone, format?)` - Format date in specific timezone
1180
+ - `isDST(date, timezone?)` - Check if DST is in effect
1181
+ - `getNextDSTTransition(date?, timezone?)` - Get next DST transition date
1182
+ - `findCommonWorkingHours(tz1, tz2, workStart?, workEnd?)` - Find overlapping work hours
1183
+ - `getTimezoneAbbreviation(date, timezone?)` - Get timezone abbreviation (EST, PST, etc.)
1184
+ - `convertBetweenZones(date, fromTz, toTz)` - Convert date between zones (returns new Date)
1185
+ - `getTimezoneDifferenceHours(tz1, tz2, date?)` - Get hour difference between timezones
1186
+ - `isSameTimezone(tz1, tz2, date?)` - Check if two timezones have same offset
1187
+
1188
+ ### Working Hours Functions
1189
+
1190
+ - `isWithinWorkingHours(date, config?)` - Check if time is within working hours
1191
+ - `getNextWorkingHour(date, config?)` - Get next available working hour
1192
+ - `addWorkingMinutes(date, minutes, config?)` - Add minutes within working hours
1193
+ - `workingMinutesBetween(start, end, config?)` - Count working minutes between dates
1194
+ - `addWorkingDays(date, days, config?)` - Add working days to date
1195
+ - `subtractWorkingDays(date, days, config?)` - Subtract working days from date
1196
+ - `getNextWorkingDay(date, config?)` - Get next working day
1197
+ - `getPreviousWorkingDay(date, config?)` - Get previous working day
1198
+ - `getWorkingDaysInMonth(year, month, config?)` - Count working days in month
1199
+ - `getWorkingDaysInMonthArray(year, month, config?)` - Get array of working days
1200
+ - `workingDaysBetween(start, end, config?)` - Count working days between dates
1201
+ - `isBreakTime(date, breakStart?, breakEnd?)` - Check if time is during break
1202
+ - `getWorkDayStart(date, config?)` - Get start time of work day
1203
+ - `getWorkDayEnd(date, config?)` - Get end time of work day
1204
+ - `getWorkingHoursPerDay(config?)` - Get working hours per day
1205
+
1206
+ ### Cron Functions
1207
+
1208
+ - `parseCronExpression(expression)` - Parse cron expression to object
1209
+ - `matchesCron(expression, date?)` - Check if date matches cron expression
1210
+ - `getNextCronDate(expression, after?)` - Get next date matching cron
1211
+ - `getNextCronDates(expression, count, after?)` - Get multiple future cron dates
1212
+ - `getPreviousCronDate(expression, before?)` - Get previous date matching cron
1213
+ - `isValidCron(expression)` - Validate cron expression syntax
1214
+ - `describeCron(expression)` - Get human-readable cron description
1215
+ - `CRON_PRESETS` - Common cron expressions (EVERY_MINUTE, HOURLY, DAILY, etc.)
1216
+
1217
+ ### Fiscal Year Functions
1218
+
1219
+ - `getFiscalYear(date, config?)` - Get fiscal year for a date
1220
+ - `getFiscalQuarter(date, config?)` - Get fiscal quarter (1-4)
1221
+ - `getFiscalMonth(date, config?)` - Get fiscal month (1-12 within fiscal year)
1222
+ - `getFiscalWeek(date, config?)` - Get fiscal week number
1223
+ - `getFiscalYearStart(year, config?)` - Get start date of fiscal year
1224
+ - `getFiscalYearEnd(year, config?)` - Get end date of fiscal year
1225
+ - `getFiscalQuarterStart(year, quarter, config?)` - Get start of fiscal quarter
1226
+ - `getFiscalQuarterEnd(year, quarter, config?)` - Get end of fiscal quarter
1227
+ - `isSameFiscalYear(date1, date2, config?)` - Check if dates are in same fiscal year
1228
+ - `isSameFiscalQuarter(date1, date2, config?)` - Check if dates are in same fiscal quarter
1229
+ - `getDaysElapsedInFiscalYear(date, config?)` - Days elapsed in fiscal year
1230
+ - `getDaysRemainingInFiscalYear(date, config?)` - Days remaining in fiscal year
1231
+ - `getFiscalYearProgress(date, config?)` - Percentage of fiscal year completed
1232
+ - `formatFiscalYear(year, config?, format?)` - Format as "FY2024" or "FY2023/24"
1233
+ - `formatFiscalQuarter(year, quarter, config?)` - Format as "Q1 FY2024"
1234
+ - `getFiscalPeriodInfo(date, config?)` - Get comprehensive fiscal period info
1235
+ - `FISCAL_PRESETS` - CALENDAR, UK_INDIA, AUSTRALIA, US_FEDERAL
1236
+
1237
+ ### Compare Functions
1238
+
1239
+ - `compareDates(a, b)` - Compare function for sorting dates
1240
+ - `compareDatesDesc(a, b)` - Compare function for reverse sorting
1241
+ - `sortDates(dates, direction?)` - Sort date array (asc/desc)
1242
+ - `minDate(dates)` - Find earliest date
1243
+ - `maxDate(dates)` - Find latest date
1244
+ - `dateExtent(dates)` - Get { min, max } from date array
1245
+ - `uniqueDates(dates, precision?)` - Remove duplicate dates
1246
+ - `closestDate(target, candidates)` - Find closest date to target
1247
+ - `closestFutureDate(target, candidates)` - Find closest future date
1248
+ - `closestPastDate(target, candidates)` - Find closest past date
1249
+ - `clampDate(date, min, max)` - Constrain date to range
1250
+ - `isDateInRange(date, min, max)` - Check if date is in range
1251
+ - `filterDatesInRange(dates, min, max)` - Filter dates in range
1252
+ - `groupDates(dates, keyFn)` - Group dates by custom key
1253
+ - `groupDatesByYear(dates)` - Group by year
1254
+ - `groupDatesByMonth(dates)` - Group by month (YYYY-MM)
1255
+ - `groupDatesByDay(dates)` - Group by day (YYYY-MM-DD)
1256
+ - `groupDatesByDayOfWeek(dates)` - Group by day of week (0-6)
1257
+ - `medianDate(dates)` - Calculate median date
1258
+ - `averageDate(dates)` - Calculate average/mean date
1259
+ - `roundDate(date, unit)` - Round to nearest minute/hour/day
1260
+ - `snapDate(date, intervalMinutes, mode?)` - Snap to interval grid
1261
+ - `isChronological(dates, strict?)` - Check if dates are in order
1262
+ - `dateSpan(dates)` - Get duration between min and max
1263
+ - `partitionDates(dates, predicate)` - Split into [matching, non-matching]
1264
+ - `nthDate(dates, n)` - Get nth date (supports negative indices)
1265
+
1266
+ ### Iterate Functions
1267
+
1268
+ - `eachDay(start, end)` - Array of each day in range
1269
+ - `eachWeekday(start, end)` - Array of weekdays (Mon-Fri)
1270
+ - `eachWeekend(start, end)` - Array of weekend days (Sat-Sun)
1271
+ - `eachWeek(start, end, weekStartsOn?)` - Array of week starts
1272
+ - `eachMonth(start, end)` - Array of month starts
1273
+ - `eachMonthEnd(start, end)` - Array of month ends
1274
+ - `eachQuarter(start, end)` - Array of quarter starts
1275
+ - `eachYear(start, end)` - Array of year starts
1276
+ - `eachHour(start, end, step?)` - Array of hourly intervals
1277
+ - `eachMinute(start, end, step?)` - Array of minute intervals
1278
+ - `eachDayOfWeek(start, end, dayOfWeek)` - Array of specific weekday
1279
+ - `eachNthDayOfMonth(start, end, day)` - Array of nth day of each month
1280
+ - `eachInterval(start, end, interval)` - Array at custom intervals
1281
+ - `countDays(start, end)` - Count days in range
1282
+ - `countWeekdays(start, end)` - Count weekdays in range
1283
+ - `countWeekendDays(start, end)` - Count weekend days
1284
+ - `countWeeks(start, end)` - Count weeks in range
1285
+ - `countMonths(start, end)` - Count months in range
1286
+ - `iterateDates(start, end, step?)` - Lazy date generator
1287
+ - `iterateDays(start, end)` - Lazy day iterator
1288
+ - `iterateWeekdays(start, end)` - Lazy weekday iterator
1289
+ - `iterateMonths(start, end)` - Lazy month iterator
1290
+ - `filterDays(start, end, filter)` - Filter days by predicate
1291
+
630
1292
  ### Calculate Functions
631
1293
 
632
1294
  - `differenceInUnits(date1, date2, unit?, precise?)` - Calculate difference between dates
@@ -644,7 +1306,16 @@ console.log(comparison.weekStartsOn);
644
1306
  - `isPast(date)` / `isFuture(date)` - Check if date is past/future
645
1307
  - `isToday(date)` / `isYesterday(date)` / `isTomorrow(date)` - Date comparisons
646
1308
  - `isSameDay(date1, date2)` - Check if dates are same day
1309
+ - `isSameWeek(date1, date2)` - Check if dates are in same week
1310
+ - `isSameMonth(date1, date2)` - Check if dates are in same month
1311
+ - `isSameYear(date1, date2)` - Check if dates are in same year
1312
+ - `isThisWeek(date)` - Check if date is in current week
1313
+ - `isThisMonth(date)` - Check if date is in current month
1314
+ - `isThisYear(date)` - Check if date is in current year
647
1315
  - `isWeekend(date)` / `isWeekday(date)` - Check day type
1316
+ - `isBusinessDay(date)` - Check if date is a business day (weekday, not a US holiday)
1317
+ - `isInLastNDays(date, n)` - Check if date is within last N days
1318
+ - `isInNextNDays(date, n)` - Check if date is within next N days
648
1319
  - `isValidTimeString(time)` - Validate HH:MM time format
649
1320
  - `isValidISOString(dateString)` - Validate ISO 8601 date string
650
1321