chronos-ts 2.0.2 → 2.0.3

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.
@@ -1,658 +0,0 @@
1
- "use strict";
2
- /**
3
- * Utility functions for Chronos
4
- * @module utils
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.MILLISECONDS_PER_YEAR = exports.MILLISECONDS_PER_MONTH = exports.MILLISECONDS_PER_WEEK = exports.MILLISECONDS_PER_DAY = exports.MILLISECONDS_PER_HOUR = exports.MILLISECONDS_PER_MINUTE = exports.MILLISECONDS_PER_SECOND = void 0;
8
- exports.isDate = isDate;
9
- exports.isValidDateInput = isValidDateInput;
10
- exports.isChronosLike = isChronosLike;
11
- exports.isDuration = isDuration;
12
- exports.isISODuration = isISODuration;
13
- exports.isLeapYear = isLeapYear;
14
- exports.normalizeUnit = normalizeUnit;
15
- exports.pluralizeUnit = pluralizeUnit;
16
- exports.getMillisecondsPerUnit = getMillisecondsPerUnit;
17
- exports.getDaysInMonth = getDaysInMonth;
18
- exports.getDaysInYear = getDaysInYear;
19
- exports.getDayOfYear = getDayOfYear;
20
- exports.getISOWeek = getISOWeek;
21
- exports.getISOWeekYear = getISOWeekYear;
22
- exports.getQuarter = getQuarter;
23
- exports.startOf = startOf;
24
- exports.endOf = endOf;
25
- exports.addDuration = addDuration;
26
- exports.subtractDuration = subtractDuration;
27
- exports.addUnits = addUnits;
28
- exports.diffInUnits = diffInUnits;
29
- exports.parseISODuration = parseISODuration;
30
- exports.durationToISO = durationToISO;
31
- exports.compareAtGranularity = compareAtGranularity;
32
- exports.isSameAt = isSameAt;
33
- exports.cloneDate = cloneDate;
34
- exports.isValidDate = isValidDate;
35
- exports.clamp = clamp;
36
- exports.ordinalSuffix = ordinalSuffix;
37
- exports.padStart = padStart;
38
- const types_1 = require("../types");
39
- Object.defineProperty(exports, "MILLISECONDS_PER_SECOND", { enumerable: true, get: function () { return types_1.MILLISECONDS_PER_SECOND; } });
40
- Object.defineProperty(exports, "MILLISECONDS_PER_MINUTE", { enumerable: true, get: function () { return types_1.MILLISECONDS_PER_MINUTE; } });
41
- Object.defineProperty(exports, "MILLISECONDS_PER_HOUR", { enumerable: true, get: function () { return types_1.MILLISECONDS_PER_HOUR; } });
42
- Object.defineProperty(exports, "MILLISECONDS_PER_DAY", { enumerable: true, get: function () { return types_1.MILLISECONDS_PER_DAY; } });
43
- Object.defineProperty(exports, "MILLISECONDS_PER_WEEK", { enumerable: true, get: function () { return types_1.MILLISECONDS_PER_WEEK; } });
44
- Object.defineProperty(exports, "MILLISECONDS_PER_MONTH", { enumerable: true, get: function () { return types_1.MILLISECONDS_PER_MONTH; } });
45
- Object.defineProperty(exports, "MILLISECONDS_PER_YEAR", { enumerable: true, get: function () { return types_1.MILLISECONDS_PER_YEAR; } });
46
- // ============================================================================
47
- // Type Guards
48
- // ============================================================================
49
- /**
50
- * Check if value is a Date object
51
- */
52
- function isDate(value) {
53
- return value instanceof Date && !isNaN(value.getTime());
54
- }
55
- /**
56
- * Check if value is a valid date input
57
- */
58
- function isValidDateInput(value) {
59
- if (value === null || value === undefined)
60
- return true;
61
- if (typeof value === 'string' || typeof value === 'number')
62
- return true;
63
- if (isDate(value))
64
- return true;
65
- if (isChronosLike(value))
66
- return true;
67
- return false;
68
- }
69
- /**
70
- * Check if value implements ChronosLike interface
71
- */
72
- function isChronosLike(value) {
73
- if (!value || typeof value !== 'object')
74
- return false;
75
- const obj = value;
76
- return typeof obj.toDate === 'function' && typeof obj.valueOf === 'function';
77
- }
78
- /**
79
- * Check if value is a Duration object
80
- */
81
- function isDuration(value) {
82
- if (!value || typeof value !== 'object')
83
- return false;
84
- const obj = value;
85
- const keys = [
86
- 'years',
87
- 'months',
88
- 'weeks',
89
- 'days',
90
- 'hours',
91
- 'minutes',
92
- 'seconds',
93
- 'milliseconds',
94
- ];
95
- return keys.some((key) => typeof obj[key] === 'number');
96
- }
97
- /**
98
- * Check if value is a valid ISO 8601 duration string
99
- */
100
- function isISODuration(value) {
101
- if (typeof value !== 'string')
102
- return false;
103
- const pattern = /^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/;
104
- return pattern.test(value);
105
- }
106
- /**
107
- * Check if a year is a leap year
108
- */
109
- function isLeapYear(year) {
110
- return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
111
- }
112
- // ============================================================================
113
- // Time Unit Utilities
114
- // ============================================================================
115
- /**
116
- * Unit aliases mapping
117
- */
118
- const UNIT_ALIASES = {
119
- // Singular
120
- millisecond: 'millisecond',
121
- second: 'second',
122
- minute: 'minute',
123
- hour: 'hour',
124
- day: 'day',
125
- week: 'week',
126
- month: 'month',
127
- quarter: 'quarter',
128
- year: 'year',
129
- decade: 'decade',
130
- century: 'century',
131
- millennium: 'millennium',
132
- // Plural
133
- milliseconds: 'millisecond',
134
- seconds: 'second',
135
- minutes: 'minute',
136
- hours: 'hour',
137
- days: 'day',
138
- weeks: 'week',
139
- months: 'month',
140
- quarters: 'quarter',
141
- years: 'year',
142
- decades: 'decade',
143
- centuries: 'century',
144
- millennia: 'millennium',
145
- // Short
146
- ms: 'millisecond',
147
- s: 'second',
148
- m: 'minute',
149
- h: 'hour',
150
- d: 'day',
151
- w: 'week',
152
- M: 'month',
153
- Q: 'quarter',
154
- y: 'year',
155
- };
156
- /**
157
- * Normalize a time unit to its canonical form
158
- */
159
- function normalizeUnit(unit) {
160
- var _a;
161
- // Check original case first for case-sensitive short codes (M vs m, etc.)
162
- const normalized = (_a = UNIT_ALIASES[unit]) !== null && _a !== void 0 ? _a : UNIT_ALIASES[unit.toLowerCase()];
163
- if (!normalized) {
164
- throw new Error(`Invalid time unit: ${unit}`);
165
- }
166
- return normalized;
167
- }
168
- /**
169
- * Get the plural form of a time unit
170
- */
171
- function pluralizeUnit(unit, count) {
172
- const plurals = {
173
- millisecond: 'milliseconds',
174
- second: 'seconds',
175
- minute: 'minutes',
176
- hour: 'hours',
177
- day: 'days',
178
- week: 'weeks',
179
- month: 'months',
180
- quarter: 'quarters',
181
- year: 'years',
182
- decade: 'decades',
183
- century: 'centuries',
184
- millennium: 'millennia',
185
- };
186
- return Math.abs(count) === 1 ? unit : plurals[unit];
187
- }
188
- /**
189
- * Get milliseconds for a given time unit
190
- */
191
- function getMillisecondsPerUnit(unit) {
192
- switch (unit) {
193
- case 'millisecond':
194
- return 1;
195
- case 'second':
196
- return types_1.MILLISECONDS_PER_SECOND;
197
- case 'minute':
198
- return types_1.MILLISECONDS_PER_MINUTE;
199
- case 'hour':
200
- return types_1.MILLISECONDS_PER_HOUR;
201
- case 'day':
202
- return types_1.MILLISECONDS_PER_DAY;
203
- case 'week':
204
- return types_1.MILLISECONDS_PER_WEEK;
205
- case 'month':
206
- return types_1.MILLISECONDS_PER_MONTH;
207
- case 'quarter':
208
- return types_1.MILLISECONDS_PER_MONTH * 3;
209
- case 'year':
210
- return types_1.MILLISECONDS_PER_YEAR;
211
- case 'decade':
212
- return types_1.MILLISECONDS_PER_YEAR * 10;
213
- case 'century':
214
- return types_1.MILLISECONDS_PER_YEAR * 100;
215
- case 'millennium':
216
- return types_1.MILLISECONDS_PER_YEAR * 1000;
217
- default:
218
- throw new Error(`Unknown unit: ${unit}`);
219
- }
220
- }
221
- // ============================================================================
222
- // Date Utilities
223
- // ============================================================================
224
- /**
225
- * Get the number of days in a specific month
226
- */
227
- function getDaysInMonth(year, month) {
228
- // Create date for first day of next month, then subtract one day
229
- return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
230
- }
231
- /**
232
- * Get the number of days in a year
233
- */
234
- function getDaysInYear(year) {
235
- return isLeapYear(year) ? 366 : 365;
236
- }
237
- /**
238
- * Get the day of year (1-366)
239
- */
240
- function getDayOfYear(date) {
241
- // Use local time consistently (not UTC) to avoid timezone issues
242
- const start = new Date(date.getFullYear(), 0, 0);
243
- const diff = date.getTime() - start.getTime();
244
- return Math.floor(diff / types_1.MILLISECONDS_PER_DAY);
245
- }
246
- /**
247
- * Get the ISO week number (1-53)
248
- */
249
- function getISOWeek(date) {
250
- const target = new Date(date.valueOf());
251
- // Set to nearest Thursday: current date + 4 - current day number (make Sunday=7)
252
- const dayNr = (date.getDay() + 6) % 7;
253
- target.setDate(target.getDate() - dayNr + 3);
254
- // Store first Thursday of year
255
- const firstThursday = target.valueOf();
256
- // Set to start of year
257
- target.setMonth(0, 1);
258
- // If not Thursday, set to first Thursday of year
259
- if (target.getDay() !== 4) {
260
- target.setMonth(0, 1 + ((4 - target.getDay() + 7) % 7));
261
- }
262
- // Calculate week number
263
- return (1 + Math.ceil((firstThursday - target.valueOf()) / types_1.MILLISECONDS_PER_WEEK));
264
- }
265
- /**
266
- * Get the ISO week year
267
- */
268
- function getISOWeekYear(date) {
269
- const target = new Date(date.valueOf());
270
- target.setDate(target.getDate() + 3 - ((date.getDay() + 6) % 7));
271
- return target.getFullYear();
272
- }
273
- /**
274
- * Get the quarter (1-4)
275
- */
276
- function getQuarter(date) {
277
- return Math.floor(date.getMonth() / 3) + 1;
278
- }
279
- /**
280
- * Get start of a time unit
281
- */
282
- function startOf(date, unit) {
283
- const result = new Date(date);
284
- switch (unit) {
285
- case 'second':
286
- result.setMilliseconds(0);
287
- break;
288
- case 'minute':
289
- result.setSeconds(0, 0);
290
- break;
291
- case 'hour':
292
- result.setMinutes(0, 0, 0);
293
- break;
294
- case 'day':
295
- result.setHours(0, 0, 0, 0);
296
- break;
297
- case 'week':
298
- result.setHours(0, 0, 0, 0);
299
- result.setDate(result.getDate() - result.getDay());
300
- break;
301
- case 'month':
302
- result.setHours(0, 0, 0, 0);
303
- result.setDate(1);
304
- break;
305
- case 'quarter':
306
- result.setHours(0, 0, 0, 0);
307
- result.setMonth(Math.floor(result.getMonth() / 3) * 3, 1);
308
- break;
309
- case 'year':
310
- result.setHours(0, 0, 0, 0);
311
- result.setMonth(0, 1);
312
- break;
313
- case 'decade':
314
- result.setHours(0, 0, 0, 0);
315
- result.setMonth(0, 1);
316
- result.setFullYear(Math.floor(result.getFullYear() / 10) * 10);
317
- break;
318
- case 'century':
319
- result.setHours(0, 0, 0, 0);
320
- result.setMonth(0, 1);
321
- result.setFullYear(Math.floor(result.getFullYear() / 100) * 100);
322
- break;
323
- case 'millennium':
324
- result.setHours(0, 0, 0, 0);
325
- result.setMonth(0, 1);
326
- result.setFullYear(Math.floor(result.getFullYear() / 1000) * 1000);
327
- break;
328
- case 'millisecond':
329
- default:
330
- break;
331
- }
332
- return result;
333
- }
334
- /**
335
- * Get end of a time unit
336
- */
337
- function endOf(date, unit) {
338
- const result = new Date(date);
339
- switch (unit) {
340
- case 'second':
341
- result.setMilliseconds(999);
342
- break;
343
- case 'minute':
344
- result.setSeconds(59, 999);
345
- break;
346
- case 'hour':
347
- result.setMinutes(59, 59, 999);
348
- break;
349
- case 'day':
350
- result.setHours(23, 59, 59, 999);
351
- break;
352
- case 'week':
353
- result.setHours(23, 59, 59, 999);
354
- result.setDate(result.getDate() + (6 - result.getDay()));
355
- break;
356
- case 'month':
357
- result.setHours(23, 59, 59, 999);
358
- result.setMonth(result.getMonth() + 1, 0);
359
- break;
360
- case 'quarter':
361
- result.setHours(23, 59, 59, 999);
362
- result.setMonth(Math.floor(result.getMonth() / 3) * 3 + 3, 0);
363
- break;
364
- case 'year':
365
- result.setHours(23, 59, 59, 999);
366
- result.setMonth(11, 31);
367
- break;
368
- case 'decade':
369
- result.setHours(23, 59, 59, 999);
370
- result.setFullYear(Math.floor(result.getFullYear() / 10) * 10 + 9, 11, 31);
371
- break;
372
- case 'century':
373
- result.setHours(23, 59, 59, 999);
374
- result.setFullYear(Math.floor(result.getFullYear() / 100) * 100 + 99, 11, 31);
375
- break;
376
- case 'millennium':
377
- result.setHours(23, 59, 59, 999);
378
- result.setFullYear(Math.floor(result.getFullYear() / 1000) * 1000 + 999, 11, 31);
379
- break;
380
- case 'millisecond':
381
- default:
382
- break;
383
- }
384
- return result;
385
- }
386
- // ============================================================================
387
- // Arithmetic Utilities
388
- // ============================================================================
389
- /**
390
- * Add a duration to a date
391
- * Handles month overflow by clamping to the last day of the month
392
- */
393
- function addDuration(date, duration) {
394
- const result = new Date(date);
395
- if (duration.years) {
396
- const originalDay = result.getDate();
397
- result.setFullYear(result.getFullYear() + duration.years);
398
- // Handle year overflow (e.g., Feb 29 in a leap year to Feb 28 in non-leap year)
399
- if (result.getDate() !== originalDay) {
400
- result.setDate(0); // Go to last day of previous month
401
- }
402
- }
403
- if (duration.months) {
404
- const originalDay = result.getDate();
405
- result.setMonth(result.getMonth() + duration.months);
406
- // Handle month overflow (e.g., Jan 31 + 1 month = Feb 28/29, not March 2/3)
407
- if (result.getDate() !== originalDay) {
408
- result.setDate(0); // Go to last day of previous month
409
- }
410
- }
411
- if (duration.weeks) {
412
- result.setDate(result.getDate() + duration.weeks * 7);
413
- }
414
- if (duration.days) {
415
- result.setDate(result.getDate() + duration.days);
416
- }
417
- if (duration.hours) {
418
- result.setHours(result.getHours() + duration.hours);
419
- }
420
- if (duration.minutes) {
421
- result.setMinutes(result.getMinutes() + duration.minutes);
422
- }
423
- if (duration.seconds) {
424
- result.setSeconds(result.getSeconds() + duration.seconds);
425
- }
426
- if (duration.milliseconds) {
427
- result.setMilliseconds(result.getMilliseconds() + duration.milliseconds);
428
- }
429
- return result;
430
- }
431
- /**
432
- * Subtract a duration from a date
433
- */
434
- function subtractDuration(date, duration) {
435
- const negated = {};
436
- for (const [key, value] of Object.entries(duration)) {
437
- if (typeof value === 'number') {
438
- negated[key] = -value;
439
- }
440
- }
441
- return addDuration(date, negated);
442
- }
443
- /**
444
- * Add a specific number of units to a date
445
- */
446
- function addUnits(date, amount, unit) {
447
- const duration = {};
448
- switch (unit) {
449
- case 'millisecond':
450
- duration.milliseconds = amount;
451
- break;
452
- case 'second':
453
- duration.seconds = amount;
454
- break;
455
- case 'minute':
456
- duration.minutes = amount;
457
- break;
458
- case 'hour':
459
- duration.hours = amount;
460
- break;
461
- case 'day':
462
- duration.days = amount;
463
- break;
464
- case 'week':
465
- duration.weeks = amount;
466
- break;
467
- case 'month':
468
- duration.months = amount;
469
- break;
470
- case 'quarter':
471
- duration.months = amount * 3;
472
- break;
473
- case 'year':
474
- duration.years = amount;
475
- break;
476
- case 'decade':
477
- duration.years = amount * 10;
478
- break;
479
- case 'century':
480
- duration.years = amount * 100;
481
- break;
482
- case 'millennium':
483
- duration.years = amount * 1000;
484
- break;
485
- }
486
- return addDuration(date, duration);
487
- }
488
- // ============================================================================
489
- // Difference Utilities
490
- // ============================================================================
491
- /**
492
- * Calculate the difference between two dates in a specific unit
493
- */
494
- function diffInUnits(date1, date2, unit) {
495
- const diff = date1.getTime() - date2.getTime();
496
- switch (unit) {
497
- case 'millisecond':
498
- return diff;
499
- case 'second':
500
- return Math.floor(diff / types_1.MILLISECONDS_PER_SECOND);
501
- case 'minute':
502
- return Math.floor(diff / types_1.MILLISECONDS_PER_MINUTE);
503
- case 'hour':
504
- return Math.floor(diff / types_1.MILLISECONDS_PER_HOUR);
505
- case 'day':
506
- return Math.floor(diff / types_1.MILLISECONDS_PER_DAY);
507
- case 'week':
508
- return Math.floor(diff / types_1.MILLISECONDS_PER_WEEK);
509
- case 'month':
510
- return monthDiff(date2, date1);
511
- case 'quarter':
512
- return Math.floor(monthDiff(date2, date1) / 3);
513
- case 'year':
514
- return date1.getFullYear() - date2.getFullYear();
515
- case 'decade':
516
- return Math.floor((date1.getFullYear() - date2.getFullYear()) / 10);
517
- case 'century':
518
- return Math.floor((date1.getFullYear() - date2.getFullYear()) / 100);
519
- case 'millennium':
520
- return Math.floor((date1.getFullYear() - date2.getFullYear()) / 1000);
521
- default:
522
- throw new Error(`Unknown unit: ${unit}`);
523
- }
524
- }
525
- /**
526
- * Calculate month difference between two dates
527
- */
528
- function monthDiff(from, to) {
529
- const years = to.getFullYear() - from.getFullYear();
530
- const months = to.getMonth() - from.getMonth();
531
- const days = to.getDate() - from.getDate();
532
- let diff = years * 12 + months;
533
- // Adjust for day difference
534
- if (days < 0) {
535
- diff--;
536
- }
537
- return diff;
538
- }
539
- // ============================================================================
540
- // Parsing Utilities
541
- // ============================================================================
542
- /**
543
- * Parse an ISO 8601 duration string
544
- */
545
- function parseISODuration(duration) {
546
- const pattern = /^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/;
547
- const match = duration.match(pattern);
548
- if (!match) {
549
- throw new Error(`Invalid ISO 8601 duration: ${duration}`);
550
- }
551
- return {
552
- years: match[1] ? parseInt(match[1], 10) : undefined,
553
- months: match[2] ? parseInt(match[2], 10) : undefined,
554
- weeks: match[3] ? parseInt(match[3], 10) : undefined,
555
- days: match[4] ? parseInt(match[4], 10) : undefined,
556
- hours: match[5] ? parseInt(match[5], 10) : undefined,
557
- minutes: match[6] ? parseInt(match[6], 10) : undefined,
558
- seconds: match[7] ? parseFloat(match[7]) : undefined,
559
- };
560
- }
561
- /**
562
- * Convert a duration to ISO 8601 format
563
- */
564
- function durationToISO(duration) {
565
- var _a, _b;
566
- let result = 'P';
567
- if (duration.years)
568
- result += `${duration.years}Y`;
569
- if (duration.months)
570
- result += `${duration.months}M`;
571
- if (duration.weeks)
572
- result += `${duration.weeks}W`;
573
- if (duration.days)
574
- result += `${duration.days}D`;
575
- const hasTime = duration.hours ||
576
- duration.minutes ||
577
- duration.seconds ||
578
- duration.milliseconds;
579
- if (hasTime) {
580
- result += 'T';
581
- if (duration.hours)
582
- result += `${duration.hours}H`;
583
- if (duration.minutes)
584
- result += `${duration.minutes}M`;
585
- const seconds = ((_a = duration.seconds) !== null && _a !== void 0 ? _a : 0) + ((_b = duration.milliseconds) !== null && _b !== void 0 ? _b : 0) / 1000;
586
- if (seconds)
587
- result += `${seconds}S`;
588
- }
589
- return result === 'P' ? 'PT0S' : result;
590
- }
591
- // ============================================================================
592
- // Comparison Utilities
593
- // ============================================================================
594
- /**
595
- * Compare two dates at a specific granularity
596
- */
597
- function compareAtGranularity(date1, date2, unit) {
598
- const d1 = startOf(date1, unit);
599
- const d2 = startOf(date2, unit);
600
- if (d1.getTime() < d2.getTime())
601
- return -1;
602
- if (d1.getTime() > d2.getTime())
603
- return 1;
604
- return 0;
605
- }
606
- /**
607
- * Check if two dates are the same at a specific granularity
608
- */
609
- function isSameAt(date1, date2, unit) {
610
- return compareAtGranularity(date1, date2, unit) === 0;
611
- }
612
- // ============================================================================
613
- // Cloning Utilities
614
- // ============================================================================
615
- /**
616
- * Create a deep clone of a date
617
- */
618
- function cloneDate(date) {
619
- return new Date(date.getTime());
620
- }
621
- // ============================================================================
622
- // Validation Utilities
623
- // ============================================================================
624
- /**
625
- * Check if a date is valid
626
- */
627
- function isValidDate(date) {
628
- return date instanceof Date && !isNaN(date.getTime());
629
- }
630
- /**
631
- * Ensure a value is within bounds
632
- */
633
- function clamp(value, min, max) {
634
- return Math.min(Math.max(value, min), max);
635
- }
636
- // ============================================================================
637
- // Ordinal Utilities
638
- // ============================================================================
639
- /**
640
- * Get ordinal suffix for a number (1st, 2nd, 3rd, etc.)
641
- */
642
- function ordinalSuffix(n) {
643
- const s = ['th', 'st', 'nd', 'rd'];
644
- const v = n % 100;
645
- return n + (s[(v - 20) % 10] || s[v] || s[0]);
646
- }
647
- // ============================================================================
648
- // Padding Utilities
649
- // ============================================================================
650
- /**
651
- * Pad a number with leading zeros
652
- */
653
- function padStart(value, length, char = '0') {
654
- const str = String(value);
655
- if (str.length >= length)
656
- return str;
657
- return char.repeat(length - str.length) + str;
658
- }