chronos-ts 1.1.0 → 2.0.1

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.
@@ -0,0 +1,656 @@
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
+ const normalized = (_a = UNIT_ALIASES[unit.toLowerCase()]) !== null && _a !== void 0 ? _a : UNIT_ALIASES[unit];
162
+ if (!normalized) {
163
+ throw new Error(`Invalid time unit: ${unit}`);
164
+ }
165
+ return normalized;
166
+ }
167
+ /**
168
+ * Get the plural form of a time unit
169
+ */
170
+ function pluralizeUnit(unit, count) {
171
+ const plurals = {
172
+ millisecond: 'milliseconds',
173
+ second: 'seconds',
174
+ minute: 'minutes',
175
+ hour: 'hours',
176
+ day: 'days',
177
+ week: 'weeks',
178
+ month: 'months',
179
+ quarter: 'quarters',
180
+ year: 'years',
181
+ decade: 'decades',
182
+ century: 'centuries',
183
+ millennium: 'millennia',
184
+ };
185
+ return Math.abs(count) === 1 ? unit : plurals[unit];
186
+ }
187
+ /**
188
+ * Get milliseconds for a given time unit
189
+ */
190
+ function getMillisecondsPerUnit(unit) {
191
+ switch (unit) {
192
+ case 'millisecond':
193
+ return 1;
194
+ case 'second':
195
+ return types_1.MILLISECONDS_PER_SECOND;
196
+ case 'minute':
197
+ return types_1.MILLISECONDS_PER_MINUTE;
198
+ case 'hour':
199
+ return types_1.MILLISECONDS_PER_HOUR;
200
+ case 'day':
201
+ return types_1.MILLISECONDS_PER_DAY;
202
+ case 'week':
203
+ return types_1.MILLISECONDS_PER_WEEK;
204
+ case 'month':
205
+ return types_1.MILLISECONDS_PER_MONTH;
206
+ case 'quarter':
207
+ return types_1.MILLISECONDS_PER_MONTH * 3;
208
+ case 'year':
209
+ return types_1.MILLISECONDS_PER_YEAR;
210
+ case 'decade':
211
+ return types_1.MILLISECONDS_PER_YEAR * 10;
212
+ case 'century':
213
+ return types_1.MILLISECONDS_PER_YEAR * 100;
214
+ case 'millennium':
215
+ return types_1.MILLISECONDS_PER_YEAR * 1000;
216
+ default:
217
+ throw new Error(`Unknown unit: ${unit}`);
218
+ }
219
+ }
220
+ // ============================================================================
221
+ // Date Utilities
222
+ // ============================================================================
223
+ /**
224
+ * Get the number of days in a specific month
225
+ */
226
+ function getDaysInMonth(year, month) {
227
+ // Create date for first day of next month, then subtract one day
228
+ return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
229
+ }
230
+ /**
231
+ * Get the number of days in a year
232
+ */
233
+ function getDaysInYear(year) {
234
+ return isLeapYear(year) ? 366 : 365;
235
+ }
236
+ /**
237
+ * Get the day of year (1-366)
238
+ */
239
+ function getDayOfYear(date) {
240
+ const start = new Date(Date.UTC(date.getFullYear(), 0, 0));
241
+ const diff = date.getTime() - start.getTime();
242
+ return Math.floor(diff / types_1.MILLISECONDS_PER_DAY);
243
+ }
244
+ /**
245
+ * Get the ISO week number (1-53)
246
+ */
247
+ function getISOWeek(date) {
248
+ const target = new Date(date.valueOf());
249
+ // Set to nearest Thursday: current date + 4 - current day number (make Sunday=7)
250
+ const dayNr = (date.getDay() + 6) % 7;
251
+ target.setDate(target.getDate() - dayNr + 3);
252
+ // Store first Thursday of year
253
+ const firstThursday = target.valueOf();
254
+ // Set to start of year
255
+ target.setMonth(0, 1);
256
+ // If not Thursday, set to first Thursday of year
257
+ if (target.getDay() !== 4) {
258
+ target.setMonth(0, 1 + ((4 - target.getDay() + 7) % 7));
259
+ }
260
+ // Calculate week number
261
+ return (1 + Math.ceil((firstThursday - target.valueOf()) / types_1.MILLISECONDS_PER_WEEK));
262
+ }
263
+ /**
264
+ * Get the ISO week year
265
+ */
266
+ function getISOWeekYear(date) {
267
+ const target = new Date(date.valueOf());
268
+ target.setDate(target.getDate() + 3 - ((date.getDay() + 6) % 7));
269
+ return target.getFullYear();
270
+ }
271
+ /**
272
+ * Get the quarter (1-4)
273
+ */
274
+ function getQuarter(date) {
275
+ return Math.floor(date.getMonth() / 3) + 1;
276
+ }
277
+ /**
278
+ * Get start of a time unit
279
+ */
280
+ function startOf(date, unit) {
281
+ const result = new Date(date);
282
+ switch (unit) {
283
+ case 'second':
284
+ result.setMilliseconds(0);
285
+ break;
286
+ case 'minute':
287
+ result.setSeconds(0, 0);
288
+ break;
289
+ case 'hour':
290
+ result.setMinutes(0, 0, 0);
291
+ break;
292
+ case 'day':
293
+ result.setHours(0, 0, 0, 0);
294
+ break;
295
+ case 'week':
296
+ result.setHours(0, 0, 0, 0);
297
+ result.setDate(result.getDate() - result.getDay());
298
+ break;
299
+ case 'month':
300
+ result.setHours(0, 0, 0, 0);
301
+ result.setDate(1);
302
+ break;
303
+ case 'quarter':
304
+ result.setHours(0, 0, 0, 0);
305
+ result.setMonth(Math.floor(result.getMonth() / 3) * 3, 1);
306
+ break;
307
+ case 'year':
308
+ result.setHours(0, 0, 0, 0);
309
+ result.setMonth(0, 1);
310
+ break;
311
+ case 'decade':
312
+ result.setHours(0, 0, 0, 0);
313
+ result.setMonth(0, 1);
314
+ result.setFullYear(Math.floor(result.getFullYear() / 10) * 10);
315
+ break;
316
+ case 'century':
317
+ result.setHours(0, 0, 0, 0);
318
+ result.setMonth(0, 1);
319
+ result.setFullYear(Math.floor(result.getFullYear() / 100) * 100);
320
+ break;
321
+ case 'millennium':
322
+ result.setHours(0, 0, 0, 0);
323
+ result.setMonth(0, 1);
324
+ result.setFullYear(Math.floor(result.getFullYear() / 1000) * 1000);
325
+ break;
326
+ case 'millisecond':
327
+ default:
328
+ break;
329
+ }
330
+ return result;
331
+ }
332
+ /**
333
+ * Get end of a time unit
334
+ */
335
+ function endOf(date, unit) {
336
+ const result = new Date(date);
337
+ switch (unit) {
338
+ case 'second':
339
+ result.setMilliseconds(999);
340
+ break;
341
+ case 'minute':
342
+ result.setSeconds(59, 999);
343
+ break;
344
+ case 'hour':
345
+ result.setMinutes(59, 59, 999);
346
+ break;
347
+ case 'day':
348
+ result.setHours(23, 59, 59, 999);
349
+ break;
350
+ case 'week':
351
+ result.setHours(23, 59, 59, 999);
352
+ result.setDate(result.getDate() + (6 - result.getDay()));
353
+ break;
354
+ case 'month':
355
+ result.setHours(23, 59, 59, 999);
356
+ result.setMonth(result.getMonth() + 1, 0);
357
+ break;
358
+ case 'quarter':
359
+ result.setHours(23, 59, 59, 999);
360
+ result.setMonth(Math.floor(result.getMonth() / 3) * 3 + 3, 0);
361
+ break;
362
+ case 'year':
363
+ result.setHours(23, 59, 59, 999);
364
+ result.setMonth(11, 31);
365
+ break;
366
+ case 'decade':
367
+ result.setHours(23, 59, 59, 999);
368
+ result.setFullYear(Math.floor(result.getFullYear() / 10) * 10 + 9, 11, 31);
369
+ break;
370
+ case 'century':
371
+ result.setHours(23, 59, 59, 999);
372
+ result.setFullYear(Math.floor(result.getFullYear() / 100) * 100 + 99, 11, 31);
373
+ break;
374
+ case 'millennium':
375
+ result.setHours(23, 59, 59, 999);
376
+ result.setFullYear(Math.floor(result.getFullYear() / 1000) * 1000 + 999, 11, 31);
377
+ break;
378
+ case 'millisecond':
379
+ default:
380
+ break;
381
+ }
382
+ return result;
383
+ }
384
+ // ============================================================================
385
+ // Arithmetic Utilities
386
+ // ============================================================================
387
+ /**
388
+ * Add a duration to a date
389
+ * Handles month overflow by clamping to the last day of the month
390
+ */
391
+ function addDuration(date, duration) {
392
+ const result = new Date(date);
393
+ if (duration.years) {
394
+ const originalDay = result.getDate();
395
+ result.setFullYear(result.getFullYear() + duration.years);
396
+ // Handle year overflow (e.g., Feb 29 in a leap year to Feb 28 in non-leap year)
397
+ if (result.getDate() !== originalDay) {
398
+ result.setDate(0); // Go to last day of previous month
399
+ }
400
+ }
401
+ if (duration.months) {
402
+ const originalDay = result.getDate();
403
+ result.setMonth(result.getMonth() + duration.months);
404
+ // Handle month overflow (e.g., Jan 31 + 1 month = Feb 28/29, not March 2/3)
405
+ if (result.getDate() !== originalDay) {
406
+ result.setDate(0); // Go to last day of previous month
407
+ }
408
+ }
409
+ if (duration.weeks) {
410
+ result.setDate(result.getDate() + duration.weeks * 7);
411
+ }
412
+ if (duration.days) {
413
+ result.setDate(result.getDate() + duration.days);
414
+ }
415
+ if (duration.hours) {
416
+ result.setHours(result.getHours() + duration.hours);
417
+ }
418
+ if (duration.minutes) {
419
+ result.setMinutes(result.getMinutes() + duration.minutes);
420
+ }
421
+ if (duration.seconds) {
422
+ result.setSeconds(result.getSeconds() + duration.seconds);
423
+ }
424
+ if (duration.milliseconds) {
425
+ result.setMilliseconds(result.getMilliseconds() + duration.milliseconds);
426
+ }
427
+ return result;
428
+ }
429
+ /**
430
+ * Subtract a duration from a date
431
+ */
432
+ function subtractDuration(date, duration) {
433
+ const negated = {};
434
+ for (const [key, value] of Object.entries(duration)) {
435
+ if (typeof value === 'number') {
436
+ negated[key] = -value;
437
+ }
438
+ }
439
+ return addDuration(date, negated);
440
+ }
441
+ /**
442
+ * Add a specific number of units to a date
443
+ */
444
+ function addUnits(date, amount, unit) {
445
+ const duration = {};
446
+ switch (unit) {
447
+ case 'millisecond':
448
+ duration.milliseconds = amount;
449
+ break;
450
+ case 'second':
451
+ duration.seconds = amount;
452
+ break;
453
+ case 'minute':
454
+ duration.minutes = amount;
455
+ break;
456
+ case 'hour':
457
+ duration.hours = amount;
458
+ break;
459
+ case 'day':
460
+ duration.days = amount;
461
+ break;
462
+ case 'week':
463
+ duration.weeks = amount;
464
+ break;
465
+ case 'month':
466
+ duration.months = amount;
467
+ break;
468
+ case 'quarter':
469
+ duration.months = amount * 3;
470
+ break;
471
+ case 'year':
472
+ duration.years = amount;
473
+ break;
474
+ case 'decade':
475
+ duration.years = amount * 10;
476
+ break;
477
+ case 'century':
478
+ duration.years = amount * 100;
479
+ break;
480
+ case 'millennium':
481
+ duration.years = amount * 1000;
482
+ break;
483
+ }
484
+ return addDuration(date, duration);
485
+ }
486
+ // ============================================================================
487
+ // Difference Utilities
488
+ // ============================================================================
489
+ /**
490
+ * Calculate the difference between two dates in a specific unit
491
+ */
492
+ function diffInUnits(date1, date2, unit) {
493
+ const diff = date1.getTime() - date2.getTime();
494
+ switch (unit) {
495
+ case 'millisecond':
496
+ return diff;
497
+ case 'second':
498
+ return Math.floor(diff / types_1.MILLISECONDS_PER_SECOND);
499
+ case 'minute':
500
+ return Math.floor(diff / types_1.MILLISECONDS_PER_MINUTE);
501
+ case 'hour':
502
+ return Math.floor(diff / types_1.MILLISECONDS_PER_HOUR);
503
+ case 'day':
504
+ return Math.floor(diff / types_1.MILLISECONDS_PER_DAY);
505
+ case 'week':
506
+ return Math.floor(diff / types_1.MILLISECONDS_PER_WEEK);
507
+ case 'month':
508
+ return monthDiff(date2, date1);
509
+ case 'quarter':
510
+ return Math.floor(monthDiff(date2, date1) / 3);
511
+ case 'year':
512
+ return date1.getFullYear() - date2.getFullYear();
513
+ case 'decade':
514
+ return Math.floor((date1.getFullYear() - date2.getFullYear()) / 10);
515
+ case 'century':
516
+ return Math.floor((date1.getFullYear() - date2.getFullYear()) / 100);
517
+ case 'millennium':
518
+ return Math.floor((date1.getFullYear() - date2.getFullYear()) / 1000);
519
+ default:
520
+ throw new Error(`Unknown unit: ${unit}`);
521
+ }
522
+ }
523
+ /**
524
+ * Calculate month difference between two dates
525
+ */
526
+ function monthDiff(from, to) {
527
+ const years = to.getFullYear() - from.getFullYear();
528
+ const months = to.getMonth() - from.getMonth();
529
+ const days = to.getDate() - from.getDate();
530
+ let diff = years * 12 + months;
531
+ // Adjust for day difference
532
+ if (days < 0) {
533
+ diff--;
534
+ }
535
+ return diff;
536
+ }
537
+ // ============================================================================
538
+ // Parsing Utilities
539
+ // ============================================================================
540
+ /**
541
+ * Parse an ISO 8601 duration string
542
+ */
543
+ function parseISODuration(duration) {
544
+ const pattern = /^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/;
545
+ const match = duration.match(pattern);
546
+ if (!match) {
547
+ throw new Error(`Invalid ISO 8601 duration: ${duration}`);
548
+ }
549
+ return {
550
+ years: match[1] ? parseInt(match[1], 10) : undefined,
551
+ months: match[2] ? parseInt(match[2], 10) : undefined,
552
+ weeks: match[3] ? parseInt(match[3], 10) : undefined,
553
+ days: match[4] ? parseInt(match[4], 10) : undefined,
554
+ hours: match[5] ? parseInt(match[5], 10) : undefined,
555
+ minutes: match[6] ? parseInt(match[6], 10) : undefined,
556
+ seconds: match[7] ? parseFloat(match[7]) : undefined,
557
+ };
558
+ }
559
+ /**
560
+ * Convert a duration to ISO 8601 format
561
+ */
562
+ function durationToISO(duration) {
563
+ var _a, _b;
564
+ let result = 'P';
565
+ if (duration.years)
566
+ result += `${duration.years}Y`;
567
+ if (duration.months)
568
+ result += `${duration.months}M`;
569
+ if (duration.weeks)
570
+ result += `${duration.weeks}W`;
571
+ if (duration.days)
572
+ result += `${duration.days}D`;
573
+ const hasTime = duration.hours ||
574
+ duration.minutes ||
575
+ duration.seconds ||
576
+ duration.milliseconds;
577
+ if (hasTime) {
578
+ result += 'T';
579
+ if (duration.hours)
580
+ result += `${duration.hours}H`;
581
+ if (duration.minutes)
582
+ result += `${duration.minutes}M`;
583
+ const seconds = ((_a = duration.seconds) !== null && _a !== void 0 ? _a : 0) + ((_b = duration.milliseconds) !== null && _b !== void 0 ? _b : 0) / 1000;
584
+ if (seconds)
585
+ result += `${seconds}S`;
586
+ }
587
+ return result === 'P' ? 'PT0S' : result;
588
+ }
589
+ // ============================================================================
590
+ // Comparison Utilities
591
+ // ============================================================================
592
+ /**
593
+ * Compare two dates at a specific granularity
594
+ */
595
+ function compareAtGranularity(date1, date2, unit) {
596
+ const d1 = startOf(date1, unit);
597
+ const d2 = startOf(date2, unit);
598
+ if (d1.getTime() < d2.getTime())
599
+ return -1;
600
+ if (d1.getTime() > d2.getTime())
601
+ return 1;
602
+ return 0;
603
+ }
604
+ /**
605
+ * Check if two dates are the same at a specific granularity
606
+ */
607
+ function isSameAt(date1, date2, unit) {
608
+ return compareAtGranularity(date1, date2, unit) === 0;
609
+ }
610
+ // ============================================================================
611
+ // Cloning Utilities
612
+ // ============================================================================
613
+ /**
614
+ * Create a deep clone of a date
615
+ */
616
+ function cloneDate(date) {
617
+ return new Date(date.getTime());
618
+ }
619
+ // ============================================================================
620
+ // Validation Utilities
621
+ // ============================================================================
622
+ /**
623
+ * Check if a date is valid
624
+ */
625
+ function isValidDate(date) {
626
+ return date instanceof Date && !isNaN(date.getTime());
627
+ }
628
+ /**
629
+ * Ensure a value is within bounds
630
+ */
631
+ function clamp(value, min, max) {
632
+ return Math.min(Math.max(value, min), max);
633
+ }
634
+ // ============================================================================
635
+ // Ordinal Utilities
636
+ // ============================================================================
637
+ /**
638
+ * Get ordinal suffix for a number (1st, 2nd, 3rd, etc.)
639
+ */
640
+ function ordinalSuffix(n) {
641
+ const s = ['th', 'st', 'nd', 'rd'];
642
+ const v = n % 100;
643
+ return n + (s[(v - 20) % 10] || s[v] || s[0]);
644
+ }
645
+ // ============================================================================
646
+ // Padding Utilities
647
+ // ============================================================================
648
+ /**
649
+ * Pad a number with leading zeros
650
+ */
651
+ function padStart(value, length, char = '0') {
652
+ const str = String(value);
653
+ if (str.length >= length)
654
+ return str;
655
+ return char.repeat(length - str.length) + str;
656
+ }
package/package.json CHANGED
@@ -1,12 +1,21 @@
1
1
  {
2
2
  "name": "chronos-ts",
3
- "version": "1.1.0",
4
- "description": "A comprehensive TypeScript package for handling time periods, intervals, and date-related operations.",
3
+ "version": "2.0.1",
4
+ "description": "A comprehensive TypeScript library for date and time manipulation, inspired by Carbon PHP. Features immutable API, intervals, periods, timezones, and i18n support.",
5
5
  "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
6
7
  "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
7
15
  "scripts": {
8
16
  "build": "tsc",
9
17
  "test": "jest",
18
+ "test:coverage": "jest --coverage",
10
19
  "format": "prettier --write 'src/**/*.{ts,js,json,md}'",
11
20
  "lint": "eslint 'src/**/*.{ts,js}'",
12
21
  "prepare": "npm run build",
@@ -33,7 +42,14 @@
33
42
  "time-period",
34
43
  "date-interval",
35
44
  "time-arithmetic",
36
- "date-arithmetic"
45
+ "date-arithmetic",
46
+ "carbon",
47
+ "moment",
48
+ "dayjs",
49
+ "timezone",
50
+ "i18n",
51
+ "localization",
52
+ "immutable"
37
53
  ],
38
54
  "files": [
39
55
  "dist/**",