ts-time-utils 3.0.0 → 3.0.4

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 (2) hide show
  1. package/README.md +331 -1344
  2. package/package.json +7 -2
package/README.md CHANGED
@@ -1,1487 +1,474 @@
1
1
  # ts-time-utils
2
2
 
3
- A lightweight TypeScript utility library for time formatting, calculations, and validation with full tree-shaking support.
4
-
5
- ## 🚀 Features
6
-
7
- - **📦 Lightweight** - Import only what you need with tree-shaking support
8
- - **⚡ Fast** - Zero dependencies, pure JavaScript functions
9
- - **🔧 TypeScript** - Full type safety and IntelliSense support
10
- - **🌳 Tree-shakable** - Import individual functions to minimize bundle size
11
- - **📚 Comprehensive** - 26 utility categories with 320+ 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
48
-
49
- ### ⏱️ Duration utilities
50
-
51
- - Immutable Duration class with arithmetic operations
52
- - Create durations from various units and string formats
53
- - Add, subtract, multiply, divide durations
54
- - Compare durations and check relationships
55
- - Format to human-readable strings
56
- - Utility functions for arrays of durations
57
-
58
- ### 💾 Serialization utilities
59
-
60
- - Safe JSON date serialization and deserialization
61
- - Multiple format support (ISO, epoch, object, custom)
62
- - Automatic date reviver and replacer functions
63
- - Timezone-aware serialization options
64
- - Cross-platform date interchange utilities
65
- - Validation for ISO strings and epoch timestamps
66
-
67
- ### 🎨 Format utilities
68
-
69
- - Format milliseconds to human-readable durations
70
- - Get human-friendly "time ago" strings
71
- - Parse duration strings back to milliseconds
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")
76
-
77
- ### 🧮 Calculation utilities
78
-
79
- - Calculate difference between dates in any unit
80
- - Add/subtract time from dates
81
- - Get start/end of time periods
82
- - Business days calculations
83
- - Check if date is between two dates
84
-
85
- ### ✅ Validation utilities
86
-
87
- - Validate dates and time strings
88
- - Check for leap years, weekends, past/future dates
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
93
-
94
- ### 🎂 Age utilities
95
-
96
- - Calculate precise age with years, months, and days
97
- - Get life stage classifications (infant, child, adult, etc.)
98
- - Birthday calculations and next birthday finder
99
- - Check if today is someone's birthday
100
-
101
- ### 📅 Calendar utilities
102
-
103
- - ISO week numbers and week-based calculations
104
- - Quarter operations and fiscal year support
105
- - Holiday calculations (Easter, US federal holidays)
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
111
-
112
- ### 🔍 Parse utilities
113
-
114
- - Advanced date parsing from multiple formats
115
- - Relative date parsing ("tomorrow", "next week")
116
- - Custom format parsing with flexible patterns
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")
122
-
123
- ### ⚡ Performance utilities
124
-
125
- - Async utilities (sleep, timeout, retry)
126
- - Performance measurement and benchmarking
127
- - Stopwatch for timing operations
128
- - Function utilities (debounce, throttle, memoize)
129
-
130
- ### 📏 Interval utilities
131
-
132
- - Create and validate intervals
133
- - Overlap, intersection, merge, subtraction
134
- - Split by day and total coverage
135
- - Normalize and compute durations
136
-
137
- ### 🌐 Timezone utilities
138
-
139
- - Validate IANA timezones
140
- - Get offsets and compare zones
141
- - Format in specific timezone
142
- - Convert absolute moment to zone components
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
148
-
149
- ### 🕘 Working hours utilities
150
-
151
- - Define working day patterns and breaks
152
- - Check working day/time
153
- - Compute working time between dates
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
160
-
161
- ### 🎯 Range preset utilities
162
-
163
- - Today / yesterday / tomorrow
164
- - Last/next N days windows
165
- - This/last/next week, month, quarter, year
166
- - Rolling windows and quarter helpers
167
-
168
- ### 🌍 Locale utilities
169
-
170
- - Multi-language relative time formatting
171
- - Locale-specific date and time formatting
172
- - Support for 40+ locales with built-in configurations
173
- - Auto-detection of system/browser locale
174
- - Custom locale registration
175
- - Internationalization (i18n) support
176
- - **Locale conversions** - Convert between different locales and detect locale from text
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/farthest dates from target
202
- - Remove duplicate dates
203
- - Group dates by year/month/day/weekday
204
- - Snap dates to grid and round to nearest unit
205
- - Validate chronological order
206
- - Get date span and partition into groups
207
- - Select nth dates from sorted arrays
208
-
209
- ### ⏭️ Date Iteration & Counting **(NEW!)**
210
-
211
- - Iterate through date sequences: days, weekdays, weekends, weeks, months, quarters, years
212
- - Count dates in ranges: count all days, weekdays, weekend days, weeks, months
213
- - Lazy iteration with generators for memory efficiency
214
- - Filter dates by custom conditions
215
- - Iterate specific day patterns (e.g., all Mondays)
216
- - Get month-end dates in range
217
- - Get nth day of each month in range
218
-
219
- ### 🌍 International Holidays **(NEW!)**
220
-
221
- - Calculate public holidays for 9 countries: UK, Netherlands, Germany, Canada, Australia, Italy, Spain, China, India
222
- - Fixed holidays (New Year, Christmas, National Days)
223
- - Easter-based holidays (Good Friday, Easter Monday, Whit Monday)
224
- - Movable holidays (Victoria Day, Thanksgiving, Spring Bank Holiday)
225
- - Unified API: check if date is holiday, get holiday name, find next holiday
226
- - Weekend adjustment for substitute holidays
227
- - Get upcoming holidays within timeframe
228
- - Support for both federal and regional observances
229
- - Find closest date to a target (past, future, or any)
230
- - Clamp dates to ranges
231
- - Remove duplicate dates with precision control
232
- - Group dates by year, month, day, or day of week
233
- - Round and snap dates to intervals (e.g., nearest 15 minutes)
234
- - Check if dates are in chronological order
235
- - Partition dates by predicate
236
-
237
- ### 🔁 Date Iteration utilities **(NEW!)**
238
-
239
- - Generate arrays of dates: `eachDay()`, `eachWeekday()`, `eachWeekend()`
240
- - Iterate by period: `eachWeek()`, `eachMonth()`, `eachQuarter()`, `eachYear()`
241
- - Time iteration: `eachHour()`, `eachMinute()`, `eachInterval()`
242
- - Get specific days: `eachDayOfWeek()`, `eachNthDayOfMonth()`, `eachMonthEnd()`
243
- - Count functions: `countDays()`, `countWeekdays()`, `countWeekendDays()`
244
- - Lazy iterators for memory efficiency: `iterateDays()`, `iterateWeekdays()`, `iterateMonths()`
245
- - Custom filtering with `filterDays()`
246
-
247
- ### 🧱 Constants
248
-
249
- - Milliseconds & seconds per unit
250
- - Time unit and formatting option types
251
-
252
- ## 📦 Installation
3
+ A comprehensive TypeScript utility library for time, dates, durations, and calendar operations. Zero dependencies, full tree-shaking support, 320+ functions across 26 categories.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/ts-time-utils.svg)](https://www.npmjs.com/package/ts-time-utils)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ **[Live Playground & Docs](https://ts-time-utils.h8frad.work)** | [GitHub](https://github.com/hatefrad/ts-time-utils)
9
+
10
+ ## Features
11
+
12
+ - **Lightweight** — Import only what you need with tree-shaking support
13
+ - **Zero dependencies** — Pure TypeScript, no external packages
14
+ - **Type-safe** — Full TypeScript support with IntelliSense
15
+ - **Comprehensive** — 320+ functions across 26 utility categories
16
+ - **Fluent API** — Chain operations with the `chain()` API
17
+ - **Extensible** — Plugin system for custom functionality
18
+
19
+ ## Installation
253
20
 
254
21
  ```bash
255
22
  npm install ts-time-utils
256
23
  ```
257
24
 
258
- ## 🔧 Usage
259
-
260
- ### Import everything (not recommended for production)
25
+ ## Quick Start
261
26
 
262
27
  ```ts
263
- import { formatDuration, timeAgo, isValidDate } from "ts-time-utils";
264
- ```
28
+ import { formatDuration, timeAgo, Duration } from 'ts-time-utils';
265
29
 
266
- ### Import by category (better for tree-shaking)
30
+ // Format milliseconds to readable duration
31
+ formatDuration(3661000); // "1 hour, 1 minute, 1 second"
267
32
 
268
- ```ts
269
- import { formatDuration, timeAgo, formatDate } from "ts-time-utils/format";
270
- import { differenceInUnits, addTime } from "ts-time-utils/calculate";
271
- import { isValidDate, isLeapYear, isSameWeek } from "ts-time-utils/validate";
272
- import { calculateAge, getNextBirthday } from "ts-time-utils/age";
273
- import {
274
- getWeekNumber,
275
- getQuarter,
276
- getUSHolidays,
277
- } from "ts-time-utils/calendar";
278
- import { parseDate, parseRelativeDate, parseTime } from "ts-time-utils/parse";
279
- import { sleep, benchmark, Stopwatch } from "ts-time-utils/performance";
280
- import { createInterval, mergeIntervals } from "ts-time-utils/interval";
281
- import { formatInTimeZone, isDST } from "ts-time-utils/timezone";
282
- import { isWorkingTime, addWorkingDays } from "ts-time-utils/workingHours";
283
- import { today, lastNDays } from "ts-time-utils/rangePresets";
284
- import { Duration, createDuration } from "ts-time-utils/duration";
285
- import { serializeDate, parseJSONWithDates } from "ts-time-utils/serialize";
286
- import {
287
- formatRelativeTime,
288
- formatDateLocale,
289
- detectLocale,
290
- } from "ts-time-utils/locale";
291
- import { createRecurrence, getNextOccurrence } from "ts-time-utils/recurrence";
292
- import { createCountdown, getRemainingTime } from "ts-time-utils/countdown";
293
- import { mergeDateRanges, findGaps } from "ts-time-utils/dateRange";
294
- import {
295
- parseNaturalDate,
296
- extractDatesFromText,
297
- } from "ts-time-utils/naturalLanguage";
298
- // NEW: Cron utilities
299
- import {
300
- matchesCron,
301
- getNextCronDate,
302
- isValidCron,
303
- CRON_PRESETS,
304
- } from "ts-time-utils/cron";
305
- // NEW: Fiscal year utilities
306
- import {
307
- getFiscalYear,
308
- getFiscalQuarter,
309
- getFiscalPeriodInfo,
310
- FISCAL_PRESETS,
311
- } from "ts-time-utils/fiscal";
312
- // NEW: Date comparison & sorting
313
- import {
314
- sortDates,
315
- closestDate,
316
- groupDatesByMonth,
317
- snapDate,
318
- } from "ts-time-utils/compare";
319
- // NEW: Date iteration
320
- import {
321
- eachDay,
322
- eachWeekday,
323
- countWeekdays,
324
- iterateDays,
325
- } from "ts-time-utils/iterate";
326
- // NEW: International holidays
327
- import {
328
- getHolidays,
329
- isHoliday,
330
- getNextHoliday,
331
- getSupportedCountries,
332
- } from "ts-time-utils/holidays";
333
- ```
33
+ // Get "time ago" strings
34
+ timeAgo(new Date(Date.now() - 3600000)); // "1 hour ago"
334
35
 
335
- ## 📖 Examples
36
+ // Duration arithmetic
37
+ const meeting = Duration.fromMinutes(45);
38
+ const buffer = Duration.fromMinutes(15);
39
+ meeting.add(buffer).toString(); // "1h"
40
+ ```
336
41
 
337
- ### Recurrence Utilities (NEW!)
42
+ ### Tree-shaking (recommended)
338
43
 
339
44
  ```ts
340
- import { createRecurrence, recurrenceToString } from "ts-time-utils/recurrence";
341
-
342
- // Daily recurrence
343
- const daily = createRecurrence({
344
- frequency: "daily",
345
- interval: 2,
346
- startDate: new Date("2024-01-01"),
347
- count: 10,
348
- });
45
+ import { formatDuration } from 'ts-time-utils/format';
46
+ import { differenceInUnits } from 'ts-time-utils/calculate';
47
+ import { isValidDate } from 'ts-time-utils/validate';
48
+ ```
349
49
 
350
- const next = daily.getNextOccurrence(new Date());
351
- const allOccurrences = daily.getAllOccurrences();
50
+ ---
352
51
 
353
- // Weekly on specific days
354
- const weekly = createRecurrence({
355
- frequency: "weekly",
356
- interval: 1,
357
- startDate: new Date("2024-01-01"),
358
- byWeekday: [1, 3, 5], // Monday, Wednesday, Friday
359
- });
52
+ ## Utility Categories
360
53
 
361
- const description = recurrenceToString(weekly.rule);
362
- // "Every week on Monday, Wednesday, Friday"
54
+ ### Format
363
55
 
364
- // Monthly on the 15th
365
- const monthly = createRecurrence({
366
- frequency: "monthly",
367
- interval: 1,
368
- startDate: new Date("2024-01-01"),
369
- byMonthDay: [15],
370
- until: new Date("2024-12-31"),
371
- });
56
+ Format durations, time ago strings, and custom date formats.
372
57
 
373
- const occurrencesInRange = monthly.getOccurrencesBetween(
374
- new Date("2024-03-01"),
375
- new Date("2024-06-30")
376
- );
58
+ ```ts
59
+ import { formatDuration, timeAgo, parseDuration } from 'ts-time-utils/format';
60
+
61
+ formatDuration(65000); // "1 minute, 5 seconds"
62
+ formatDuration(65000, { short: true }); // "1m 5s"
63
+ timeAgo(new Date(Date.now() - 60000)); // "1 minute ago"
64
+ parseDuration('1h 30m'); // 5400000 (ms)
377
65
  ```
378
66
 
379
- ### Countdown & Timer Utilities (NEW!)
67
+ ### Calculate
68
+
69
+ Date arithmetic, differences, and business day calculations.
380
70
 
381
71
  ```ts
382
- import {
383
- createCountdown,
384
- getRemainingTime,
385
- formatCountdown,
386
- } from "ts-time-utils/countdown";
387
-
388
- // Create a countdown timer
389
- const countdown = createCountdown(new Date("2024-12-31T23:59:59"), {
390
- onTick: (remaining) => {
391
- console.log(`${remaining.days}d ${remaining.hours}h ${remaining.minutes}m`);
392
- },
393
- onComplete: () => {
394
- console.log("Happy New Year!");
395
- },
396
- interval: 1000, // Update every second
397
- });
72
+ import { differenceInUnits, addTime, startOf, endOf } from 'ts-time-utils/calculate';
398
73
 
399
- countdown.start();
400
- // Later...
401
- countdown.stop();
74
+ differenceInUnits(date1, date2, 'days'); // 10
75
+ addTime(new Date(), 5, 'hours'); // 5 hours from now
76
+ startOf(new Date(), 'day'); // 00:00:00 today
77
+ endOf(new Date(), 'month'); // Last moment of month
78
+ ```
402
79
 
403
- // Get remaining time
404
- const remaining = getRemainingTime(new Date("2024-12-31"));
405
- console.log(`${remaining.days} days, ${remaining.hours} hours remaining`);
80
+ ### Validate
406
81
 
407
- // Format countdown
408
- const formatted = formatCountdown(new Date("2024-12-31"), {
409
- units: ["days", "hours", "minutes"],
410
- short: true,
411
- });
412
- // "45d 12h 30m"
82
+ Date validation, checks, and comparisons.
413
83
 
414
- // Progress tracking
415
- import { getProgressPercentage } from "ts-time-utils/countdown";
84
+ ```ts
85
+ import { isValidDate, isLeapYear, isWeekend, isSameDay } from 'ts-time-utils/validate';
416
86
 
417
- const progress = getProgressPercentage(
418
- new Date("2024-01-01"),
419
- new Date("2024-12-31"),
420
- new Date("2024-07-01")
421
- );
422
- console.log(`${progress}% complete`); // ~50%
87
+ isValidDate(new Date('2025-13-01')); // false
88
+ isLeapYear(2024); // true
89
+ isWeekend(new Date('2025-09-13')); // true (Saturday)
90
+ isSameDay(date1, date2); // boolean
423
91
  ```
424
92
 
425
- ### Date Range Utilities (NEW!)
93
+ ### Duration
426
94
 
427
- ```ts
428
- import {
429
- mergeDateRanges,
430
- findGaps,
431
- dateRangeOverlap,
432
- splitRange,
433
- } from "ts-time-utils/dateRange";
434
-
435
- // Merge overlapping ranges
436
- const ranges = [
437
- { start: new Date("2024-01-01"), end: new Date("2024-01-10") },
438
- { start: new Date("2024-01-05"), end: new Date("2024-01-15") },
439
- { start: new Date("2024-01-20"), end: new Date("2024-01-25") },
440
- ];
95
+ Immutable Duration class with arithmetic operations.
441
96
 
442
- const merged = mergeDateRanges(ranges);
443
- // [
444
- // { start: Date('2024-01-01'), end: Date('2024-01-15') },
445
- // { start: Date('2024-01-20'), end: Date('2024-01-25') }
446
- // ]
97
+ ```ts
98
+ import { Duration } from 'ts-time-utils/duration';
447
99
 
448
- // Find gaps between busy times
449
- const busyTimes = [
450
- { start: new Date("2024-01-01T09:00"), end: new Date("2024-01-01T11:00") },
451
- { start: new Date("2024-01-01T14:00"), end: new Date("2024-01-01T16:00") },
452
- ];
100
+ const d1 = Duration.fromHours(2.5);
101
+ const d2 = Duration.fromString('1h 30m 45s');
102
+ const d3 = Duration.between(startDate, endDate);
453
103
 
454
- const gaps = findGaps(busyTimes, {
455
- start: new Date("2024-01-01T08:00"),
456
- end: new Date("2024-01-01T18:00"),
457
- });
458
- // Returns available time slots
459
-
460
- // Split into chunks
461
- const range = {
462
- start: new Date("2024-01-01"),
463
- end: new Date("2024-01-31"),
464
- };
465
-
466
- const weeks = splitRange(range, 1, "week");
467
- // Splits January into weekly chunks
468
-
469
- // Check overlap
470
- const overlap = dateRangeOverlap(
471
- { start: new Date("2024-01-01"), end: new Date("2024-01-15") },
472
- { start: new Date("2024-01-10"), end: new Date("2024-01-20") }
473
- ); // true
104
+ d1.add(d2).toString(); // "4h 0m 45s"
105
+ d1.greaterThan(d2); // true
106
+ d1.multiply(2).hours; // 5
474
107
  ```
475
108
 
476
- ### Natural Language Parsing (NEW!)
109
+ ### Chain API
477
110
 
478
- ```ts
479
- import {
480
- parseNaturalDate,
481
- extractDatesFromText,
482
- suggestDateFromContext,
483
- } from "ts-time-utils/naturalLanguage";
484
-
485
- // Parse natural language dates
486
- parseNaturalDate("tomorrow at 3pm");
487
- // Returns Date for tomorrow at 15:00
488
-
489
- parseNaturalDate("next Friday");
490
- // Returns Date for next Friday
491
-
492
- parseNaturalDate("in 2 weeks");
493
- // Returns Date 2 weeks from now
494
-
495
- parseNaturalDate("3 days ago");
496
- // Returns Date 3 days ago
497
-
498
- // Extract dates from text
499
- const text = "Meeting tomorrow at 3pm and lunch next Friday at noon";
500
- const dates = extractDatesFromText(text);
501
- // [
502
- // { date: Date(...), text: 'tomorrow at 3pm', index: 8, confidence: 0.9 },
503
- // { date: Date(...), text: 'next Friday at noon', index: 35, confidence: 0.85 }
504
- // ]
505
-
506
- // Context-aware suggestions
507
- const suggestions = suggestDateFromContext("deadline is end of month");
508
- // [{ date: Date(last day of current month), text: 'end of month', confidence: 0.85 }]
509
-
510
- // Supported phrases:
511
- // - "tomorrow", "yesterday", "today"
512
- // - "next Monday", "last Friday"
513
- // - "in 2 hours", "5 days ago"
514
- // - "end of month/week/year" (or EOM/EOW/EOY)
515
- // - "beginning of month/year"
516
- ```
517
-
518
- ### Duration Utilities
111
+ Fluent chainable API for date operations.
519
112
 
520
113
  ```ts
521
- import {
522
- Duration,
523
- createDuration,
524
- formatDurationString,
525
- } from "ts-time-utils/duration";
526
-
527
- // Create durations
528
- const duration1 = Duration.fromHours(2.5); // 2.5 hours
529
- const duration2 = new Duration({ hours: 1, minutes: 30 }); // 1.5 hours
530
- const duration3 = Duration.fromString("1h 30m 45s"); // Parse from string
531
- const duration4 = Duration.between(startDate, endDate); // From date range
532
-
533
- // Arithmetic operations
534
- const sum = duration1.add(duration2); // 4 hours
535
- const diff = duration1.subtract(duration2); // 1 hour
536
- const doubled = duration1.multiply(2); // 5 hours
537
- const half = duration1.divide(2); // 1.25 hours
538
-
539
- // Comparisons
540
- duration1.equals(duration2); // false
541
- duration1.greaterThan(duration2); // true
542
- duration1.compareTo(duration2); // 1
543
-
544
- // Conversions and formatting
545
- duration1.hours; // 2.5
546
- duration1.minutes; // 150
547
- duration1.toString(); // "2h 30m"
548
- formatDurationString(duration1, { long: true }); // "2 hours, 30 minutes"
549
-
550
- // Utility functions with arrays
551
- const durations = [duration1, duration2, duration3];
552
- const max = maxDuration(...durations);
553
- const total = sumDurations(...durations);
554
- const average = averageDuration(...durations);
114
+ import { chain } from 'ts-time-utils/chain';
115
+
116
+ chain(new Date())
117
+ .startOf('day')
118
+ .add(9, 'hours')
119
+ .add(30, 'minutes')
120
+ .toDate(); // Today at 9:30am
121
+
122
+ chain(new Date())
123
+ .add(1, 'week')
124
+ .startOf('week')
125
+ .format('YYYY-MM-DD'); // Next week Monday
555
126
  ```
556
127
 
557
- ### Serialization Utilities
128
+ ### Timezone
129
+
130
+ Timezone conversions, DST handling, and zone comparisons.
558
131
 
559
132
  ```ts
560
- import {
561
- serializeDate,
562
- deserializeDate,
563
- parseJSONWithDates,
564
- stringifyWithDates,
565
- toEpochTimestamp,
566
- fromEpochTimestamp,
567
- toDateObject,
568
- fromDateObject,
569
- } from "ts-time-utils/serialize";
570
-
571
- // Serialize dates in different formats
572
- const date = new Date("2025-09-14T12:30:45.123Z");
573
-
574
- const isoString = serializeDate(date, { format: "iso" }); // "2025-09-14T12:30:45.123Z"
575
- const epochMs = serializeDate(date, { format: "epoch" }); // 1757853045123
576
- const dateObj = serializeDate(date, { format: "object" }); // {year: 2025, month: 9, ...}
577
- const custom = serializeDate(date, {
578
- format: "custom",
579
- customFormat: "YYYY-MM-DD HH:mm:ss",
580
- }); // "2025-09-14 12:30:45"
581
-
582
- // Deserialize from various formats
583
- const fromISO = deserializeDate("2025-09-14T12:30:45.123Z");
584
- const fromEpoch = deserializeDate(1757853045123);
585
- const fromObj = deserializeDate({
586
- year: 2025,
587
- month: 9,
588
- day: 14,
589
- hour: 12,
590
- minute: 30,
591
- second: 45,
592
- millisecond: 123,
593
- });
133
+ import { formatInTimeZone, isDST, convertTimezone } from 'ts-time-utils/timezone';
594
134
 
595
- // Safe JSON handling with automatic date conversion
596
- const data = {
597
- name: "User",
598
- createdAt: new Date(),
599
- updatedAt: new Date(),
600
- metadata: "other data",
601
- };
602
-
603
- // Stringify with automatic date serialization
604
- const jsonString = stringifyWithDates(data, ["createdAt", "updatedAt"], {
605
- format: "epoch",
606
- });
607
- // {"name":"User","createdAt":1757853045123,"updatedAt":1757853045123,"metadata":"other data"}
135
+ formatInTimeZone(date, 'America/New_York');
136
+ isDST(new Date('2025-07-14'), 'America/New_York'); // true
137
+ convertTimezone(date, 'UTC', 'Asia/Tokyo');
138
+ ```
139
+
140
+ ### Calendar
608
141
 
609
- // Parse with automatic date restoration
610
- const parsed = parseJSONWithDates(jsonString, ["createdAt", "updatedAt"]);
611
- // parsed.createdAt and parsed.updatedAt are Date objects
142
+ ISO weeks, quarters, holidays, and calendar grids.
612
143
 
613
- // Epoch timestamp utilities
614
- const timestamp = toEpochTimestamp(date, "seconds"); // 1757853045
615
- const restoredDate = fromEpochTimestamp(timestamp, "seconds");
144
+ ```ts
145
+ import { getWeekNumber, getQuarter, getEaster, getUSHolidays } from 'ts-time-utils/calendar';
616
146
 
617
- // Date object utilities (UTC-based)
618
- const dateObject = toDateObject(date, true); // includes timezone
619
- const reconstructed = fromDateObject(dateObject);
147
+ getWeekNumber(new Date('2025-09-14')); // 37
148
+ getQuarter(new Date('2025-07-15')); // 3
149
+ getEaster(2025); // Easter Sunday 2025
150
+ getUSHolidays(2025); // Array of US federal holidays
620
151
  ```
621
152
 
622
- ### Format Utilities
153
+ ### Date Range
623
154
 
624
- ```ts
625
- import { formatDuration, timeAgo, parseDuration } from "ts-time-utils/format";
155
+ Date range operations: overlap, gaps, merge, split.
626
156
 
627
- // Format durations
628
- formatDuration(65000); // "1 minute, 5 seconds"
629
- formatDuration(65000, { short: true }); // "1m 5s"
630
- formatDuration(90061000, { maxUnits: 2 }); // "1 day, 1 hour"
157
+ ```ts
158
+ import { mergeDateRanges, findGaps, dateRangeOverlap } from 'ts-time-utils/dateRange';
631
159
 
632
- // Time ago strings
633
- timeAgo(new Date(Date.now() - 60000)); // "1 minute ago"
634
- timeAgo(new Date(Date.now() + 60000)); // "in 1 minute"
160
+ const ranges = [
161
+ { start: new Date('2024-01-01'), end: new Date('2024-01-10') },
162
+ { start: new Date('2024-01-05'), end: new Date('2024-01-15') },
163
+ ];
635
164
 
636
- // Parse duration strings
637
- parseDuration("1h 30m"); // 5400000 (milliseconds)
638
- parseDuration("2 days 3 hours"); // 183600000
165
+ mergeDateRanges(ranges); // Merged into single range
166
+ findGaps(busyTimes, workday); // Available time slots
167
+ dateRangeOverlap(range1, range2); // true/false
639
168
  ```
640
169
 
641
- ### Calculate Utilities
170
+ ### Recurrence
171
+
172
+ RRULE-inspired recurring event patterns.
642
173
 
643
174
  ```ts
644
- import { differenceInUnits, addTime, startOf } from "ts-time-utils/calculate";
175
+ import { createRecurrence, recurrenceToString } from 'ts-time-utils/recurrence';
645
176
 
646
- // Date calculations
647
- differenceInUnits(new Date("2025-09-01"), new Date("2025-09-11"), "days"); // 10
177
+ const weekly = createRecurrence({
178
+ frequency: 'weekly',
179
+ interval: 1,
180
+ startDate: new Date('2025-01-01'),
181
+ byWeekday: [1, 3, 5], // Mon, Wed, Fri
182
+ });
648
183
 
649
- addTime(new Date(), 5, "hours"); // 5 hours from now
650
- startOf(new Date(), "day"); // Start of today (00:00:00)
184
+ weekly.getNextOccurrence(new Date());
185
+ weekly.getAllOccurrences();
186
+ recurrenceToString(weekly.rule); // "Every week on Monday, Wednesday, Friday"
651
187
  ```
652
188
 
653
- ### Validation Utilities
189
+ ### Cron
190
+
191
+ Parse and match cron expressions.
654
192
 
655
193
  ```ts
656
- import { isValidDate, isLeapYear, isWeekend } from "ts-time-utils/validate";
194
+ import { matchesCron, getNextCronDate, describeCron, CRON_PRESETS } from 'ts-time-utils/cron';
657
195
 
658
- // Validations
659
- isValidDate(new Date("2025-13-01")); // false
660
- isLeapYear(2024); // true
661
- isWeekend(new Date("2025-09-13")); // true (Saturday)
196
+ matchesCron('0 9 * * 1-5', date); // true if weekday 9am
197
+ getNextCronDate('0 9 * * *'); // Next 9am
198
+ describeCron('0 9 * * 1-5'); // "At 09:00 on Monday through Friday"
199
+ CRON_PRESETS.DAILY; // "0 0 * * *"
662
200
  ```
663
201
 
664
- ### Age Utilities
202
+ ### Fiscal Year
203
+
204
+ Fiscal year utilities with configurable start month.
665
205
 
666
206
  ```ts
667
- import {
668
- calculateAge,
669
- getLifeStage,
670
- getNextBirthday,
671
- isBirthday,
672
- } from "ts-time-utils/age";
673
-
674
- // Age calculations
675
- calculateAge(new Date("1990-05-15")); // { years: 34, months: 4, days: 2 }
676
- getLifeStage(25); // "adult"
677
- getNextBirthday(new Date("1990-05-15")); // Next May 15th
678
- isBirthday(new Date("1990-05-15"), new Date("2025-05-15")); // true
207
+ import { getFiscalYear, getFiscalQuarter, FISCAL_PRESETS } from 'ts-time-utils/fiscal';
208
+
209
+ getFiscalYear(date, FISCAL_PRESETS.UK_INDIA); // April start
210
+ getFiscalYear(date, FISCAL_PRESETS.AUSTRALIA); // July start
211
+ getFiscalYear(date, FISCAL_PRESETS.US_FEDERAL); // October start
212
+ getFiscalQuarter(date, { startMonth: 4 }); // Q2 for UK fiscal
679
213
  ```
680
214
 
681
- ### Calendar Utilities
215
+ ### Compare & Sort
216
+
217
+ Sort, group, and analyze date arrays.
682
218
 
683
219
  ```ts
684
- import {
685
- getWeekNumber,
686
- getQuarter,
687
- getEaster,
688
- getDaysInMonth,
689
- } from "ts-time-utils/calendar";
690
-
691
- // Calendar operations
692
- getWeekNumber(new Date("2025-01-15")); // 3
693
- getQuarter(new Date("2025-07-15")); // 3
694
- getEaster(2025); // Date object for Easter Sunday 2025
695
- getDaysInMonth(2, 2024); // 29 (leap year)
220
+ import { sortDates, closestDate, groupDatesByMonth, snapDate } from 'ts-time-utils/compare';
221
+
222
+ sortDates(dates, 'desc');
223
+ closestDate(target, candidates);
224
+ groupDatesByMonth(dates); // Map by YYYY-MM
225
+ snapDate(date, 15, 'minutes'); // Snap to 15-min grid
696
226
  ```
697
227
 
698
- ### Parse Utilities
228
+ ### Iterate
229
+
230
+ Iterate through date sequences and count dates.
699
231
 
700
232
  ```ts
701
- import {
702
- parseDate,
703
- parseRelativeDate,
704
- parseCustomFormat,
705
- } from "ts-time-utils/parse";
706
-
707
- // Advanced parsing
708
- parseDate("2025-02-30"); // null (invalid date)
709
- parseDate("Dec 25, 2025"); // Date object
710
- parseRelativeDate("tomorrow"); // Date for tomorrow
711
- parseCustomFormat("25/12/2025", "DD/MM/YYYY"); // Date object
233
+ import { eachDay, eachWeekday, countWeekdays, filterDays } from 'ts-time-utils/iterate';
234
+
235
+ eachDay(start, end); // Array of each day
236
+ eachWeekday(start, end); // Weekdays only (Mon-Fri)
237
+ countWeekdays(start, end); // Number of weekdays
238
+ filterDays(start, end, d => d.getDate() === 15); // 15th of each month
712
239
  ```
713
240
 
714
- ### Performance Utilities
241
+ ### Natural Language
242
+
243
+ Parse human-friendly date strings.
715
244
 
716
245
  ```ts
717
- import {
718
- sleep,
719
- timeout,
720
- benchmark,
721
- Stopwatch,
722
- debounce,
723
- } from "ts-time-utils/performance";
724
-
725
- // Async utilities
726
- await sleep(1000); // Wait 1 second
727
- await timeout(promise, 5000); // Timeout after 5 seconds
728
-
729
- // Performance measurement
730
- const result = await benchmark(() => heavyOperation(), 10); // Run 10 times
731
- const stopwatch = new Stopwatch();
732
- stopwatch.start();
733
- // ... operations
734
- console.log(stopwatch.getElapsed()); // Get elapsed time
246
+ import { parseNaturalDate, extractDatesFromText } from 'ts-time-utils/naturalLanguage';
247
+
248
+ parseNaturalDate('tomorrow');
249
+ parseNaturalDate('next Friday');
250
+ parseNaturalDate('in 2 weeks');
251
+ parseNaturalDate('end of month');
735
252
 
736
- // Function utilities
737
- const debouncedFn = debounce(() => console.log("Called!"), 300);
253
+ extractDatesFromText('Meeting tomorrow at 3pm');
254
+ // [{ date: Date, text: 'tomorrow at 3pm', confidence: 0.9 }]
738
255
  ```
739
256
 
740
- ### Interval Utilities
257
+ ### International Holidays
258
+
259
+ Public holidays for 10 countries.
741
260
 
742
261
  ```ts
743
- import {
744
- createInterval,
745
- intervalsOverlap,
746
- mergeIntervals,
747
- } from "ts-time-utils/interval";
748
-
749
- const a = createInterval("2025-01-01", "2025-01-05");
750
- const b = createInterval("2025-01-04", "2025-01-10");
751
- intervalsOverlap(a!, b!); // true
752
- const merged = mergeIntervals([a!, b!]);
262
+ import { getHolidays, isHoliday, getNextHoliday } from 'ts-time-utils/holidays';
263
+
264
+ getHolidays(2025, 'UK'); // UK bank holidays
265
+ getHolidays(2025, 'DE'); // German holidays
266
+ isHoliday(date, 'CA'); // Is Canadian holiday?
267
+ getNextHoliday(date, 'AU'); // Next Australian holiday
268
+
269
+ // Supported: UK, NL, DE, CA, AU, IT, ES, CN, IN, US
753
270
  ```
754
271
 
755
- ### Timezone Utilities
272
+ ### Locale
273
+
274
+ Multi-language formatting with 40+ locales.
756
275
 
757
276
  ```ts
758
- import { formatInTimeZone, getTimezoneOffset } from "ts-time-utils/timezone";
759
- formatInTimeZone(new Date(), "Europe/Paris", {
760
- hour: "2-digit",
761
- minute: "2-digit",
762
- });
763
- getTimezoneOffset("America/New_York"); // e.g. -300 (minutes)
277
+ import { formatRelativeTime, formatDateLocale, detectLocale } from 'ts-time-utils/locale';
278
+
279
+ formatRelativeTime(pastDate, { locale: 'es' }); // "hace 2 horas"
280
+ formatRelativeTime(pastDate, { locale: 'de' }); // "vor 2 Stunden"
281
+ formatDateLocale(date, 'fr', 'long'); // "15 janvier 2024"
282
+ detectLocale(); // Auto-detect system locale
764
283
  ```
765
284
 
766
- ### Working Hours Utilities
285
+ ### Working Hours
286
+
287
+ Business hours calculations with break support.
767
288
 
768
289
  ```ts
769
- import { isWorkingTime, addWorkingHours } from "ts-time-utils/workingHours";
290
+ import { isWorkingTime, addWorkingDays, workingDaysBetween } from 'ts-time-utils/workingHours';
770
291
 
771
- isWorkingTime(new Date()); // depends on config
772
- addWorkingHours(new Date(), 10); // adds 10 working hours, skipping off-hours
292
+ isWorkingTime(date, config);
293
+ addWorkingDays(date, 5, config);
294
+ workingDaysBetween(start, end, config);
773
295
  ```
774
296
 
775
- ### Range Preset Utilities
297
+ ### Serialization
298
+
299
+ Safe JSON date serialization and deserialization.
776
300
 
777
301
  ```ts
778
- import { lastNDays, thisWeek, quarterRange } from "ts-time-utils/rangePresets";
302
+ import { serializeDate, parseJSONWithDates, stringifyWithDates } from 'ts-time-utils/serialize';
303
+
304
+ serializeDate(date, { format: 'iso' }); // "2025-09-14T12:30:45.123Z"
305
+ serializeDate(date, { format: 'epoch' }); // 1757853045123
779
306
 
780
- const last7 = lastNDays(7);
781
- const week = thisWeek();
782
- const quarter = quarterRange();
307
+ const json = stringifyWithDates(data, ['createdAt']);
308
+ const parsed = parseJSONWithDates(json, ['createdAt']);
783
309
  ```
784
310
 
785
- ### Cron Utilities
311
+ ### Performance
312
+
313
+ Async utilities, benchmarking, and timing.
786
314
 
787
315
  ```ts
788
- import {
789
- parseCronExpression,
790
- matchesCron,
791
- getNextCronDate,
792
- getNextCronDates,
793
- describeCron,
794
- isValidCron,
795
- CRON_PRESETS,
796
- } from "ts-time-utils/cron";
797
-
798
- // Parse a cron expression
799
- const parsed = parseCronExpression("0 9 * * 1-5"); // 9 AM weekdays
800
- // { minute: [0], hour: [9], dayOfMonth: [1-31], month: [1-12], dayOfWeek: [1,2,3,4,5] }
801
-
802
- // Check if a date matches a cron expression
803
- matchesCron("0 9 * * *", new Date("2024-01-15T09:00:00")); // true (9 AM daily)
804
- matchesCron("0 9 * * *", new Date("2024-01-15T10:00:00")); // false
805
-
806
- // Get next scheduled date
807
- getNextCronDate("0 9 * * *"); // Next 9 AM
808
- getNextCronDate("0 0 1 * *"); // Next 1st of month at midnight
809
-
810
- // Get multiple upcoming dates
811
- getNextCronDates("0 9 * * 1-5", 5); // Next 5 weekday 9 AMs
812
-
813
- // Human-readable descriptions
814
- describeCron("0 9 * * *"); // "At 09:00"
815
- describeCron("0 9 * * 1-5"); // "At 09:00 on Monday through Friday"
816
- describeCron("0 0 1 * *"); // "At 00:00 on day 1 of every month"
817
-
818
- // Validate cron expressions
819
- isValidCron("0 9 * * *"); // true
820
- isValidCron("invalid"); // false
821
-
822
- // Common presets
823
- CRON_PRESETS.EVERY_MINUTE; // "* * * * *"
824
- CRON_PRESETS.HOURLY; // "0 * * * *"
825
- CRON_PRESETS.DAILY; // "0 0 * * *"
826
- CRON_PRESETS.WEEKLY; // "0 0 * * 0"
827
- CRON_PRESETS.MONTHLY; // "0 0 1 * *"
828
- CRON_PRESETS.WEEKDAYS; // "0 0 * * 1-5"
316
+ import { sleep, benchmark, Stopwatch, debounce } from 'ts-time-utils/performance';
317
+
318
+ await sleep(1000);
319
+ await benchmark(() => heavyOperation(), 10);
320
+
321
+ const stopwatch = new Stopwatch();
322
+ stopwatch.start();
323
+ // ... operations
324
+ stopwatch.getElapsed();
325
+
326
+ const debouncedFn = debounce(fn, 300);
829
327
  ```
830
328
 
831
- ### Fiscal Year Utilities (NEW!)
329
+ ### Age
330
+
331
+ Age calculations and birthday utilities.
832
332
 
833
333
  ```ts
834
- import {
835
- getFiscalYear,
836
- getFiscalQuarter,
837
- getFiscalYearStart,
838
- getFiscalYearEnd,
839
- getFiscalPeriodInfo,
840
- formatFiscalYear,
841
- FISCAL_PRESETS,
842
- } from "ts-time-utils/fiscal";
843
-
844
- // Default calendar year (January start)
845
- getFiscalYear(new Date("2024-06-15")); // 2024
846
- getFiscalQuarter(new Date("2024-06-15")); // 2
847
-
848
- // UK/India fiscal year (April start)
849
- getFiscalYear(new Date("2024-03-15"), FISCAL_PRESETS.UK_INDIA); // 2023
850
- getFiscalYear(new Date("2024-04-15"), FISCAL_PRESETS.UK_INDIA); // 2024
851
-
852
- // Australian fiscal year (July start)
853
- getFiscalYear(new Date("2024-06-30"), FISCAL_PRESETS.AUSTRALIA); // 2023
854
- getFiscalYear(new Date("2024-07-01"), FISCAL_PRESETS.AUSTRALIA); // 2024
855
-
856
- // US Federal fiscal year (October start)
857
- getFiscalYear(new Date("2024-09-30"), FISCAL_PRESETS.US_FEDERAL); // 2023
858
- getFiscalYear(new Date("2024-10-01"), FISCAL_PRESETS.US_FEDERAL); // 2024
859
-
860
- // Get fiscal year boundaries
861
- getFiscalYearStart(2024, FISCAL_PRESETS.UK_INDIA); // April 1, 2024
862
- getFiscalYearEnd(2024, FISCAL_PRESETS.UK_INDIA); // March 31, 2025
863
-
864
- // Format fiscal years
865
- formatFiscalYear(2024); // "FY2024"
866
- formatFiscalYear(2024, FISCAL_PRESETS.UK_INDIA, "long"); // "FY2024/25"
867
-
868
- // Get comprehensive fiscal info
869
- const info = getFiscalPeriodInfo(new Date("2024-06-15"));
870
- // { fiscalYear: 2024, fiscalQuarter: 2, fiscalMonth: 6, progress: 45.2, ... }
334
+ import { calculateAge, getLifeStage, getNextBirthday } from 'ts-time-utils/age';
335
+
336
+ calculateAge(new Date('1990-05-15')); // { years: 34, months: 4, days: 2 }
337
+ getLifeStage(25); // "adult"
338
+ getNextBirthday(birthDate); // Next birthday date
871
339
  ```
872
340
 
873
- ### Date Comparison & Sorting (NEW!)
341
+ ### Countdown
874
342
 
875
- ```ts
876
- import {
877
- sortDates,
878
- minDate,
879
- maxDate,
880
- closestDate,
881
- uniqueDates,
882
- groupDatesByMonth,
883
- snapDate,
884
- roundDate,
885
- medianDate,
886
- } from "ts-time-utils/compare";
887
-
888
- const dates = [
889
- new Date("2024-03-15"),
890
- new Date("2024-01-10"),
891
- new Date("2024-06-20"),
892
- ];
343
+ Timer and countdown utilities.
893
344
 
894
- // Sort dates
895
- sortDates(dates); // [Jan 10, Mar 15, Jun 20]
896
- sortDates(dates, "desc"); // [Jun 20, Mar 15, Jan 10]
345
+ ```ts
346
+ import { createCountdown, getRemainingTime, formatCountdown } from 'ts-time-utils/countdown';
897
347
 
898
- // Find extremes
899
- minDate(dates); // Jan 10, 2024
900
- maxDate(dates); // Jun 20, 2024
901
- medianDate(dates); // Mar 15, 2024
348
+ const countdown = createCountdown(targetDate, {
349
+ onTick: (remaining) => console.log(remaining.days, 'd'),
350
+ onComplete: () => console.log('Done!'),
351
+ });
352
+ countdown.start();
902
353
 
903
- // Find closest to target
904
- const target = new Date("2024-04-01");
905
- closestDate(target, dates); // Mar 15, 2024
354
+ getRemainingTime(targetDate); // { days, hours, minutes, seconds }
355
+ formatCountdown(targetDate, { units: ['days', 'hours'] }); // "45d 12h"
356
+ ```
906
357
 
907
- // Remove duplicates
908
- uniqueDates([date1, date1Copy, date2]); // [date1, date2]
909
- uniqueDates(dates, "day"); // Unique by day precision
358
+ ### Interval
910
359
 
911
- // Group dates
912
- groupDatesByMonth(dates);
913
- // Map { "2024-01" => [Jan 10], "2024-03" => [Mar 15], "2024-06" => [Jun 20] }
360
+ Time interval operations.
914
361
 
915
- // Snap to intervals (e.g., 15-minute blocks)
916
- snapDate(new Date("2024-01-15T10:37:00"), 15); // 10:30:00
917
- snapDate(new Date("2024-01-15T10:37:00"), 15, "ceil"); // 10:45:00
362
+ ```ts
363
+ import { createInterval, intervalsOverlap, mergeIntervals } from 'ts-time-utils/interval';
918
364
 
919
- // Round to nearest unit
920
- roundDate(new Date("2024-01-15T10:37:00"), "hour"); // 11:00:00
365
+ const a = createInterval('2025-01-01', '2025-01-05');
366
+ const b = createInterval('2025-01-04', '2025-01-10');
367
+ intervalsOverlap(a, b); // true
368
+ mergeIntervals([a, b]); // Single merged interval
921
369
  ```
922
370
 
923
- ### Date Iteration (NEW!)
371
+ ### Range Presets
372
+
373
+ Common date range presets.
924
374
 
925
375
  ```ts
926
- import {
927
- eachDay,
928
- eachWeekday,
929
- eachWeek,
930
- eachMonth,
931
- countWeekdays,
932
- eachDayOfWeek,
933
- iterateDays,
934
- filterDays,
935
- } from "ts-time-utils/iterate";
936
-
937
- const start = new Date("2024-01-01");
938
- const end = new Date("2024-01-31");
939
-
940
- // Generate arrays of dates
941
- eachDay(start, end); // [Jan 1, Jan 2, ..., Jan 31] (31 dates)
942
- eachWeekday(start, end); // All Mon-Fri dates (23 dates)
943
- eachWeek(start, end); // [Jan 7, Jan 14, Jan 21, Jan 28] (Sundays)
944
- eachMonth(start, new Date("2024-06-30")); // [Feb 1, Mar 1, Apr 1, May 1, Jun 1]
945
-
946
- // Count dates
947
- countWeekdays(start, end); // 23
948
-
949
- // Get specific weekdays
950
- eachDayOfWeek(start, end, 1); // All Mondays in January
951
-
952
- // Lazy iteration (memory efficient for large ranges)
953
- for (const date of iterateDays(start, end)) {
954
- console.log(date);
955
- }
956
-
957
- // Filter days by custom predicate
958
- filterDays(start, end, (d) => d.getDate() === 15); // [Jan 15]
959
-
960
- // Custom intervals
961
- eachInterval(start, end, { days: 7 }); // Every 7 days
962
- eachInterval(start, end, { hours: 6 }); // Every 6 hours
376
+ import { today, lastNDays, thisWeek, thisMonth } from 'ts-time-utils/rangePresets';
377
+
378
+ today(); // { start, end } for today
379
+ lastNDays(7); // Last 7 days
380
+ thisWeek(); // Current week
381
+ thisMonth(); // Current month
963
382
  ```
964
383
 
965
- ### International Holidays (NEW!)
384
+ ### Parse
966
385
 
967
- ```ts
968
- import {
969
- getHolidays,
970
- isHoliday,
971
- getHolidayName,
972
- getNextHoliday,
973
- getUpcomingHolidays,
974
- getSupportedCountries,
975
- getUKHolidays,
976
- getCanadaHolidays,
977
- } from "ts-time-utils/holidays";
978
-
979
- // Get all holidays for a country and year
980
- const ukHolidays2024 = getHolidays(2024, "UK");
981
- console.log(ukHolidays2024);
982
- // [
983
- // { name: "New Year's Day", date: Date, countryCode: "UK", type: "bank" },
984
- // { name: "Good Friday", date: Date, countryCode: "UK", type: "bank" },
985
- // { name: "Easter Monday", date: Date, countryCode: "UK", type: "bank" },
986
- // ...
987
- // ]
988
-
989
- // Check if a date is a holiday
990
- const christmas = new Date(2024, 11, 25);
991
- isHoliday(christmas, "UK"); // true
992
- isHoliday(new Date(2024, 5, 15), "UK"); // false
993
-
994
- // Get holiday name for a date
995
- getHolidayName(christmas, "UK"); // "Christmas Day"
996
- getHolidayName(new Date(2024, 0, 1), "CA"); // "New Year's Day"
997
-
998
- // Find next holiday from a date
999
- const today = new Date();
1000
- const nextHoliday = getNextHoliday(today, "CA");
1001
- console.log(`Next holiday: ${nextHoliday?.name} on ${nextHoliday?.date}`);
1002
-
1003
- // Get upcoming holidays in the next 90 days
1004
- const upcoming = getUpcomingHolidays(today, 90, "AU");
1005
- upcoming.forEach((h) => {
1006
- console.log(`${h.name} - ${h.date.toDateString()}`);
1007
- });
386
+ Date parsing from various formats.
1008
387
 
1009
- // Get supported countries
1010
- getSupportedCountries(); // ["UK", "NL", "DE", "CA", "AU", "IT", "ES", "CN", "IN", "US"]
388
+ ```ts
389
+ import { parseDate, parseTime, autoDetectFormat } from 'ts-time-utils/parse';
1011
390
 
1012
- // Country-specific functions
1013
- const nlHolidays = getHolidays(2024, "NL"); // Netherlands holidays (includes King's Day)
1014
- const deHolidays = getHolidays(2024, "DE"); // German holidays (includes German Unity Day)
1015
- const itHolidays = getHolidays(2024, "IT"); // Italian holidays (includes Republic Day)
1016
- const esHolidays = getHolidays(2024, "ES"); // Spanish holidays (includes Constitution Day)
391
+ parseDate('Dec 25, 2025');
392
+ parseDate('25/12/2025', 'DD/MM/YYYY');
393
+ parseTime('2:30 PM'); // { hour: 14, minute: 30 }
394
+ autoDetectFormat('2025-09-14'); // 'YYYY-MM-DD'
1017
395
  ```
1018
396
 
1019
- ### Locale Utilities
397
+ ---
398
+
399
+ ## Plugin System
400
+
401
+ Extend ChainedDate with custom functionality.
1020
402
 
1021
403
  ```ts
1022
- import {
1023
- formatRelativeTime,
1024
- formatDateLocale,
1025
- formatTimeLocale,
1026
- formatDateTimeLocale,
1027
- registerLocale,
1028
- getLocaleConfig,
1029
- detectLocale,
1030
- getSupportedLocales,
1031
- } from "ts-time-utils/locale";
1032
-
1033
- // Relative time formatting in multiple languages
1034
- const pastDate = new Date(Date.now() - 2 * 60 * 60 * 1000); // 2 hours ago
1035
- formatRelativeTime(pastDate, { locale: "en" }); // "2 hours ago"
1036
- formatRelativeTime(pastDate, { locale: "es" }); // "hace 2 horas"
1037
- formatRelativeTime(pastDate, { locale: "fr" }); // "il y a 2 heures"
1038
- formatRelativeTime(pastDate, { locale: "de" }); // "vor 2 Stunden"
1039
- formatRelativeTime(pastDate, { locale: "nl" }); // "2 uur geleden"
1040
- formatRelativeTime(pastDate, { locale: "it" }); // "2 ore fa"
1041
- formatRelativeTime(pastDate, { locale: "zh" }); // "2小时前"
1042
- formatRelativeTime(pastDate, { locale: "ja" }); // "2時間前"
1043
- formatRelativeTime(pastDate, { locale: "fa" }); // "2 ساعت پیش"
1044
-
1045
- // Future dates
1046
- const futureDate = new Date(Date.now() + 3 * 24 * 60 * 60 * 1000);
1047
- formatRelativeTime(futureDate, { locale: "en" }); // "in 3 days"
1048
- formatRelativeTime(futureDate, { locale: "es" }); // "en 3 dĂ­as"
1049
- formatRelativeTime(futureDate, { locale: "nl" }); // "over 3 dagen"
1050
- formatRelativeTime(futureDate, { locale: "it" }); // "tra 3 giorni"
1051
- formatRelativeTime(futureDate, { locale: "fa" }); // "3 روز دیگر"
1052
-
1053
- // Relative time options
1054
- formatRelativeTime(pastDate, {
1055
- locale: "en",
1056
- maxUnit: "days", // Don't use units larger than days
1057
- minUnit: "minutes", // Don't use units smaller than minutes
1058
- precision: 1, // Show 1 decimal place: "2.0 hours ago"
1059
- short: true, // Use abbreviated format: "2h ago"
1060
- numeric: "auto", // Use words when appropriate: "yesterday"
1061
- });
404
+ import { chain, registerPlugin, createPlugin } from 'ts-time-utils/chain';
1062
405
 
1063
- // Date formatting
1064
- const date = new Date("2024-01-15T14:30:45Z");
1065
- formatDateLocale(date, "en", "medium"); // "Jan 15, 2024"
1066
- formatDateLocale(date, "es", "medium"); // "15 ene 2024"
1067
- formatDateLocale(date, "fr", "long"); // "15 janvier 2024"
1068
- formatDateLocale(date, "de", "short"); // "15.1.2024"
1069
-
1070
- // Time formatting
1071
- formatTimeLocale(date, "en", "short"); // "2:30 PM"
1072
- formatTimeLocale(date, "de", "medium"); // "14:30:45"
1073
- formatTimeLocale(date, "fr", "long"); // "14:30:45 UTC"
1074
-
1075
- // Combined date and time
1076
- formatDateTimeLocale(date, "en"); // "Jan 15, 2024 2:30:45 PM"
1077
-
1078
- // Auto-detect locale from browser/system
1079
- const userLocale = detectLocale(); // e.g., 'en-US' or 'fr-FR'
1080
- formatRelativeTime(pastDate, { locale: userLocale });
1081
-
1082
- // Get supported locales
1083
- const locales = getSupportedLocales();
1084
- // ['en', 'es', 'fr', 'de', 'zh', 'ja', ...]
1085
-
1086
- // Register custom locale
1087
- registerLocale("custom", {
1088
- locale: "custom",
1089
- dateFormats: {
1090
- short: "M/d/yyyy",
1091
- medium: "MMM d, yyyy",
1092
- long: "MMMM d, yyyy",
1093
- full: "EEEE, MMMM d, yyyy",
1094
- },
1095
- timeFormats: {
1096
- short: "h:mm a",
1097
- medium: "h:mm:ss a",
1098
- long: "h:mm:ss a z",
1099
- full: "h:mm:ss a zzzz",
1100
- },
1101
- relativeTime: {
1102
- future: "in {0}",
1103
- past: "{0} ago",
1104
- units: {
1105
- second: "sec",
1106
- seconds: "secs",
1107
- minute: "min",
1108
- minutes: "mins",
1109
- hour: "hr",
1110
- hours: "hrs",
1111
- day: "day",
1112
- days: "days",
1113
- week: "wk",
1114
- weeks: "wks",
1115
- month: "mo",
1116
- months: "mos",
1117
- year: "yr",
1118
- years: "yrs",
1119
- },
1120
- },
1121
- calendar: {
1122
- weekStartsOn: 0, // Sunday
1123
- monthNames: ["Jan", "Feb", "Mar" /* ... */],
1124
- monthNamesShort: ["J", "F", "M" /* ... */],
1125
- dayNames: ["Sun", "Mon", "Tue" /* ... */],
1126
- dayNamesShort: ["S", "M", "T" /* ... */],
1127
- },
1128
- numbers: {
1129
- decimal: ".",
1130
- thousands: ",",
406
+ const businessPlugin = createPlugin('business', {
407
+ addBusinessDays(days: number) {
408
+ // Implementation
409
+ return this;
1131
410
  },
411
+ isBusinessDay() {
412
+ const day = this.toDate().getDay();
413
+ return day !== 0 && day !== 6;
414
+ }
1132
415
  });
1133
416
 
1134
- // Locale Conversion Utilities
1135
- import {
1136
- convertRelativeTime,
1137
- detectLocaleFromRelativeTime,
1138
- convertFormatPattern,
1139
- convertFormattedDate,
1140
- convertRelativeTimeArray,
1141
- compareLocaleFormats,
1142
- } from "ts-time-utils/locale";
1143
-
1144
- // Convert relative time between locales
1145
- convertRelativeTime("2 hours ago", "en", "es"); // "hace 2 horas"
1146
- convertRelativeTime("hace 3 dĂ­as", "es", "fr"); // "il y a 3 jours"
1147
- convertRelativeTime("2h ago", "en", "de"); // "vor 2h"
1148
- convertRelativeTime("2 hours ago", "en", "nl"); // "2 uur geleden"
1149
- convertRelativeTime("2 hours ago", "en", "it"); // "2 ore fa"
1150
- convertRelativeTime("2 hours ago", "en", "fa"); // "2 ساعت پیش"
1151
- convertRelativeTime("2 ساعت پیش", "fa", "en"); // "2 hours ago"
1152
-
1153
- // Detect locale from formatted text
1154
- detectLocaleFromRelativeTime("2 hours ago"); // "en"
1155
- detectLocaleFromRelativeTime("hace 2 horas"); // "es"
1156
- detectLocaleFromRelativeTime("il y a 2 heures"); // "fr"
1157
- detectLocaleFromRelativeTime("2 uur geleden"); // "nl"
1158
- detectLocaleFromRelativeTime("2 ore fa"); // "it"
1159
- detectLocaleFromRelativeTime("2 ساعت پیش"); // "fa"
1160
- detectLocaleFromRelativeTime("vor 2 Stunden"); // "de"
1161
-
1162
- // Convert date format patterns between locales
1163
- convertFormatPattern("M/d/yyyy", "en", "de"); // "dd.MM.yyyy"
1164
- convertFormatPattern("MMM d, yyyy", "en", "fr", "long"); // "d MMMM yyyy"
1165
-
1166
- // Convert formatted dates between locales
1167
- convertFormattedDate("Jan 15, 2024", "en", "es"); // "15 ene 2024"
1168
- convertFormattedDate("15. Januar 2024", "de", "en"); // "Jan 15, 2024"
1169
-
1170
- // Bulk conversion of relative time arrays
1171
- const englishTimes = ["2 hours ago", "in 3 days", "1 week ago"];
1172
- convertRelativeTimeArray(englishTimes, "en", "es");
1173
- // ["hace 2 horas", "en 3 dĂ­as", "hace 1 semana"]
1174
-
1175
- // Compare format differences between locales
1176
- const comparison = compareLocaleFormats("en", "de");
1177
- console.log(comparison.dateFormats.short);
1178
- // { locale1: "M/d/yyyy", locale2: "dd.MM.yyyy" }
1179
- console.log(comparison.weekStartsOn);
1180
- // { locale1: 0, locale2: 1 } // Sunday vs Monday
417
+ registerPlugin(businessPlugin);
418
+
419
+ chain(new Date())
420
+ .addBusinessDays(5)
421
+ .isBusinessDay(); // true/false
1181
422
  ```
1182
423
 
1183
- ## 📊 API Reference
1184
-
1185
- ### Duration Functions
1186
-
1187
- - `Duration` class - Immutable duration with full arithmetic support
1188
- - `createDuration(input)` - Create duration from number, object, or string
1189
- - `Duration.fromHours/Minutes/Seconds/Days/Weeks(n)` - Create from specific units
1190
- - `Duration.fromString(str)` - Parse from string like "1h 30m 45s"
1191
- - `Duration.between(start, end)` - Create from date range
1192
- - `duration.add/subtract/multiply/divide()` - Arithmetic operations
1193
- - `duration.equals/greaterThan/lessThan()` - Comparison methods
1194
- - `formatDurationString(duration, options?)` - Format to readable string
1195
- - `maxDuration/minDuration(...durations)` - Find extremes
1196
- - `sumDurations/averageDuration(...durations)` - Aggregate operations
1197
-
1198
- ### Serialization Functions
1199
-
1200
- - `serializeDate(date, options?)` - Serialize date to various formats (ISO, epoch, object, custom)
1201
- - `deserializeDate(serialized, options?)` - Deserialize from string, number, or object
1202
- - `parseJSONWithDates(jsonString, dateKeys?, options?)` - Parse JSON with automatic date conversion
1203
- - `stringifyWithDates(obj, dateKeys?, options?)` - Stringify JSON with automatic date serialization
1204
- - `createDateReviver/createDateReplacer(dateKeys?, options?)` - Create JSON reviver/replacer functions
1205
- - `toEpochTimestamp/fromEpochTimestamp(input, precision?)` - Convert to/from epoch timestamps
1206
- - `toDateObject/fromDateObject(input)` - Convert to/from safe object representation
1207
- - `isValidISODateString/isValidEpochTimestamp(input)` - Validation utilities
1208
- - `cloneDate(date)` - Safe date cloning
1209
- - `datesEqual(date1, date2, precision?)` - Compare dates with precision control
1210
-
1211
- ### Format Functions
1212
-
1213
- - `formatDuration(ms, options?)` - Format milliseconds to readable duration
1214
- - `formatDurationCompact(ms)` - Format milliseconds as HH:MM:SS
1215
- - `timeAgo(date, options?)` - Get "time ago" string for past/future dates
1216
- - `formatTime(date, format?)` - Format time as 12h/24h/ISO
1217
- - `formatDate(date, pattern?)` - Format date using patterns (YYYY-MM-DD, etc.)
1218
- - `formatRelativeTime(date, locale?, options?)` - Format as relative time ("2 days ago")
1219
- - `formatDateRange(start, end, options?)` - Format date ranges ("Jan 1-5, 2024")
1220
- - `formatOrdinal(n)` - Format number as ordinal ("1st", "2nd", "3rd")
1221
- - `formatDayOrdinal(date)` - Format day with ordinal ("1st", "15th")
1222
- - `formatCalendarDate(date)` - Format as "Today", "Tomorrow", or day name
1223
- - `parseDuration(duration)` - Parse duration string to milliseconds
1224
-
1225
- ### Parse Functions
1226
-
1227
- - `parseISO8601Duration(duration)` - Parse ISO 8601 duration to object (P1Y2M3DT4H5M6S)
1228
- - `parseISO8601DurationToMs(duration)` - Parse ISO 8601 duration to milliseconds
1229
- - `parseTime(timeString)` - Parse time string ("14:30", "2:30 PM") to Date
1230
- - `guessDateFormat(dateString)` - Guess the format of a date string
1231
- - `parseAutoFormat(dateString)` - Auto-detect and parse date string
1232
- - `parseRangeEndpoint(endpoint)` - Parse range endpoint (date string, Date, or number)
1233
-
1234
- ### Calendar Functions
1235
-
1236
- - `getCalendarDays(year, month)` - Get array of days for a calendar month
1237
- - `getWeekNumber(date)` - Get ISO week number (1-53)
1238
- - `getQuarter(date)` - Get quarter (1-4)
1239
- - `getFirstDayOfMonth(date)` / `getLastDayOfMonth(date)` - Month boundaries
1240
- - `getFirstDayOfWeek(date)` / `getLastDayOfWeek(date)` - Week boundaries
1241
- - `getNthDayOfMonth(year, month, dayOfWeek, n)` - Get nth occurrence of weekday in month
1242
- - `getStartOfWeek(date, startDay?)` - Get start of week (configurable start day)
1243
- - `getEndOfWeek(date, startDay?)` - Get end of week (configurable start day)
1244
- - `getWeeksInMonth(year, month)` - Count weeks in a month
1245
-
1246
- #### US Federal Holidays
1247
-
1248
- - `getNewYearsDay(year)` - Get New Year's Day
1249
- - `getMLKDay(year)` - Get Martin Luther King Jr. Day (3rd Monday of January)
1250
- - `getPresidentsDay(year)` - Get Presidents Day (3rd Monday of February)
1251
- - `getMemorialDay(year)` - Get Memorial Day (last Monday of May)
1252
- - `getIndependenceDay(year)` - Get Independence Day (July 4th)
1253
- - `getLaborDay(year)` - Get Labor Day (1st Monday of September)
1254
- - `getColumbusDay(year)` - Get Columbus Day (2nd Monday of October)
1255
- - `getVeteransDay(year)` - Get Veterans Day (November 11th)
1256
- - `getThanksgivingDay(year)` - Get Thanksgiving Day (4th Thursday of November)
1257
- - `getChristmasDay(year)` - Get Christmas Day
1258
- - `getGoodFriday(year)` - Get Good Friday
1259
- - `getUSHolidays(year)` - Get all US federal holidays for a year
1260
- - `isUSHoliday(date)` - Check if date is a US federal holiday
1261
- - `getUSHolidayName(date)` - Get name of US holiday (or null)
1262
-
1263
- ### Timezone Functions
1264
-
1265
- - `getTimezoneOffset(timezone, date?)` - Get timezone offset in minutes
1266
- - `convertTimezone(date, fromTz, toTz)` - Convert date between timezones
1267
- - `getTimezoneNames()` - Get array of valid timezone names
1268
- - `formatWithTimezone(date, timezone, format?)` - Format date in specific timezone
1269
- - `isDST(date, timezone?)` - Check if DST is in effect
1270
- - `getNextDSTTransition(date?, timezone?)` - Get next DST transition date
1271
- - `findCommonWorkingHours(tz1, tz2, workStart?, workEnd?)` - Find overlapping work hours
1272
- - `getTimezoneAbbreviation(date, timezone?)` - Get timezone abbreviation (EST, PST, etc.)
1273
- - `convertBetweenZones(date, fromTz, toTz)` - Convert date between zones (returns new Date)
1274
- - `getTimezoneDifferenceHours(tz1, tz2, date?)` - Get hour difference between timezones
1275
- - `isSameTimezone(tz1, tz2, date?)` - Check if two timezones have same offset
1276
-
1277
- ### Working Hours Functions
1278
-
1279
- - `isWithinWorkingHours(date, config?)` - Check if time is within working hours
1280
- - `getNextWorkingHour(date, config?)` - Get next available working hour
1281
- - `addWorkingMinutes(date, minutes, config?)` - Add minutes within working hours
1282
- - `workingMinutesBetween(start, end, config?)` - Count working minutes between dates
1283
- - `addWorkingDays(date, days, config?)` - Add working days to date
1284
- - `subtractWorkingDays(date, days, config?)` - Subtract working days from date
1285
- - `getNextWorkingDay(date, config?)` - Get next working day
1286
- - `getPreviousWorkingDay(date, config?)` - Get previous working day
1287
- - `getWorkingDaysInMonth(year, month, config?)` - Count working days in month
1288
- - `getWorkingDaysInMonthArray(year, month, config?)` - Get array of working days
1289
- - `workingDaysBetween(start, end, config?)` - Count working days between dates
1290
- - `isBreakTime(date, breakStart?, breakEnd?)` - Check if time is during break
1291
- - `getWorkDayStart(date, config?)` - Get start time of work day
1292
- - `getWorkDayEnd(date, config?)` - Get end time of work day
1293
- - `getWorkingHoursPerDay(config?)` - Get working hours per day
1294
-
1295
- ### Cron Functions
1296
-
1297
- - `parseCronExpression(expression)` - Parse cron expression to object
1298
- - `matchesCron(expression, date?)` - Check if date matches cron expression
1299
- - `getNextCronDate(expression, after?)` - Get next date matching cron
1300
- - `getNextCronDates(expression, count, after?)` - Get multiple future cron dates
1301
- - `getPreviousCronDate(expression, before?)` - Get previous date matching cron
1302
- - `isValidCron(expression)` - Validate cron expression syntax
1303
- - `describeCron(expression)` - Get human-readable cron description
1304
- - `CRON_PRESETS` - Common cron expressions (EVERY_MINUTE, HOURLY, DAILY, etc.)
1305
-
1306
- ### Fiscal Year Functions
1307
-
1308
- - `getFiscalYear(date, config?)` - Get fiscal year for a date
1309
- - `getFiscalQuarter(date, config?)` - Get fiscal quarter (1-4)
1310
- - `getFiscalMonth(date, config?)` - Get fiscal month (1-12 within fiscal year)
1311
- - `getFiscalWeek(date, config?)` - Get fiscal week number
1312
- - `getFiscalYearStart(year, config?)` - Get start date of fiscal year
1313
- - `getFiscalYearEnd(year, config?)` - Get end date of fiscal year
1314
- - `getFiscalQuarterStart(year, quarter, config?)` - Get start of fiscal quarter
1315
- - `getFiscalQuarterEnd(year, quarter, config?)` - Get end of fiscal quarter
1316
- - `isSameFiscalYear(date1, date2, config?)` - Check if dates are in same fiscal year
1317
- - `isSameFiscalQuarter(date1, date2, config?)` - Check if dates are in same fiscal quarter
1318
- - `getDaysElapsedInFiscalYear(date, config?)` - Days elapsed in fiscal year
1319
- - `getDaysRemainingInFiscalYear(date, config?)` - Days remaining in fiscal year
1320
- - `getFiscalYearProgress(date, config?)` - Percentage of fiscal year completed
1321
- - `formatFiscalYear(year, config?, format?)` - Format as "FY2024" or "FY2023/24"
1322
- - `formatFiscalQuarter(year, quarter, config?)` - Format as "Q1 FY2024"
1323
- - `getFiscalPeriodInfo(date, config?)` - Get comprehensive fiscal period info
1324
- - `FISCAL_PRESETS` - CALENDAR, UK_INDIA, AUSTRALIA, US_FEDERAL
1325
-
1326
- ### Compare Functions
1327
-
1328
- - `compareDates(a, b)` - Compare function for sorting dates
1329
- - `compareDatesDesc(a, b)` - Compare function for reverse sorting
1330
- - `sortDates(dates, direction?)` - Sort date array (asc/desc)
1331
- - `minDate(dates)` - Find earliest date
1332
- - `maxDate(dates)` - Find latest date
1333
- - `dateExtent(dates)` - Get { min, max } from date array
1334
- - `uniqueDates(dates, precision?)` - Remove duplicate dates
1335
- - `closestDate(target, candidates)` - Find closest date to target
1336
- - `closestFutureDate(target, candidates)` - Find closest future date
1337
- - `closestPastDate(target, candidates)` - Find closest past date
1338
- - `clampDate(date, min, max)` - Constrain date to range
1339
- - `isDateInRange(date, min, max)` - Check if date is in range
1340
- - `filterDatesInRange(dates, min, max)` - Filter dates in range
1341
- - `groupDates(dates, keyFn)` - Group dates by custom key
1342
- - `groupDatesByYear(dates)` - Group by year
1343
- - `groupDatesByMonth(dates)` - Group by month (YYYY-MM)
1344
- - `groupDatesByDay(dates)` - Group by day (YYYY-MM-DD)
1345
- - `groupDatesByDayOfWeek(dates)` - Group by day of week (0-6)
1346
- - `medianDate(dates)` - Calculate median date
1347
- - `averageDate(dates)` - Calculate average/mean date
1348
- - `roundDate(date, unit)` - Round to nearest minute/hour/day
1349
- - `snapDate(date, intervalMinutes, mode?)` - Snap to interval grid
1350
- - `isChronological(dates, strict?)` - Check if dates are in order
1351
- - `dateSpan(dates)` - Get duration between min and max
1352
- - `partitionDates(dates, predicate)` - Split into [matching, non-matching]
1353
- - `nthDate(dates, n)` - Get nth date (supports negative indices)
1354
-
1355
- ### Iterate Functions
1356
-
1357
- - `eachDay(start, end)` - Array of each day in range
1358
- - `eachWeekday(start, end)` - Array of weekdays (Mon-Fri)
1359
- - `eachWeekend(start, end)` - Array of weekend days (Sat-Sun)
1360
- - `eachWeek(start, end, weekStartsOn?)` - Array of week starts
1361
- - `eachMonth(start, end)` - Array of month starts
1362
- - `eachMonthEnd(start, end)` - Array of month ends
1363
- - `eachQuarter(start, end)` - Array of quarter starts
1364
- - `eachYear(start, end)` - Array of year starts
1365
- - `eachHour(start, end, step?)` - Array of hourly intervals
1366
- - `eachMinute(start, end, step?)` - Array of minute intervals
1367
- - `eachDayOfWeek(start, end, dayOfWeek)` - Array of specific weekday
1368
- - `eachNthDayOfMonth(start, end, day)` - Array of nth day of each month
1369
- - `eachInterval(start, end, interval)` - Array at custom intervals
1370
- - `countDays(start, end)` - Count days in range
1371
- - `countWeekdays(start, end)` - Count weekdays in range
1372
- - `countWeekendDays(start, end)` - Count weekend days
1373
- - `countWeeks(start, end)` - Count weeks in range
1374
- - `countMonths(start, end)` - Count months in range
1375
- - `iterateDates(start, end, step?)` - Lazy date generator
1376
- - `iterateDays(start, end)` - Lazy day iterator
1377
- - `iterateWeekdays(start, end)` - Lazy weekday iterator
1378
- - `iterateMonths(start, end)` - Lazy month iterator
1379
- - `filterDays(start, end, filter)` - Filter days by predicate
1380
-
1381
- ### Holidays Functions
1382
-
1383
- - `getHolidays(year, countryCode)` - Get all holidays for a country and year
1384
- - `isHoliday(date, countryCode)` - Check if date is a holiday
1385
- - `getHolidayName(date, countryCode)` - Get holiday name for date (or null)
1386
- - `getNextHoliday(date, countryCode)` - Find next holiday after date
1387
- - `getUpcomingHolidays(date, days, countryCode)` - Get holidays in next N days
1388
- - `getSupportedCountries()` - Get array of supported country codes
1389
- - `getUKHolidays(year)` - Get UK bank holidays (New Year, Easter, Spring/Summer Bank Holiday, Christmas)
1390
- - `getNetherlandsHolidays(year)` - Get Netherlands holidays (King's Day, Liberation Day, Easter, Ascension, Whit)
1391
- - `getGermanyHolidays(year)` - Get German holidays (Unity Day, Labour Day, Easter, Ascension, Whit, Christmas)
1392
- - `getCanadaHolidays(year)` - Get Canadian federal holidays (Victoria Day, Canada Day, Labour Day, Thanksgiving)
1393
- - `getAustraliaHolidays(year)` - Get Australian holidays (Australia Day, Anzac Day, Queen's Birthday)
1394
- - `getItalyHolidays(year)` - Get Italian holidays (Epiphany, Liberation Day, Republic Day, Assumption)
1395
- - `getSpainHolidays(year)` - Get Spanish holidays (National Day, Constitution Day, Immaculate Conception)
1396
- - `getChinaHolidays(year)` - Get Chinese holidays (Spring Festival, National Day, New Year) - simplified
1397
- - `getIndiaHolidays(year)` - Get Indian holidays (Republic Day, Independence Day, Gandhi Jayanti) - simplified
1398
- - **Types**: `CountryCode` = "UK" | "NL" | "DE" | "CA" | "AU" | "IT" | "ES" | "CN" | "IN" | "US"
1399
- - **Holiday Interface**: `{ name: string, date: Date, countryCode: CountryCode, type: string }`
1400
-
1401
- ### Calculate Functions
1402
-
1403
- - `differenceInUnits(date1, date2, unit?, precise?)` - Calculate difference between dates
1404
- - `addTime(date, amount, unit)` - Add time to a date
1405
- - `subtractTime(date, amount, unit)` - Subtract time from a date
1406
- - `startOf(date, unit)` - Get start of time period
1407
- - `endOf(date, unit)` - Get end of time period
1408
- - `isBetween(date, start, end)` - Check if date is between two dates
1409
- - `businessDaysBetween(start, end)` - Count business days between dates
1410
-
1411
- ### Validation Functions
1412
-
1413
- - `isValidDate(date)` - Check if date is valid
1414
- - `isLeapYear(year)` - Check if year is leap year
1415
- - `isPast(date)` / `isFuture(date)` - Check if date is past/future
1416
- - `isToday(date)` / `isYesterday(date)` / `isTomorrow(date)` - Date comparisons
1417
- - `isSameDay(date1, date2)` - Check if dates are same day
1418
- - `isSameWeek(date1, date2)` - Check if dates are in same week
1419
- - `isSameMonth(date1, date2)` - Check if dates are in same month
1420
- - `isSameYear(date1, date2)` - Check if dates are in same year
1421
- - `isThisWeek(date)` - Check if date is in current week
1422
- - `isThisMonth(date)` - Check if date is in current month
1423
- - `isThisYear(date)` - Check if date is in current year
1424
- - `isWeekend(date)` / `isWeekday(date)` - Check day type
1425
- - `isBusinessDay(date)` - Check if date is a business day (weekday, not a US holiday)
1426
- - `isInLastNDays(date, n)` - Check if date is within last N days
1427
- - `isInNextNDays(date, n)` - Check if date is within next N days
1428
- - `isValidTimeString(time)` - Validate HH:MM time format
1429
- - `isValidISOString(dateString)` - Validate ISO 8601 date string
1430
-
1431
- ### Locale Functions
1432
-
1433
- - `formatRelativeTime(date, options?)` - Format relative time with locale support
1434
- - Options: `locale`, `maxUnit`, `minUnit`, `precision`, `short`, `numeric`, `style`
1435
- - Supports 30+ locales: en, es, fr, de, it, pt, nl, sv, da, no, fi, pl, cs, sk, hu, ro, bg, hr, sl, et, lv, lt, ru, uk, tr, ar, he, hi, th, ko, zh, ja
1436
- - `formatDateLocale(date, locale?, style?)` - Format date in locale-specific format
1437
- - Styles: 'short', 'medium', 'long', 'full'
1438
- - `formatTimeLocale(date, locale?, style?)` - Format time in locale-specific format
1439
- - `formatDateTimeLocale(date, locale?, dateStyle?, timeStyle?)` - Format both date and time
1440
- - `registerLocale(locale, config)` - Register a custom locale configuration
1441
- - `getLocaleConfig(locale)` - Get configuration for a specific locale
1442
- - `detectLocale(fallback?)` - Auto-detect system/browser locale
1443
- - `getSupportedLocales()` - Get array of all supported locale codes
1444
- - `getMonthNames(locale?, short?)` - Get localized month names
1445
- - `getDayNames(locale?, short?)` - Get localized day names
1446
- - `getBestMatchingLocale(preferences, fallback?)` - Find best matching locale from preferences
1447
-
1448
- #### Locale Conversion Functions
1449
-
1450
- - `convertRelativeTime(text, fromLocale, toLocale)` - Convert relative time between locales
1451
- - Example: `convertRelativeTime("2 hours ago", "en", "es")` → `"hace 2 horas"`
1452
- - Example: `convertRelativeTime("2 hours ago", "en", "nl")` → `"2 uur geleden"`
1453
- - Example: `convertRelativeTime("2 hours ago", "en", "it")` → `"2 ore fa"`
1454
- - Example: `convertRelativeTime("2 hours ago", "en", "fa")` → `"2 ساعت پیش"`
1455
- - `detectLocaleFromRelativeTime(text)` - Detect locale from relative time string
1456
- - Returns most likely locale or null if detection fails
1457
- - `convertFormatPattern(pattern, fromLocale, toLocale, style?)` - Convert date format patterns
1458
- - Maps common patterns between locales or uses target locale's style
1459
- - `convertFormattedDate(formattedDate, fromLocale, toLocale, targetStyle?)` - Convert formatted dates
1460
- - Parses date in source locale and reformats in target locale
1461
- - `convertRelativeTimeArray(array, fromLocale, toLocale)` - Bulk convert relative time arrays
1462
- - Returns array with same length, null for unparseable strings
1463
- - `compareLocaleFormats(locale1, locale2)` - Compare format differences between locales
1464
- - Returns object with dateFormats, timeFormats, and weekStartsOn comparisons
1465
-
1466
- ## 🛠️ Development
424
+ ---
425
+
426
+ ## API Reference
427
+
428
+ For complete API documentation, see the [Playground & Docs](https://ts-time-utils.h8frad.work).
429
+
430
+ ### All Modules
431
+
432
+ | Module | Description |
433
+ |--------|-------------|
434
+ | `format` | Duration formatting, time ago, date patterns |
435
+ | `calculate` | Date arithmetic, differences, period boundaries |
436
+ | `validate` | Date validation, comparisons, type checks |
437
+ | `duration` | Immutable Duration class with arithmetic |
438
+ | `chain` | Fluent chainable API |
439
+ | `timezone` | Timezone conversions, DST handling |
440
+ | `calendar` | ISO weeks, quarters, holidays, grids |
441
+ | `dateRange` | Range operations: overlap, gaps, merge |
442
+ | `recurrence` | RRULE-inspired recurring patterns |
443
+ | `cron` | Cron expression parsing and matching |
444
+ | `fiscal` | Fiscal year utilities |
445
+ | `compare` | Date sorting, grouping, statistics |
446
+ | `iterate` | Date iteration and counting |
447
+ | `naturalLanguage` | Natural language date parsing |
448
+ | `holidays` | International holiday calculations |
449
+ | `locale` | Multi-language formatting (40+ locales) |
450
+ | `workingHours` | Business hours calculations |
451
+ | `serialize` | JSON date serialization |
452
+ | `performance` | Async utilities, benchmarking |
453
+ | `age` | Age calculations, birthdays |
454
+ | `countdown` | Timer and countdown utilities |
455
+ | `interval` | Time interval operations |
456
+ | `rangePresets` | Common date range presets |
457
+ | `parse` | Date parsing from various formats |
458
+ | `plugins` | Plugin system for extensions |
459
+ | `constants` | Time constants and types |
460
+
461
+ ---
462
+
463
+ ## Development
1467
464
 
1468
465
  ```bash
1469
- # Install dependencies
1470
- npm install
1471
-
1472
- # Build (both CommonJS and ES modules)
1473
- npm run build
1474
-
1475
- # Run tests
1476
- npm test
1477
-
1478
- # Run tests in watch mode
1479
- npm run test:watch
1480
-
1481
- # Lint code
1482
- npm run lint
466
+ npm install # Install dependencies
467
+ npm run build # Build both CJS and ESM
468
+ npm test # Run tests
469
+ npm run lint # Lint code
1483
470
  ```
1484
471
 
1485
- ## 📄 License
472
+ ## License
1486
473
 
1487
474
  MIT