@bereasoftware/time-guard 2.6.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/README.en.md +232 -0
  2. package/README.md +259 -4
  3. package/dist/{types/adapters → adapters}/temporal.adapter.d.ts +4 -9
  4. package/dist/angular/index.cjs +148 -0
  5. package/dist/angular/index.d.ts +2 -0
  6. package/dist/angular/index.es.js +143 -0
  7. package/dist/angular.d.ts +59 -0
  8. package/dist/calendars/index.cjs +357 -2
  9. package/dist/calendars/index.es.js +99 -68
  10. package/dist/chunk-Ddh6569R.cjs +36 -0
  11. package/dist/core-BAd7GYfw.js +1809 -0
  12. package/dist/core-CafqOI7W.cjs +1892 -0
  13. package/dist/core.d.ts +224 -0
  14. package/dist/index.d.ts +9 -0
  15. package/dist/locales/african.locale.d.ts +7 -0
  16. package/dist/locales/index.cjs +7 -2
  17. package/dist/{types/locales → locales}/index.d.ts +2 -2
  18. package/dist/locales/index.es.js +3 -2797
  19. package/dist/locales/south-american.locale.d.ts +7 -0
  20. package/dist/locales-C2-lOmC8.cjs +3537 -0
  21. package/dist/locales-CcuSu4P1.js +3514 -0
  22. package/dist/native/index.cjs +48 -0
  23. package/dist/native/index.d.ts +2 -0
  24. package/dist/native/index.es.js +18 -0
  25. package/dist/native.d.ts +9 -0
  26. package/dist/plugins/advanced-format.cjs +105 -2
  27. package/dist/plugins/advanced-format.es.js +63 -45
  28. package/dist/plugins/duration.cjs +258 -2
  29. package/dist/plugins/duration.es.js +165 -61
  30. package/dist/plugins/index.d.ts +10 -0
  31. package/dist/plugins/relative-time.cjs +166 -2
  32. package/dist/plugins/relative-time.es.js +74 -37
  33. package/dist/qwik/index.cjs +104 -0
  34. package/dist/qwik/index.d.ts +2 -0
  35. package/dist/qwik/index.es.js +100 -0
  36. package/dist/qwik.d.ts +32 -0
  37. package/dist/react/index.cjs +112 -0
  38. package/dist/react/index.d.ts +2 -0
  39. package/dist/react/index.es.js +103 -0
  40. package/dist/react.d.ts +46 -0
  41. package/dist/solid/index.cjs +127 -0
  42. package/dist/solid/index.d.ts +2 -0
  43. package/dist/solid/index.es.js +122 -0
  44. package/dist/solid.d.ts +53 -0
  45. package/dist/svelte/index.cjs +398 -0
  46. package/dist/svelte/index.d.ts +2 -0
  47. package/dist/svelte/index.es.js +393 -0
  48. package/dist/svelte.d.ts +88 -0
  49. package/dist/time-guard.cjs +7359 -4
  50. package/dist/time-guard.d.ts +2 -0
  51. package/dist/time-guard.es.js +3625 -8073
  52. package/dist/time-guard.iife.js +13549 -4
  53. package/dist/time-guard.umd.js +13550 -4
  54. package/dist/types/index.d.ts +651 -128
  55. package/dist/vue/index.cjs +143 -0
  56. package/dist/vue/index.d.ts +2 -0
  57. package/dist/vue/index.es.js +137 -0
  58. package/dist/vue.d.ts +35 -0
  59. package/package.json +111 -17
  60. package/dist/calendars/index.cjs.map +0 -1
  61. package/dist/calendars/index.es.js.map +0 -1
  62. package/dist/locales/index.cjs.map +0 -1
  63. package/dist/locales/index.es.js.map +0 -1
  64. package/dist/plugins/advanced-format.cjs.map +0 -1
  65. package/dist/plugins/advanced-format.es.js.map +0 -1
  66. package/dist/plugins/duration.cjs.map +0 -1
  67. package/dist/plugins/duration.es.js.map +0 -1
  68. package/dist/plugins/relative-time.cjs.map +0 -1
  69. package/dist/plugins/relative-time.es.js.map +0 -1
  70. package/dist/time-guard.cjs.map +0 -1
  71. package/dist/time-guard.es.js.map +0 -1
  72. package/dist/time-guard.iife.js.map +0 -1
  73. package/dist/time-guard.umd.js.map +0 -1
  74. package/dist/types/plugins/index.d.ts +0 -10
  75. package/dist/types/types/index.d.ts +0 -586
  76. /package/dist/{types/calendars → calendars}/calendar.manager.d.ts +0 -0
  77. /package/dist/{types/calendars → calendars}/index.d.ts +0 -0
  78. /package/dist/{types/formatters → formatters}/date.formatter.d.ts +0 -0
  79. /package/dist/{types/locales → locales}/additional.locale.d.ts +0 -0
  80. /package/dist/{types/locales → locales}/asian.locale.d.ts +0 -0
  81. /package/dist/{types/locales → locales}/english.locale.d.ts +0 -0
  82. /package/dist/{types/locales → locales}/european.locale.d.ts +0 -0
  83. /package/dist/{types/locales → locales}/locale.manager.d.ts +0 -0
  84. /package/dist/{types/locales → locales}/middle-eastern.locale.d.ts +0 -0
  85. /package/dist/{types/locales → locales}/nordic.locale.d.ts +0 -0
  86. /package/dist/{types/locales → locales}/romance.locale.d.ts +0 -0
  87. /package/dist/{types/locales → locales}/slavic.locale.d.ts +0 -0
  88. /package/dist/{types/locales → locales}/spanish.locale.d.ts +0 -0
  89. /package/dist/{types/plugins → plugins}/advanced-format/index.d.ts +0 -0
  90. /package/dist/{types/plugins → plugins}/advanced-format.d.ts +0 -0
  91. /package/dist/{types/plugins → plugins}/duration/index.d.ts +0 -0
  92. /package/dist/{types/plugins → plugins}/duration/types.d.ts +0 -0
  93. /package/dist/{types/plugins → plugins}/duration.d.ts +0 -0
  94. /package/dist/{types/plugins → plugins}/manager.d.ts +0 -0
  95. /package/dist/{types/plugins → plugins}/relative-time/index.d.ts +0 -0
  96. /package/dist/{types/plugins → plugins}/relative-time/types.d.ts +0 -0
  97. /package/dist/{types/plugins → plugins}/relative-time.d.ts +0 -0
  98. /package/dist/{types/utils → utils}/duration-locale.d.ts +0 -0
@@ -0,0 +1,1892 @@
1
+ /*! time-guard v2.7.0 | (c) 2026 Berea-Soft | MIT License | https://github.com/Berea-Soft/time-guard */
2
+ //#region src/locales/locale.manager.ts
3
+ /**
4
+ * English locale data
5
+ */
6
+ var EN_LOCALE = {
7
+ name: "en",
8
+ months: [
9
+ "January",
10
+ "February",
11
+ "March",
12
+ "April",
13
+ "May",
14
+ "June",
15
+ "July",
16
+ "August",
17
+ "September",
18
+ "October",
19
+ "November",
20
+ "December"
21
+ ],
22
+ monthsShort: [
23
+ "Jan",
24
+ "Feb",
25
+ "Mar",
26
+ "Apr",
27
+ "May",
28
+ "Jun",
29
+ "Jul",
30
+ "Aug",
31
+ "Sep",
32
+ "Oct",
33
+ "Nov",
34
+ "Dec"
35
+ ],
36
+ weekdays: [
37
+ "Sunday",
38
+ "Monday",
39
+ "Tuesday",
40
+ "Wednesday",
41
+ "Thursday",
42
+ "Friday",
43
+ "Saturday"
44
+ ],
45
+ weekdaysShort: [
46
+ "Sun",
47
+ "Mon",
48
+ "Tue",
49
+ "Wed",
50
+ "Thu",
51
+ "Fri",
52
+ "Sat"
53
+ ],
54
+ weekdaysMin: [
55
+ "Su",
56
+ "Mo",
57
+ "Tu",
58
+ "We",
59
+ "Th",
60
+ "Fr",
61
+ "Sa"
62
+ ],
63
+ meridiem: {
64
+ am: "AM",
65
+ pm: "PM"
66
+ },
67
+ formats: {
68
+ iso: "YYYY-MM-DDTHH:mm:ss.SSSZ",
69
+ date: "YYYY-MM-DD",
70
+ time: "HH:mm:ss",
71
+ datetime: "YYYY-MM-DD HH:mm:ss",
72
+ rfc2822: "ddd, DD MMM YYYY HH:mm:ss Z"
73
+ }
74
+ };
75
+ /**
76
+ * Spanish locale data (sample for i18n support)
77
+ */
78
+ var ES_LOCALE = {
79
+ name: "es",
80
+ months: [
81
+ "Enero",
82
+ "Febrero",
83
+ "Marzo",
84
+ "Abril",
85
+ "Mayo",
86
+ "Junio",
87
+ "Julio",
88
+ "Agosto",
89
+ "Septiembre",
90
+ "Octubre",
91
+ "Noviembre",
92
+ "Diciembre"
93
+ ],
94
+ monthsShort: [
95
+ "Ene",
96
+ "Feb",
97
+ "Mar",
98
+ "Abr",
99
+ "May",
100
+ "Jun",
101
+ "Jul",
102
+ "Ago",
103
+ "Sep",
104
+ "Oct",
105
+ "Nov",
106
+ "Dic"
107
+ ],
108
+ weekdays: [
109
+ "Domingo",
110
+ "Lunes",
111
+ "Martes",
112
+ "Miércoles",
113
+ "Jueves",
114
+ "Viernes",
115
+ "Sábado"
116
+ ],
117
+ weekdaysShort: [
118
+ "Dom",
119
+ "Lun",
120
+ "Mar",
121
+ "Mié",
122
+ "Jue",
123
+ "Vie",
124
+ "Sáb"
125
+ ],
126
+ weekdaysMin: [
127
+ "Do",
128
+ "Lu",
129
+ "Ma",
130
+ "Mi",
131
+ "Ju",
132
+ "Vi",
133
+ "Sa"
134
+ ],
135
+ meridiem: {
136
+ am: "AM",
137
+ pm: "PM"
138
+ },
139
+ formats: {
140
+ iso: "YYYY-MM-DDTHH:mm:ss.SSSZ",
141
+ date: "DD/MM/YYYY",
142
+ time: "HH:mm:ss",
143
+ datetime: "DD/MM/YYYY HH:mm:ss",
144
+ rfc2822: "ddd, DD MMM YYYY HH:mm:ss Z"
145
+ }
146
+ };
147
+ /**
148
+ * Locale Manager - implements ILocaleManager
149
+ */
150
+ var LocaleManager = class LocaleManager {
151
+ static instance;
152
+ locales = /* @__PURE__ */ new Map();
153
+ currentLocale = "en";
154
+ /**
155
+ * Singleton pattern
156
+ */
157
+ static getInstance() {
158
+ if (!LocaleManager.instance) LocaleManager.instance = new LocaleManager();
159
+ return LocaleManager.instance;
160
+ }
161
+ constructor() {
162
+ this.locales.set("en", EN_LOCALE);
163
+ this.locales.set("es", ES_LOCALE);
164
+ }
165
+ /**
166
+ * Set or register a locale
167
+ */
168
+ setLocale(locale, data) {
169
+ if (data) this.locales.set(locale.toLowerCase(), data);
170
+ this.currentLocale = locale.toLowerCase();
171
+ }
172
+ /**
173
+ * Get locale information
174
+ */
175
+ getLocale(locale) {
176
+ const target = (locale || this.currentLocale).toLowerCase();
177
+ const result = this.locales.get(target);
178
+ if (!result) return this.locales.get("en") || EN_LOCALE;
179
+ return result;
180
+ }
181
+ /**
182
+ * List all registered locales
183
+ */
184
+ listLocales() {
185
+ return Array.from(this.locales.keys());
186
+ }
187
+ /**
188
+ * Get current locale
189
+ */
190
+ getCurrentLocale() {
191
+ return this.currentLocale;
192
+ }
193
+ /**
194
+ * Load multiple locales
195
+ */
196
+ loadLocales(locales) {
197
+ Object.entries(locales).forEach(([name, data]) => {
198
+ this.locales.set(name.toLowerCase(), data);
199
+ });
200
+ }
201
+ };
202
+ //#endregion
203
+ //#region src/adapters/temporal.adapter.ts
204
+ var temporalCache = null;
205
+ /**
206
+ * Get Temporal from globalThis or imported module
207
+ */
208
+ function useTemporal() {
209
+ if (temporalCache) return temporalCache;
210
+ const TemporalLoaded = globalThis.Temporal;
211
+ if (!TemporalLoaded) throw new Error("Temporal API not loaded. Make sure @js-temporal/polyfill is imported in your app.");
212
+ temporalCache = TemporalLoaded;
213
+ return TemporalLoaded;
214
+ }
215
+ /**
216
+ * Adapter for Temporal date/time operations
217
+ */
218
+ var TemporalAdapter = class {
219
+ /**
220
+ * Parse various input formats to Temporal.PlainDateTime
221
+ */
222
+ static parseToPlainDateTime(input) {
223
+ const Temporal = useTemporal();
224
+ if (this.isPlainDateTime(input)) return input;
225
+ if (this.isZonedDateTime(input)) return input.toPlainDateTime();
226
+ if (this.isPlainDate(input)) return input.toPlainDateTime({
227
+ hour: 0,
228
+ minute: 0,
229
+ second: 0,
230
+ millisecond: 0
231
+ });
232
+ if (this.isPlainTime(input)) return Temporal.Now.plainDateTimeISO().with(input);
233
+ if (input !== null && typeof input === "object" && "getTime" in input && typeof input.getTime === "function") return this.fromDate(input);
234
+ if (typeof input === "number") return this.fromUnix(input);
235
+ if (typeof input === "string") return this.parseISOString(input);
236
+ if (typeof input === "object" && input !== null) return this.fromObject(input);
237
+ return Temporal.Now.plainDateTimeISO();
238
+ }
239
+ /**
240
+ * Convert JavaScript Date to Temporal.PlainDateTime
241
+ */
242
+ static fromDate(date) {
243
+ const Temporal = useTemporal();
244
+ const [datePart, timePart] = date.toISOString().split("T");
245
+ return Temporal.PlainDateTime.from(datePart + "T" + timePart.slice(0, -1));
246
+ }
247
+ /**
248
+ * Convert Unix timestamp (milliseconds) to Temporal.PlainDateTime
249
+ */
250
+ static fromUnix(timestamp) {
251
+ return this.fromDate(new Date(timestamp));
252
+ }
253
+ /**
254
+ * Parse ISO string to Temporal.PlainDateTime
255
+ */
256
+ static parseISOString(iso) {
257
+ const Temporal = useTemporal();
258
+ try {
259
+ if (iso.includes("T") || / \d{2}:\d{2}/.test(iso)) {
260
+ const normalized = iso.replace(" ", "T");
261
+ return Temporal.PlainDateTime.from(normalized);
262
+ }
263
+ return Temporal.PlainDate.from(iso).toPlainDateTime({ hour: 0 });
264
+ } catch {
265
+ return Temporal.Now.plainDateTimeISO();
266
+ }
267
+ }
268
+ /**
269
+ * Create from object with date components
270
+ */
271
+ static fromObject(obj) {
272
+ const Temporal = useTemporal();
273
+ const year = obj.year || Temporal.Now.plainDateISO().year;
274
+ const month = obj.month || 1;
275
+ const day = obj.day || 1;
276
+ const hour = obj.hour || 0;
277
+ const minute = obj.minute || 0;
278
+ const second = obj.second || 0;
279
+ const millisecond = obj.millisecond || 0;
280
+ return Temporal.PlainDateTime.from({
281
+ year: this.toFiniteInteger(year),
282
+ month: this.toFiniteInteger(month),
283
+ day: this.toFiniteInteger(day),
284
+ hour: this.toFiniteInteger(hour),
285
+ minute: this.toFiniteInteger(minute),
286
+ second: this.toFiniteInteger(second),
287
+ millisecond: this.toFiniteInteger(millisecond)
288
+ });
289
+ }
290
+ /**
291
+ * Convert Temporal.PlainDateTime to JavaScript Date
292
+ */
293
+ static toDate(temporal) {
294
+ const plainDT = this.toPlainDateTime(temporal);
295
+ return new Date(plainDT.toString());
296
+ }
297
+ /**
298
+ * Convert to Unix timestamp (milliseconds)
299
+ */
300
+ static toUnix(temporal) {
301
+ const plainDT = this.toPlainDateTime(temporal);
302
+ return Date.UTC(plainDT.year, plainDT.month - 1, plainDT.day, plainDT.hour, plainDT.minute, plainDT.second, plainDT.millisecond);
303
+ }
304
+ /**
305
+ * Convert to ISO string
306
+ */
307
+ static toISOString(temporal) {
308
+ return this.toPlainDateTime(temporal).toString() + "Z";
309
+ }
310
+ /**
311
+ * Ensure we have a PlainDateTime
312
+ */
313
+ static toPlainDateTime(temporal) {
314
+ if (this.isPlainDateTime(temporal)) return temporal;
315
+ return temporal.toPlainDateTime();
316
+ }
317
+ /**
318
+ * Type guards
319
+ */
320
+ static isPlainDateTime(obj) {
321
+ return obj !== null && typeof obj === "object" && "year" in obj && "month" in obj && "day" in obj && "hour" in obj;
322
+ }
323
+ static isZonedDateTime(obj) {
324
+ return obj !== null && typeof obj === "object" && "timeZone" in obj;
325
+ }
326
+ static isPlainDate(obj) {
327
+ return obj !== null && typeof obj === "object" && "year" in obj && "month" in obj && "day" in obj && !("hour" in obj) && "toPlainDateTime" in obj;
328
+ }
329
+ static isPlainTime(obj) {
330
+ return obj !== null && typeof obj === "object" && "hour" in obj && !("year" in obj);
331
+ }
332
+ static toFiniteInteger(value) {
333
+ const num = Number(value);
334
+ if (!Number.isFinite(num)) throw new Error(`Temporal error: Expected finite integer, got ${value}`);
335
+ return Math.trunc(num);
336
+ }
337
+ /**
338
+ * Validate that a PlainDateTime has finite integer components
339
+ */
340
+ static validatePlainDateTime(dt) {
341
+ for (const field of [
342
+ "year",
343
+ "month",
344
+ "day",
345
+ "hour",
346
+ "minute",
347
+ "second",
348
+ "millisecond"
349
+ ]) {
350
+ const value = dt[field];
351
+ if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value)) {
352
+ if (typeof console !== "undefined" && typeof console.error === "function") console.error("TemporalAdapter.validatePlainDateTime: campo inválido", field, value, dt);
353
+ throw new Error(`Temporal error: Expected finite integer for ${field}, got ${value}`);
354
+ }
355
+ }
356
+ }
357
+ /**
358
+ * Get current time as PlainDateTime
359
+ */
360
+ static now() {
361
+ return useTemporal().Now.plainDateTimeISO();
362
+ }
363
+ /**
364
+ * Get current time as ZonedDateTime with timezone
365
+ */
366
+ static nowInTimezone(timezone) {
367
+ return useTemporal().Now.zonedDateTimeISO(timezone);
368
+ }
369
+ /**
370
+ * Compare two Temporal.PlainDateTime objects
371
+ * Returns: -1 if dt1 < dt2, 0 if equal, 1 if dt1 > dt2
372
+ * Uses ISO string comparison as fallback for polyfills that don't have Temporal.PlainDateTime.compare
373
+ */
374
+ static compare(dt1, dt2) {
375
+ const Temporal = useTemporal();
376
+ this.validatePlainDateTime(dt1);
377
+ this.validatePlainDateTime(dt2);
378
+ if (Temporal.PlainDateTime && typeof Temporal.PlainDateTime.compare === "function") return Temporal.PlainDateTime.compare(dt1, dt2);
379
+ const iso1 = dt1.toString();
380
+ const iso2 = dt2.toString();
381
+ if (iso1 < iso2) return -1;
382
+ if (iso1 > iso2) return 1;
383
+ return 0;
384
+ }
385
+ };
386
+ //#endregion
387
+ //#region src/formatters/date.formatter.ts
388
+ /**
389
+ * Date Formatter implementation
390
+ */
391
+ var DateFormatter = class {
392
+ localeManager;
393
+ constructor() {
394
+ this.localeManager = LocaleManager.getInstance();
395
+ }
396
+ /**
397
+ * Format date with pattern and locale
398
+ */
399
+ format(date, pattern, locale) {
400
+ const localeData = this.localeManager.getLocale(locale);
401
+ const escapedParts = [];
402
+ let escapedPattern = pattern.replace(/\[([^\]]+)\]/g, (_match, content) => {
403
+ escapedParts.push(content);
404
+ return `~${escapedParts.length - 1}~`;
405
+ });
406
+ escapedPattern = escapedPattern.replace(/"([^"]*)"/g, (_match, content) => {
407
+ escapedParts.push(content);
408
+ return `~${escapedParts.length - 1}~`;
409
+ });
410
+ let result = escapedPattern.replace(/Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|SSS/g, (match) => {
411
+ switch (match) {
412
+ case "YYYY": return String(date.year).padStart(4, "0");
413
+ case "YY": return String(date.year).slice(-2);
414
+ case "Y": return String(date.year);
415
+ case "MMMM": return localeData.months[date.month - 1];
416
+ case "MMM": return localeData.monthsShort[date.month - 1];
417
+ case "MM": return String(date.month).padStart(2, "0");
418
+ case "M": return String(date.month);
419
+ case "DD": return String(date.day).padStart(2, "0");
420
+ case "D": return String(date.day);
421
+ case "dddd": return localeData.weekdays[date.dayOfWeek % 7];
422
+ case "ddd": return localeData.weekdaysShort[date.dayOfWeek % 7];
423
+ case "dd": return localeData.weekdaysMin[date.dayOfWeek % 7];
424
+ case "d": return String(date.dayOfWeek);
425
+ case "HH": return String(date.hour).padStart(2, "0");
426
+ case "H": return String(date.hour);
427
+ case "hh": return String(date.hour % 12 || 12).padStart(2, "0");
428
+ case "h": return String(date.hour % 12 || 12);
429
+ case "mm": return String(date.minute).padStart(2, "0");
430
+ case "m": return String(date.minute);
431
+ case "ss": return String(date.second).padStart(2, "0");
432
+ case "s": return String(date.second);
433
+ case "SSS": return String(date.millisecond).padStart(3, "0");
434
+ case "a":
435
+ case "A":
436
+ const meridiem = localeData.meridiem || {
437
+ am: "am",
438
+ pm: "pm"
439
+ };
440
+ const value = date.hour >= 12 ? meridiem.pm : meridiem.am;
441
+ return match === "a" ? value.toLowerCase() : value.toUpperCase();
442
+ default: return match;
443
+ }
444
+ });
445
+ escapedParts.forEach((content, index) => {
446
+ result = result.replace(`~${index}~`, content);
447
+ });
448
+ return result;
449
+ }
450
+ /**
451
+ * Get format pattern for preset
452
+ */
453
+ getPreset(preset) {
454
+ const presets = {
455
+ iso: "YYYY-MM-DDTHH:mm:ss.SSSZ",
456
+ date: "YYYY-MM-DD",
457
+ time: "HH:mm:ss",
458
+ datetime: "YYYY-MM-DD HH:mm:ss",
459
+ rfc2822: "ddd, DD MMM YYYY HH:mm:ss Z",
460
+ rfc3339: "YYYY-MM-DDTHH:mm:ssZ",
461
+ utc: "YYYY-MM-DDTHH:mm:ss[Z]"
462
+ };
463
+ return presets[preset] || presets.iso;
464
+ }
465
+ /**
466
+ * Format with preset
467
+ */
468
+ formatPreset(date, preset, locale) {
469
+ const pattern = this.getPreset(preset);
470
+ return this.format(date, pattern, locale);
471
+ }
472
+ };
473
+ //#endregion
474
+ //#region src/utils/duration-locale.ts
475
+ /**
476
+ * Shared locale utilities for duration formatting
477
+ * Extracted from DiffResult and DurationResult to avoid duplication
478
+ */
479
+ /**
480
+ * Duration unit labels for different locales
481
+ * Format: [singular, plural]
482
+ */
483
+ var DURATION_UNIT_LABELS = {
484
+ en: {
485
+ year: ["year", "years"],
486
+ month: ["month", "months"],
487
+ week: ["week", "weeks"],
488
+ day: ["day", "days"],
489
+ hour: ["hour", "hours"],
490
+ minute: ["minute", "minutes"],
491
+ second: ["second", "seconds"],
492
+ millisecond: ["millisecond", "milliseconds"]
493
+ },
494
+ es: {
495
+ year: ["año", "años"],
496
+ month: ["mes", "meses"],
497
+ week: ["semana", "semanas"],
498
+ day: ["día", "días"],
499
+ hour: ["hora", "horas"],
500
+ minute: ["minuto", "minutos"],
501
+ second: ["segundo", "segundos"],
502
+ millisecond: ["milisegundo", "milisegundos"]
503
+ },
504
+ fr: {
505
+ year: ["année", "années"],
506
+ month: ["mois", "mois"],
507
+ week: ["semaine", "semaines"],
508
+ day: ["jour", "jours"],
509
+ hour: ["heure", "heures"],
510
+ minute: ["minute", "minutes"],
511
+ second: ["seconde", "secondes"],
512
+ millisecond: ["milliseconde", "millisecondes"]
513
+ }
514
+ };
515
+ /**
516
+ * Conjunction words for joining duration parts
517
+ */
518
+ var CONJUNCTION_LABELS = {
519
+ en: "and",
520
+ es: "y",
521
+ fr: "et",
522
+ de: "und",
523
+ it: "e",
524
+ pt: "e"
525
+ };
526
+ /**
527
+ * Get duration unit label for a specific locale
528
+ */
529
+ function getDurationUnitLabel(unit, locale, value) {
530
+ return ((DURATION_UNIT_LABELS[locale] || DURATION_UNIT_LABELS.en)[unit] || [unit, unit + "s"])[value === 1 ? 0 : 1];
531
+ }
532
+ /**
533
+ * Get conjunction word for a specific locale
534
+ */
535
+ function getConjunctionLabel(locale) {
536
+ return CONJUNCTION_LABELS[locale] || "and";
537
+ }
538
+ /**
539
+ * Join formatted duration parts with locale-appropriate conjunctions
540
+ */
541
+ function joinDurationParts(parts, locale) {
542
+ if (parts.length === 0) return "";
543
+ if (parts.length === 1) return parts[0];
544
+ const conjunction = getConjunctionLabel(locale);
545
+ if (parts.length === 2) return `${parts[0]} ${conjunction} ${parts[1]}`;
546
+ return parts.slice(0, -1).join(", ") + ` ${conjunction} ${parts[parts.length - 1]}`;
547
+ }
548
+ /**
549
+ * Format a zero duration for display
550
+ */
551
+ function formatZeroDuration(locale) {
552
+ return {
553
+ en: "0 seconds",
554
+ es: "0 segundos",
555
+ fr: "0 secondes"
556
+ }[locale] || "0 seconds";
557
+ }
558
+ //#endregion
559
+ //#region src/calendars/calendar.manager.ts
560
+ /**
561
+ * Gregorian Calendar System (ISO 8601 default)
562
+ */
563
+ var GregorianCalendar = class {
564
+ id = "gregory";
565
+ name = "Gregorian Calendar";
566
+ locale = "en";
567
+ monthNames = [
568
+ "January",
569
+ "February",
570
+ "March",
571
+ "April",
572
+ "May",
573
+ "June",
574
+ "July",
575
+ "August",
576
+ "September",
577
+ "October",
578
+ "November",
579
+ "December"
580
+ ];
581
+ monthNamesShort = [
582
+ "Jan",
583
+ "Feb",
584
+ "Mar",
585
+ "Apr",
586
+ "May",
587
+ "Jun",
588
+ "Jul",
589
+ "Aug",
590
+ "Sep",
591
+ "Oct",
592
+ "Nov",
593
+ "Dec"
594
+ ];
595
+ weekdayNames = [
596
+ "Sunday",
597
+ "Monday",
598
+ "Tuesday",
599
+ "Wednesday",
600
+ "Thursday",
601
+ "Friday",
602
+ "Saturday"
603
+ ];
604
+ weekdayNamesShort = [
605
+ "Sun",
606
+ "Mon",
607
+ "Tue",
608
+ "Wed",
609
+ "Thu",
610
+ "Fri",
611
+ "Sat"
612
+ ];
613
+ getMonthName(month, short = false) {
614
+ return (short ? this.monthNamesShort : this.monthNames)[Math.max(0, Math.min(11, month - 1))];
615
+ }
616
+ getWeekdayName(day, short = false) {
617
+ return (short ? this.weekdayNamesShort : this.weekdayNames)[Math.max(0, Math.min(6, day - 1))];
618
+ }
619
+ isLeapYear(year) {
620
+ return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
621
+ }
622
+ daysInMonth(year, month) {
623
+ const daysPerMonth = [
624
+ 31,
625
+ 28,
626
+ 31,
627
+ 30,
628
+ 31,
629
+ 30,
630
+ 31,
631
+ 31,
632
+ 30,
633
+ 31,
634
+ 30,
635
+ 31
636
+ ];
637
+ if (month === 2 && this.isLeapYear(year)) return 29;
638
+ return daysPerMonth[Math.max(0, Math.min(11, month - 1))];
639
+ }
640
+ daysInYear(year) {
641
+ return this.isLeapYear(year) ? 366 : 365;
642
+ }
643
+ };
644
+ /**
645
+ * Calendar Manager - Singleton for managing calendar systems
646
+ */
647
+ var CalendarManager = class CalendarManager {
648
+ static instance;
649
+ calendars = /* @__PURE__ */ new Map();
650
+ defaultCalendar = "gregory";
651
+ constructor() {
652
+ this.register(new GregorianCalendar());
653
+ }
654
+ /**
655
+ * Get singleton instance
656
+ */
657
+ static getInstance() {
658
+ if (!CalendarManager.instance) CalendarManager.instance = new CalendarManager();
659
+ return CalendarManager.instance;
660
+ }
661
+ /**
662
+ * Register a new calendar system
663
+ */
664
+ register(calendar) {
665
+ this.calendars.set(calendar.id, calendar);
666
+ }
667
+ /**
668
+ * Get calendar by ID
669
+ */
670
+ get(id) {
671
+ return this.calendars.get(id);
672
+ }
673
+ /**
674
+ * List all available calendars
675
+ */
676
+ list() {
677
+ return Array.from(this.calendars.keys());
678
+ }
679
+ /**
680
+ * Set default calendar
681
+ */
682
+ setDefault(id) {
683
+ if (this.calendars.has(id)) this.defaultCalendar = id;
684
+ }
685
+ /**
686
+ * Get default calendar
687
+ */
688
+ getDefault() {
689
+ const calendar = this.calendars.get(this.defaultCalendar);
690
+ if (!calendar) throw new Error(`Default calendar '${this.defaultCalendar}' not found`);
691
+ return calendar;
692
+ }
693
+ };
694
+ var calendarManager = CalendarManager.getInstance();
695
+ //#endregion
696
+ //#region src/plugins/manager.ts
697
+ /**
698
+ * Plugin Manager - handles plugin registration and initialization
699
+ * Uses Singleton pattern to ensure single instance across application
700
+ */
701
+ var PluginManager = class PluginManager {
702
+ static instance;
703
+ plugins = /* @__PURE__ */ new Map();
704
+ /**
705
+ * Get singleton instance
706
+ */
707
+ static getInstance() {
708
+ if (!PluginManager.instance) PluginManager.instance = new PluginManager();
709
+ return PluginManager.instance;
710
+ }
711
+ /**
712
+ * Register a plugin
713
+ * @param plugin - The plugin to register
714
+ * @param timeGuardClass - Reference to TimeGuard class
715
+ * @param config - Optional plugin configuration
716
+ */
717
+ static use(plugin, timeGuardClass, config) {
718
+ PluginManager.getInstance().register(plugin, timeGuardClass, config);
719
+ }
720
+ /**
721
+ * Register multiple plugins at once
722
+ * @param plugins - Array of plugins to register
723
+ * @param timeGuardClass - Reference to TimeGuard class
724
+ * @param config - Optional plugin configuration
725
+ */
726
+ static useMultiple(plugins, timeGuardClass, config) {
727
+ const manager = PluginManager.getInstance();
728
+ plugins.forEach((plugin) => manager.register(plugin, timeGuardClass, config));
729
+ }
730
+ /**
731
+ * Get registered plugin by name
732
+ * @param name - Plugin name
733
+ * @returns Plugin instance or undefined
734
+ */
735
+ static getPlugin(name) {
736
+ return PluginManager.getInstance().plugins.get(name);
737
+ }
738
+ /**
739
+ * Check if plugin is registered
740
+ * @param name - Plugin name
741
+ * @returns True if plugin is registered
742
+ */
743
+ static hasPlugin(name) {
744
+ return PluginManager.getInstance().plugins.has(name);
745
+ }
746
+ /**
747
+ * Get all registered plugins
748
+ * @returns Array of registered plugin names
749
+ */
750
+ static listPlugins() {
751
+ const manager = PluginManager.getInstance();
752
+ return Array.from(manager.plugins.keys());
753
+ }
754
+ /**
755
+ * Unregister a plugin
756
+ * @param name - Plugin name
757
+ */
758
+ static unuse(name) {
759
+ return PluginManager.getInstance().plugins.delete(name);
760
+ }
761
+ /**
762
+ * Clear all plugins
763
+ */
764
+ static clear() {
765
+ PluginManager.getInstance().plugins.clear();
766
+ }
767
+ /**
768
+ * Internal register method
769
+ */
770
+ register(plugin, timeGuardClass, config) {
771
+ if (this.plugins.has(plugin.name)) {
772
+ console.warn(`Plugin "${plugin.name}" is already registered. Skipping...`);
773
+ return;
774
+ }
775
+ try {
776
+ plugin.install(timeGuardClass, config);
777
+ this.plugins.set(plugin.name, plugin);
778
+ if (process.env.NODE_ENV !== "production") console.warn(`Plugin "${plugin.name}" v${plugin.version} registered successfully`);
779
+ } catch (error) {
780
+ console.error(`Failed to register plugin "${plugin.name}":`, error);
781
+ throw new Error(`Failed to register plugin "${plugin.name}": ${error instanceof Error ? error.message : String(error)}`);
782
+ }
783
+ }
784
+ };
785
+ //#endregion
786
+ //#region src/core.ts
787
+ /**
788
+ * TimeGuard - Modern date/time library using Temporal API
789
+ * Core Implementation (zero-dependency, polyfill-erased type-space)
790
+ *
791
+ * @author Berea-Soft
792
+ * @license MIT
793
+ */
794
+ var MS_PER_SECOND = 1e3;
795
+ var MS_PER_MINUTE = MS_PER_SECOND * 60;
796
+ var MS_PER_HOUR = MS_PER_MINUTE * 60;
797
+ var MS_PER_DAY = MS_PER_HOUR * 24;
798
+ var MS_PER_WEEK = MS_PER_DAY * 7;
799
+ var DAYS_PER_YEAR = 365.25;
800
+ var MS_PER_MONTH = DAYS_PER_YEAR / 12 * MS_PER_DAY;
801
+ var MS_PER_YEAR = DAYS_PER_YEAR * MS_PER_DAY;
802
+ var ZERO_DIFF_DAYS = " days";
803
+ /**
804
+ * Calculate total milliseconds from duration parts using hoisted constants
805
+ */
806
+ function calculateTotalMs(duration) {
807
+ return (duration.years || 0) * MS_PER_YEAR + (duration.months || 0) * MS_PER_MONTH + (duration.weeks || 0) * MS_PER_WEEK + (duration.days || 0) * MS_PER_DAY + (duration.hours || 0) * MS_PER_HOUR + (duration.minutes || 0) * MS_PER_MINUTE + (duration.seconds || 0) * MS_PER_SECOND + (duration.milliseconds || 0);
808
+ }
809
+ /**
810
+ * Diff result object that allows chaining with .as()
811
+ *
812
+ * Supports two modes:
813
+ * - 'exact': Returns precise time differences
814
+ * - 'calendar': Returns calendar-aware breakdown
815
+ */
816
+ var DiffResult = class {
817
+ _value;
818
+ _tg1;
819
+ _tg2;
820
+ _mode;
821
+ _breakdownData;
822
+ _locale;
823
+ constructor(value, tg1, tg2, mode = "exact", breakdownData, locale) {
824
+ this._value = value;
825
+ this._tg1 = tg1;
826
+ this._tg2 = tg2;
827
+ this._mode = mode;
828
+ this._breakdownData = breakdownData || null;
829
+ this._locale = locale || "en";
830
+ }
831
+ as(unit) {
832
+ return this._tg1.diff(this._tg2, unit);
833
+ }
834
+ breakdown() {
835
+ return this._breakdownData;
836
+ }
837
+ format(locale) {
838
+ const l = locale || this._locale;
839
+ if (!this._breakdownData) return `${Math.abs(this._tg1.diff(this._tg2, "day"))}${ZERO_DIFF_DAYS}`;
840
+ const parts = [];
841
+ const bd = this._breakdownData;
842
+ if (bd.years !== 0) parts.push(`${bd.years} ${getDurationUnitLabel("year", l, bd.years)}`);
843
+ if (bd.months !== 0) parts.push(`${bd.months} ${getDurationUnitLabel("month", l, bd.months)}`);
844
+ if (bd.weeks !== 0) parts.push(`${bd.weeks} ${getDurationUnitLabel("week", l, bd.weeks)}`);
845
+ if (bd.days !== 0) parts.push(`${bd.days} ${getDurationUnitLabel("day", l, bd.days)}`);
846
+ if (bd.hours !== 0) parts.push(`${bd.hours} ${getDurationUnitLabel("hour", l, bd.hours)}`);
847
+ if (bd.minutes !== 0) parts.push(`${bd.minutes} ${getDurationUnitLabel("minute", l, bd.minutes)}`);
848
+ if (bd.seconds !== 0) parts.push(`${bd.seconds} ${getDurationUnitLabel("second", l, bd.seconds)}`);
849
+ if (parts.length === 0) return formatZeroDuration(l);
850
+ return joinDurationParts(parts, l);
851
+ }
852
+ getMode() {
853
+ return this._mode;
854
+ }
855
+ valueOf() {
856
+ return this._value;
857
+ }
858
+ toString() {
859
+ if (this._mode === "calendar" && this._breakdownData) return this.format();
860
+ return this._value.toString();
861
+ }
862
+ toJSON() {
863
+ return this._value;
864
+ }
865
+ };
866
+ /**
867
+ * DurationResult class - Represents a duration breakdown with humanize support
868
+ * Returned by until(), since(), and between() methods
869
+ */
870
+ var DurationResult = class {
871
+ years;
872
+ months;
873
+ weeks;
874
+ days;
875
+ hours;
876
+ minutes;
877
+ seconds;
878
+ milliseconds;
879
+ _locale;
880
+ _startDate;
881
+ _endDate;
882
+ _steps = [];
883
+ _mode = "exact";
884
+ _leapYearFlags = [];
885
+ _calculationTimeMs = 0;
886
+ constructor(parts, locale = "en", metadata) {
887
+ this.years = parts.years;
888
+ this.months = parts.months;
889
+ this.weeks = parts.weeks;
890
+ this.days = parts.days;
891
+ this.hours = parts.hours;
892
+ this.minutes = parts.minutes;
893
+ this.seconds = parts.seconds;
894
+ this.milliseconds = parts.milliseconds;
895
+ this._locale = locale;
896
+ if (metadata) {
897
+ this._startDate = metadata.startDate;
898
+ this._endDate = metadata.endDate;
899
+ this._steps = metadata.steps || [];
900
+ this._mode = metadata.mode || "exact";
901
+ this._leapYearFlags = metadata.leapYearFlags || [];
902
+ this._calculationTimeMs = metadata.calculationTimeMs || 0;
903
+ }
904
+ }
905
+ humanize(options) {
906
+ const locale = options?.locale || this._locale;
907
+ const fullBreakdown = options?.fullBreakdown ?? false;
908
+ const numeric = options?.numeric ?? "always";
909
+ const nonZeroParts = [
910
+ {
911
+ unit: "year",
912
+ value: this.years
913
+ },
914
+ {
915
+ unit: "month",
916
+ value: this.months
917
+ },
918
+ {
919
+ unit: "week",
920
+ value: this.weeks
921
+ },
922
+ {
923
+ unit: "day",
924
+ value: this.days
925
+ },
926
+ {
927
+ unit: "hour",
928
+ value: this.hours
929
+ },
930
+ {
931
+ unit: "minute",
932
+ value: this.minutes
933
+ },
934
+ {
935
+ unit: "second",
936
+ value: this.seconds
937
+ },
938
+ {
939
+ unit: "millisecond",
940
+ value: this.milliseconds
941
+ }
942
+ ].filter((p) => p.value > 0);
943
+ if (nonZeroParts.length === 0) return "0 seconds";
944
+ if (!fullBreakdown || nonZeroParts.length === 1) {
945
+ const largest = nonZeroParts[0];
946
+ try {
947
+ return new Intl.RelativeTimeFormat(locale, {
948
+ numeric,
949
+ style: "long"
950
+ }).format(largest.value, largest.unit);
951
+ } catch {
952
+ return `${largest.value} ${this.pluralizeUnit(largest.unit, largest.value, locale)}`;
953
+ }
954
+ }
955
+ return joinDurationParts(nonZeroParts.map((p) => {
956
+ const label = getDurationUnitLabel(p.unit, locale, p.value);
957
+ return `${p.value} ${label}`;
958
+ }), locale);
959
+ }
960
+ total(unit) {
961
+ let totalMs = 0;
962
+ totalMs += this.years * MS_PER_YEAR;
963
+ totalMs += this.months * MS_PER_MONTH;
964
+ totalMs += this.weeks * MS_PER_WEEK;
965
+ totalMs += this.days * MS_PER_DAY;
966
+ totalMs += this.hours * MS_PER_HOUR;
967
+ totalMs += this.minutes * MS_PER_MINUTE;
968
+ totalMs += this.seconds * MS_PER_SECOND;
969
+ totalMs += this.milliseconds;
970
+ switch (unit) {
971
+ case "millisecond": return totalMs;
972
+ case "second": return totalMs / MS_PER_SECOND;
973
+ case "minute": return totalMs / MS_PER_MINUTE;
974
+ case "hour": return totalMs / MS_PER_HOUR;
975
+ case "day": return totalMs / MS_PER_DAY;
976
+ case "week": return totalMs / MS_PER_WEEK;
977
+ case "month": return totalMs / MS_PER_MONTH;
978
+ case "year": return totalMs / MS_PER_YEAR;
979
+ case "microsecond": return totalMs * 1e3;
980
+ case "nanosecond": return totalMs * 1e6;
981
+ default: throw new Error(`Unsupported unit: ${unit}`);
982
+ }
983
+ }
984
+ toString() {
985
+ return this.humanize({ fullBreakdown: true });
986
+ }
987
+ toJSON() {
988
+ return {
989
+ years: this.years,
990
+ months: this.months,
991
+ weeks: this.weeks,
992
+ days: this.days,
993
+ hours: this.hours,
994
+ minutes: this.minutes,
995
+ seconds: this.seconds,
996
+ milliseconds: this.milliseconds
997
+ };
998
+ }
999
+ explain() {
1000
+ let steps = [...this._steps];
1001
+ if (steps.length === 0) steps = this.generateExplanationSteps();
1002
+ const explanationParts = [];
1003
+ if (this._startDate && this._endDate) explanationParts.push(`Calculated duration from ${this._startDate} to ${this._endDate}`);
1004
+ if (this._leapYearFlags && this._leapYearFlags.length > 0) {
1005
+ const leapYears = this._leapYearFlags.filter((f) => f.isLeap).map((f) => f.year);
1006
+ if (leapYears.length > 0) explanationParts.push(`Leap year(s) detected: ${leapYears.join(", ")}`);
1007
+ }
1008
+ explanationParts.push(`Breakdown: ${this.years} year(s), ${this.months} month(s), ${this.days} day(s)`);
1009
+ explanationParts.push(`Mode: ${this._mode} calculation`);
1010
+ return {
1011
+ input: this._startDate && this._endDate ? [this._startDate, this._endDate] : [],
1012
+ steps,
1013
+ breakdown: {
1014
+ years: this.years,
1015
+ months: this.months,
1016
+ weeks: this.weeks,
1017
+ days: this.days,
1018
+ hours: this.hours,
1019
+ minutes: this.minutes,
1020
+ seconds: this.seconds,
1021
+ milliseconds: this.milliseconds
1022
+ },
1023
+ mode: this._mode,
1024
+ explanation: explanationParts.join(". "),
1025
+ locale: this._locale,
1026
+ leapYearFlags: this._leapYearFlags.length > 0 ? this._leapYearFlags : void 0,
1027
+ metadata: {
1028
+ calculationTimeMs: this._calculationTimeMs,
1029
+ precision: "day"
1030
+ }
1031
+ };
1032
+ }
1033
+ generateExplanationSteps() {
1034
+ const steps = [];
1035
+ if (this._startDate && this._endDate) steps.push(`Input: ${this._startDate} to ${this._endDate}`);
1036
+ else steps.push("Duration calculation started");
1037
+ if (this.years > 0) steps.push(`Years: ${this.years}`);
1038
+ if (this.months > 0) steps.push(`Months: ${this.months}`);
1039
+ if (this.weeks > 0) steps.push(`Weeks: ${this.weeks}`);
1040
+ if (this.days > 0) steps.push(`Days: ${this.days}`);
1041
+ if (this.hours > 0) steps.push(`Hours: ${this.hours}`);
1042
+ if (this.minutes > 0) steps.push(`Minutes: ${this.minutes}`);
1043
+ if (this.seconds > 0) steps.push(`Seconds: ${this.seconds}`);
1044
+ if (this.milliseconds > 0) steps.push(`Milliseconds: ${this.milliseconds}`);
1045
+ if (this._leapYearFlags && this._leapYearFlags.length > 0) {
1046
+ for (const flag of this._leapYearFlags) if (flag.isLeap) steps.push(`${flag.year} is a leap year (February has ${flag.daysInFebruary} days)`);
1047
+ }
1048
+ const totalParts = [
1049
+ this.years > 0 ? `${this.years}y` : "",
1050
+ this.months > 0 ? `${this.months}m` : "",
1051
+ this.days > 0 ? `${this.days}d` : "",
1052
+ this.hours > 0 ? `${this.hours}h` : "",
1053
+ this.minutes > 0 ? `${this.minutes}min` : "",
1054
+ this.seconds > 0 ? `${this.seconds}s` : ""
1055
+ ].filter((p) => p.length > 0).join(" ");
1056
+ steps.push(`Total: ${totalParts || "0"}`);
1057
+ return steps;
1058
+ }
1059
+ pluralizeUnit(unit, count, locale) {
1060
+ return getDurationUnitLabel(unit, locale, count);
1061
+ }
1062
+ };
1063
+ /**
1064
+ * TimeRange - Fluent API for date range operations
1065
+ *
1066
+ * @example
1067
+ * TimeGuard.range('2024-01-15', '2024-03-20')
1068
+ * .toDuration().humanize() // "2 months and 5 days"
1069
+ * .inMonths() // 2.1355 (precise decimal)
1070
+ */
1071
+ var TimeRange = class TimeRange {
1072
+ _start;
1073
+ _end;
1074
+ constructor(start, end) {
1075
+ this._start = start;
1076
+ this._end = end;
1077
+ }
1078
+ get start() {
1079
+ return this._start;
1080
+ }
1081
+ get end() {
1082
+ return this._end;
1083
+ }
1084
+ getOrdered() {
1085
+ const t1 = TemporalAdapter.toPlainDateTime(this._start.toTemporal());
1086
+ const t2 = TemporalAdapter.toPlainDateTime(this._end.toTemporal());
1087
+ return TemporalAdapter.compare(t1, t2) <= 0 ? [t1, t2] : [t2, t1];
1088
+ }
1089
+ toDuration() {
1090
+ return TimeGuard.between(this._start, this._end);
1091
+ }
1092
+ inMonths() {
1093
+ return this.toDuration().total("month");
1094
+ }
1095
+ humanize(options) {
1096
+ return this.toDuration().humanize(options);
1097
+ }
1098
+ in(unit) {
1099
+ return this.toDuration().total(unit);
1100
+ }
1101
+ contains(date) {
1102
+ const tg = date instanceof TimeGuard ? date : new TimeGuard(date);
1103
+ const t = TemporalAdapter.toPlainDateTime(tg.toTemporal());
1104
+ const [startT, endT] = this.getOrdered();
1105
+ return TemporalAdapter.compare(t, startT) >= 0 && TemporalAdapter.compare(t, endT) <= 0;
1106
+ }
1107
+ overlaps(other) {
1108
+ const [s1, e1] = this.getOrdered();
1109
+ const [s2, e2] = other.getOrdered();
1110
+ return TemporalAdapter.compare(s1, e2) <= 0 && TemporalAdapter.compare(s2, e1) <= 0;
1111
+ }
1112
+ intersect(other) {
1113
+ if (!this.overlaps(other)) return null;
1114
+ const [s1, e1] = this.getOrdered();
1115
+ const [s2, e2] = other.getOrdered();
1116
+ const startT = TemporalAdapter.compare(s1, s2) >= 0 ? s1 : s2;
1117
+ const endT = TemporalAdapter.compare(e1, e2) <= 0 ? e1 : e2;
1118
+ return new TimeRange(TimeGuard.fromTemporal(startT, { locale: this._start.locale() }), TimeGuard.fromTemporal(endT, { locale: this._end.locale() }));
1119
+ }
1120
+ union(other) {
1121
+ const [s1, e1] = this.getOrdered();
1122
+ const [s2, e2] = other.getOrdered();
1123
+ const startT = TemporalAdapter.compare(s1, s2) <= 0 ? s1 : s2;
1124
+ const endT = TemporalAdapter.compare(e1, e2) >= 0 ? e1 : e2;
1125
+ return new TimeRange(TimeGuard.fromTemporal(startT, { locale: this._start.locale() }), TimeGuard.fromTemporal(endT, { locale: this._end.locale() }));
1126
+ }
1127
+ };
1128
+ /**
1129
+ * TimeGuard implementation - Main facade class
1130
+ */
1131
+ var TimeGuard = class TimeGuard {
1132
+ temporal;
1133
+ config;
1134
+ formatterInstance;
1135
+ static holidays = /* @__PURE__ */ new Set();
1136
+ static registerHolidays(dates) {
1137
+ dates.forEach((d) => {
1138
+ try {
1139
+ const tg = new TimeGuard(d);
1140
+ this.holidays.add(tg.format("YYYY-MM-DD"));
1141
+ } catch {}
1142
+ });
1143
+ }
1144
+ static clearHolidays() {
1145
+ this.holidays.clear();
1146
+ }
1147
+ static getRegisteredHolidays() {
1148
+ return Array.from(this.holidays).sort();
1149
+ }
1150
+ static ZERO_DURATION = {
1151
+ years: 0,
1152
+ months: 0,
1153
+ weeks: 0,
1154
+ days: 0,
1155
+ hours: 0,
1156
+ minutes: 0,
1157
+ seconds: 0,
1158
+ milliseconds: 0
1159
+ };
1160
+ static isLeapYearValue(year) {
1161
+ return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
1162
+ }
1163
+ static toDurationParts(duration) {
1164
+ return {
1165
+ years: Math.floor(duration.years || 0),
1166
+ months: Math.floor(duration.months || 0),
1167
+ weeks: Math.floor(duration.weeks || 0),
1168
+ days: Math.floor(duration.days || 0),
1169
+ hours: Math.floor(duration.hours || 0),
1170
+ minutes: Math.floor(duration.minutes || 0),
1171
+ seconds: Math.floor(duration.seconds || 0),
1172
+ milliseconds: Math.floor(duration.milliseconds || 0)
1173
+ };
1174
+ }
1175
+ constructor(input, config) {
1176
+ this.formatterInstance = new DateFormatter();
1177
+ this.config = {
1178
+ locale: config?.locale || "en",
1179
+ timezone: config?.timezone || "UTC",
1180
+ strict: config?.strict ?? false
1181
+ };
1182
+ this.temporal = TemporalAdapter.parseToPlainDateTime(input);
1183
+ if (this.config.timezone && this.config.timezone !== "UTC") try {
1184
+ const zoned = this.temporal.toZonedDateTime(this.config.timezone);
1185
+ this.temporal = zoned;
1186
+ } catch {}
1187
+ }
1188
+ static now(config) {
1189
+ return new TimeGuard(void 0, config);
1190
+ }
1191
+ static from(input, config) {
1192
+ return new TimeGuard(input, config);
1193
+ }
1194
+ static fromTemporal(temporal, config) {
1195
+ const instance = new TimeGuard(void 0, config);
1196
+ instance.temporal = temporal;
1197
+ return instance;
1198
+ }
1199
+ /**
1200
+ * Calculate duration between two dates - always returns positive duration
1201
+ *
1202
+ * @example
1203
+ * TimeGuard.between(start, end).humanize() // "2 months and 5 days"
1204
+ * TimeGuard.between(end, start).humanize() // "2 months and 5 days" (still positive)
1205
+ */
1206
+ static between(date1, date2) {
1207
+ const t1 = TemporalAdapter.toPlainDateTime(date1.temporal);
1208
+ const t2 = TemporalAdapter.toPlainDateTime(date2.temporal);
1209
+ const [earlier, later] = TemporalAdapter.compare(t1, t2) <= 0 ? [date1, date2] : [date2, date1];
1210
+ return earlier.until(later);
1211
+ }
1212
+ /**
1213
+ * Create a TimeRange for fluent duration calculations
1214
+ *
1215
+ * @example
1216
+ * TimeGuard.range("2024-01-15", "2024-03-20").humanize() // "2 months and 5 days"
1217
+ */
1218
+ static range(start, end) {
1219
+ return new TimeRange(start instanceof TimeGuard ? start : new TimeGuard(start), end instanceof TimeGuard ? end : new TimeGuard(end));
1220
+ }
1221
+ toTemporal() {
1222
+ return this.temporal;
1223
+ }
1224
+ toDate() {
1225
+ return TemporalAdapter.toDate(this.temporal);
1226
+ }
1227
+ toISOString() {
1228
+ return TemporalAdapter.toISOString(this.temporal);
1229
+ }
1230
+ valueOf() {
1231
+ return TemporalAdapter.toUnix(this.temporal);
1232
+ }
1233
+ unix() {
1234
+ return Math.floor(this.valueOf() / 1e3);
1235
+ }
1236
+ toJSON() {
1237
+ return this.toISOString();
1238
+ }
1239
+ [Symbol.toPrimitive](hint) {
1240
+ if (hint === "number") return this.valueOf();
1241
+ if (hint === "string") return this.toISOString();
1242
+ return this.toISOString();
1243
+ }
1244
+ toString() {
1245
+ return this.format("YYYY-MM-DD HH:mm:ss");
1246
+ }
1247
+ locale(locale) {
1248
+ if (locale === void 0) return this.config.locale;
1249
+ const cloned = this.clone();
1250
+ cloned.config.locale = locale;
1251
+ return cloned;
1252
+ }
1253
+ timezone(timezone) {
1254
+ if (timezone === void 0) return this.config.timezone;
1255
+ const cloned = this.clone();
1256
+ cloned.config.timezone = timezone;
1257
+ try {
1258
+ cloned.temporal = TemporalAdapter.toPlainDateTime(cloned.temporal).toZonedDateTime(timezone);
1259
+ } catch {}
1260
+ return cloned;
1261
+ }
1262
+ format(pattern) {
1263
+ const plainDT = TemporalAdapter.toPlainDateTime(this.temporal);
1264
+ const formatPattern = [
1265
+ "iso",
1266
+ "date",
1267
+ "time",
1268
+ "datetime",
1269
+ "rfc2822",
1270
+ "rfc3339",
1271
+ "utc"
1272
+ ].includes(pattern) ? this.formatterInstance.getPreset(pattern) : pattern;
1273
+ return this.formatterInstance.format(plainDT, formatPattern, this.config.locale);
1274
+ }
1275
+ get(component) {
1276
+ const plainDT = TemporalAdapter.toPlainDateTime(this.temporal);
1277
+ const unitMap = {
1278
+ year: "year",
1279
+ month: "month",
1280
+ week: "year",
1281
+ day: "day",
1282
+ hour: "hour",
1283
+ minute: "minute",
1284
+ second: "second",
1285
+ millisecond: "millisecond",
1286
+ microsecond: "microsecond",
1287
+ nanosecond: "nanosecond"
1288
+ };
1289
+ if (component === "week") return plainDT.weekOfYear;
1290
+ return plainDT[unitMap[component]];
1291
+ }
1292
+ /** Map from singular Unit to plural Temporal polyfill key */
1293
+ static UNIT_TO_PLURAL = {
1294
+ year: "years",
1295
+ month: "months",
1296
+ week: "weeks",
1297
+ day: "days",
1298
+ hour: "hours",
1299
+ minute: "minutes",
1300
+ second: "seconds",
1301
+ millisecond: "milliseconds",
1302
+ microsecond: "microseconds",
1303
+ nanosecond: "nanoseconds",
1304
+ years: "years",
1305
+ months: "months",
1306
+ weeks: "weeks",
1307
+ days: "days",
1308
+ hours: "hours",
1309
+ minutes: "minutes",
1310
+ seconds: "seconds",
1311
+ milliseconds: "milliseconds",
1312
+ microseconds: "microseconds",
1313
+ nanoseconds: "nanoseconds"
1314
+ };
1315
+ add(units) {
1316
+ let plainDT = TemporalAdapter.toPlainDateTime(this.temporal);
1317
+ const duration = {
1318
+ years: 0,
1319
+ months: 0,
1320
+ weeks: 0,
1321
+ days: 0,
1322
+ hours: 0,
1323
+ minutes: 0,
1324
+ seconds: 0,
1325
+ milliseconds: 0,
1326
+ microseconds: 0,
1327
+ nanoseconds: 0
1328
+ };
1329
+ let hasValidFields = false;
1330
+ Object.entries(units).forEach(([unit, value]) => {
1331
+ if (value !== void 0 && value !== 0) {
1332
+ const num = Number(value);
1333
+ if (Number.isFinite(num)) {
1334
+ const targetKey = TimeGuard.UNIT_TO_PLURAL[unit] || unit;
1335
+ duration[targetKey] = Math.trunc(num);
1336
+ hasValidFields = true;
1337
+ }
1338
+ }
1339
+ });
1340
+ if (!hasValidFields) return this;
1341
+ plainDT = plainDT.add(duration);
1342
+ return TimeGuard.fromTemporal(plainDT, this.config);
1343
+ }
1344
+ subtract(units) {
1345
+ const negated = {};
1346
+ Object.entries(units).forEach(([unit, value]) => {
1347
+ negated[unit] = value ? -value : 0;
1348
+ });
1349
+ return this.add(negated);
1350
+ }
1351
+ diff(other, unitOrOptions) {
1352
+ const plainDT1 = TemporalAdapter.toPlainDateTime(this.temporal);
1353
+ const plainDT2 = TemporalAdapter.toPlainDateTime(other.temporal);
1354
+ const unitMap = {
1355
+ year: "years",
1356
+ month: "months",
1357
+ week: "weeks",
1358
+ day: "days",
1359
+ hour: "hours",
1360
+ minute: "minutes",
1361
+ second: "seconds",
1362
+ millisecond: "milliseconds",
1363
+ microsecond: "microseconds",
1364
+ nanosecond: "nanoseconds"
1365
+ };
1366
+ if (typeof unitOrOptions === "string") {
1367
+ const unit = unitOrOptions;
1368
+ const mappedUnit = unitMap[unit];
1369
+ const durationObj = plainDT1.since(plainDT2, { smallestUnit: unit });
1370
+ return Math.round(durationObj[mappedUnit] || 0);
1371
+ }
1372
+ const options = unitOrOptions || {};
1373
+ const mode = options.mode || "exact";
1374
+ const unit = options.unit || "millisecond";
1375
+ const locale = options.locale || this.config.locale;
1376
+ if (mode === "exact") {
1377
+ const mappedUnit = unitMap[unit];
1378
+ const duration = plainDT1.since(plainDT2, { smallestUnit: unit });
1379
+ const result = Math.round(duration[mappedUnit] || 0);
1380
+ if (unitOrOptions === void 0 || typeof unitOrOptions === "object") {
1381
+ const totalMs = calculateTotalMs(duration);
1382
+ return new DiffResult(Math.round(totalMs), this, other, mode, void 0, locale);
1383
+ }
1384
+ return result;
1385
+ }
1386
+ if (mode === "calendar") {
1387
+ const duration = plainDT1.since(plainDT2, {
1388
+ largestUnit: "month",
1389
+ smallestUnit: "millisecond"
1390
+ });
1391
+ const breakdownData = {
1392
+ years: Math.floor(duration.years || 0),
1393
+ months: Math.floor(duration.months || 0),
1394
+ weeks: Math.floor(duration.weeks || 0),
1395
+ days: Math.floor(duration.days || 0),
1396
+ hours: Math.floor(duration.hours || 0),
1397
+ minutes: Math.floor(duration.minutes || 0),
1398
+ seconds: Math.floor(duration.seconds || 0),
1399
+ milliseconds: Math.floor(duration.milliseconds || 0)
1400
+ };
1401
+ const totalMs = calculateTotalMs(duration);
1402
+ return new DiffResult(Math.round(totalMs), this, other, mode, breakdownData, locale);
1403
+ }
1404
+ const totalMs = calculateTotalMs(plainDT1.since(plainDT2, { smallestUnit: "millisecond" }));
1405
+ return new DiffResult(Math.round(totalMs), this, other, mode, void 0, locale);
1406
+ }
1407
+ isBefore(other) {
1408
+ const plainDT1 = TemporalAdapter.toPlainDateTime(this.temporal);
1409
+ const plainDT2 = TemporalAdapter.toPlainDateTime(other.temporal);
1410
+ return TemporalAdapter.compare(plainDT1, plainDT2) < 0;
1411
+ }
1412
+ isAfter(other) {
1413
+ const plainDT1 = TemporalAdapter.toPlainDateTime(this.temporal);
1414
+ const plainDT2 = TemporalAdapter.toPlainDateTime(other.temporal);
1415
+ return TemporalAdapter.compare(plainDT1, plainDT2) > 0;
1416
+ }
1417
+ isSame(other, unit) {
1418
+ if (!unit) return TemporalAdapter.compare(TemporalAdapter.toPlainDateTime(this.temporal), TemporalAdapter.toPlainDateTime(other.temporal)) === 0;
1419
+ const plainDT1 = TemporalAdapter.toPlainDateTime(this.temporal);
1420
+ const plainDT2 = TemporalAdapter.toPlainDateTime(other.temporal);
1421
+ switch (unit) {
1422
+ case "year": return plainDT1.year === plainDT2.year;
1423
+ case "month": return plainDT1.year === plainDT2.year && plainDT1.month === plainDT2.month;
1424
+ case "day": return plainDT1.year === plainDT2.year && plainDT1.month === plainDT2.month && plainDT1.day === plainDT2.day;
1425
+ case "hour": return plainDT1.year === plainDT2.year && plainDT1.month === plainDT2.month && plainDT1.day === plainDT2.day && plainDT1.hour === plainDT2.hour;
1426
+ case "minute": return plainDT1.year === plainDT2.year && plainDT1.month === plainDT2.month && plainDT1.day === plainDT2.day && plainDT1.hour === plainDT2.hour && plainDT1.minute === plainDT2.minute;
1427
+ case "second": return plainDT1.year === plainDT2.year && plainDT1.month === plainDT2.month && plainDT1.day === plainDT2.day && plainDT1.hour === plainDT2.hour && plainDT1.minute === plainDT2.minute && plainDT1.second === plainDT2.second;
1428
+ default: return false;
1429
+ }
1430
+ }
1431
+ isBetween(start, end, unit, inclusivity = "[]") {
1432
+ const plainDT = TemporalAdapter.toPlainDateTime(this.temporal);
1433
+ const plainStart = TemporalAdapter.toPlainDateTime(start.temporal);
1434
+ const plainEnd = TemporalAdapter.toPlainDateTime(end.temporal);
1435
+ let afterStart = true;
1436
+ let beforeEnd = true;
1437
+ if (unit) {
1438
+ const startCopy = this.clone().startOf(unit);
1439
+ const endCopy = this.clone().endOf(unit);
1440
+ const plainCopy = TemporalAdapter.toPlainDateTime(startCopy.temporal);
1441
+ const plainEndCopy = TemporalAdapter.toPlainDateTime(endCopy.temporal);
1442
+ afterStart = TemporalAdapter.compare(plainCopy, plainStart) >= 0;
1443
+ beforeEnd = TemporalAdapter.compare(plainEndCopy, plainEnd) <= 0;
1444
+ } else {
1445
+ afterStart = TemporalAdapter.compare(plainDT, plainStart) >= 0;
1446
+ beforeEnd = TemporalAdapter.compare(plainDT, plainEnd) <= 0;
1447
+ }
1448
+ const hasStartBracket = inclusivity[0] === "[";
1449
+ const hasEndBracket = inclusivity[1] === "]";
1450
+ return (hasStartBracket ? afterStart : TemporalAdapter.compare(plainDT, plainStart) > 0) && (hasEndBracket ? beforeEnd : TemporalAdapter.compare(plainDT, plainEnd) < 0);
1451
+ }
1452
+ clone() {
1453
+ return new TimeGuard(this.toDate(), this.config);
1454
+ }
1455
+ startOf(unit) {
1456
+ const plainDT = TemporalAdapter.toPlainDateTime(this.temporal);
1457
+ const values = {};
1458
+ switch (unit) {
1459
+ case "year":
1460
+ values.month = 1;
1461
+ values.day = 1;
1462
+ values.hour = 0;
1463
+ values.minute = 0;
1464
+ values.second = 0;
1465
+ values.millisecond = 0;
1466
+ break;
1467
+ case "month":
1468
+ values.day = 1;
1469
+ values.hour = 0;
1470
+ values.minute = 0;
1471
+ values.second = 0;
1472
+ values.millisecond = 0;
1473
+ break;
1474
+ case "week":
1475
+ case "day":
1476
+ values.hour = 0;
1477
+ values.minute = 0;
1478
+ values.second = 0;
1479
+ values.millisecond = 0;
1480
+ break;
1481
+ case "hour":
1482
+ values.minute = 0;
1483
+ values.second = 0;
1484
+ values.millisecond = 0;
1485
+ break;
1486
+ case "minute":
1487
+ values.second = 0;
1488
+ values.millisecond = 0;
1489
+ break;
1490
+ case "second":
1491
+ values.millisecond = 0;
1492
+ break;
1493
+ }
1494
+ const updated = plainDT.with(values);
1495
+ return TimeGuard.fromTemporal(updated, this.config);
1496
+ }
1497
+ endOf(unit) {
1498
+ return this.startOf(unit).add({ [unit]: 1 }).subtract({ millisecond: 1 });
1499
+ }
1500
+ set(values) {
1501
+ const updated = TemporalAdapter.toPlainDateTime(this.temporal).with(values);
1502
+ return TimeGuard.fromTemporal(updated, this.config);
1503
+ }
1504
+ year() {
1505
+ return TemporalAdapter.toPlainDateTime(this.temporal).year;
1506
+ }
1507
+ month() {
1508
+ return TemporalAdapter.toPlainDateTime(this.temporal).month;
1509
+ }
1510
+ day() {
1511
+ return TemporalAdapter.toPlainDateTime(this.temporal).day;
1512
+ }
1513
+ hour() {
1514
+ return TemporalAdapter.toPlainDateTime(this.temporal).hour;
1515
+ }
1516
+ minute() {
1517
+ return TemporalAdapter.toPlainDateTime(this.temporal).minute;
1518
+ }
1519
+ second() {
1520
+ return TemporalAdapter.toPlainDateTime(this.temporal).second;
1521
+ }
1522
+ millisecond() {
1523
+ return TemporalAdapter.toPlainDateTime(this.temporal).millisecond;
1524
+ }
1525
+ dayOfWeek() {
1526
+ return TemporalAdapter.toPlainDateTime(this.temporal).dayOfWeek;
1527
+ }
1528
+ dayOfYear() {
1529
+ return TemporalAdapter.toPlainDateTime(this.temporal).dayOfYear;
1530
+ }
1531
+ weekOfYear() {
1532
+ return TemporalAdapter.toPlainDateTime(this.temporal).weekOfYear;
1533
+ }
1534
+ daysInMonth() {
1535
+ return TemporalAdapter.toPlainDateTime(this.temporal).add({ months: 1 }).with({ day: 1 }).subtract({ days: 1 }).day;
1536
+ }
1537
+ daysInYear() {
1538
+ const year = this.year();
1539
+ return TimeGuard.isLeapYearValue(year) ? 366 : 365;
1540
+ }
1541
+ inLeapYear() {
1542
+ const plainDT = TemporalAdapter.toPlainDateTime(this.temporal);
1543
+ return TimeGuard.isLeapYearValue(plainDT.year);
1544
+ }
1545
+ until(other, options) {
1546
+ const plainDT1 = TemporalAdapter.toPlainDateTime(this.temporal);
1547
+ const plainDT2 = TemporalAdapter.toPlainDateTime(other.temporal);
1548
+ const startTime = performance.now();
1549
+ try {
1550
+ const temporalOptions = {};
1551
+ if (options?.largestUnit) temporalOptions.largestUnit = options.largestUnit;
1552
+ if (options?.smallestUnit) temporalOptions.smallestUnit = options.smallestUnit;
1553
+ const duration = plainDT2.since(plainDT1, Object.keys(temporalOptions).length > 0 ? temporalOptions : void 0);
1554
+ const parts = TimeGuard.toDurationParts(duration);
1555
+ const startYear = plainDT1.year;
1556
+ const endYear = plainDT2.year;
1557
+ const leapYearFlags = [];
1558
+ for (let year = startYear; year <= endYear; year++) {
1559
+ const isLeap = TimeGuard.isLeapYearValue(year);
1560
+ leapYearFlags.push({
1561
+ year,
1562
+ isLeap,
1563
+ daysInFebruary: isLeap ? 29 : 28
1564
+ });
1565
+ }
1566
+ const steps = this.generateUntilSteps(plainDT1, plainDT2, parts, leapYearFlags);
1567
+ const calculationTimeMs = performance.now() - startTime;
1568
+ return new DurationResult(parts, this.config.locale, {
1569
+ startDate: plainDT1.toString(),
1570
+ endDate: plainDT2.toString(),
1571
+ steps,
1572
+ mode: "exact",
1573
+ leapYearFlags: leapYearFlags.filter((f) => f.isLeap),
1574
+ calculationTimeMs
1575
+ });
1576
+ } catch {
1577
+ return new DurationResult(TimeGuard.ZERO_DURATION, this.config.locale, {
1578
+ startDate: plainDT1.toString(),
1579
+ endDate: plainDT2.toString(),
1580
+ steps: ["Calculation failed, returning zero duration"],
1581
+ mode: "estimated"
1582
+ });
1583
+ }
1584
+ }
1585
+ generateUntilSteps(start, end, parts, leapYearFlags) {
1586
+ const steps = [];
1587
+ steps.push(`Parsed dates: ${start.year}-${String(start.month).padStart(2, "0")}-${String(start.day).padStart(2, "0")} (day ${start.dayOfYear} of ${TimeGuard.isLeapYearValue(start.year) ? 366 : 365})`);
1588
+ steps.push(`to ${end.year}-${String(end.month).padStart(2, "0")}-${String(end.day).padStart(2, "0")} (day ${end.dayOfYear} of ${TimeGuard.isLeapYearValue(end.year) ? 366 : 365})`);
1589
+ const leapYearsInRange = leapYearFlags.filter((f) => f.isLeap);
1590
+ if (leapYearsInRange.length > 0) for (const flag of leapYearsInRange) steps.push(`${flag.year} is a leap year (February has ${flag.daysInFebruary} days)`);
1591
+ if (parts.years > 0) steps.push(`Years: ${parts.years}`);
1592
+ if (parts.months > 0) steps.push(`Months: ${parts.months}`);
1593
+ if (parts.days > 0) steps.push(`Days: ${parts.days}`);
1594
+ if (parts.hours > 0 || parts.minutes > 0 || parts.seconds > 0) {
1595
+ const timeComponents = [];
1596
+ if (parts.hours > 0) timeComponents.push(`${parts.hours}h`);
1597
+ if (parts.minutes > 0) timeComponents.push(`${parts.minutes}m`);
1598
+ if (parts.seconds > 0) timeComponents.push(`${parts.seconds}s`);
1599
+ steps.push(`Time: ${timeComponents.join(" ")}`);
1600
+ }
1601
+ const totalDays = parts.years * 365.25 + parts.months * 30.4375 + parts.days + parts.hours / 24;
1602
+ steps.push(`Total: approximately ${totalDays.toFixed(2)} days`);
1603
+ return steps;
1604
+ }
1605
+ round(options = {}) {
1606
+ const { smallestUnit = "millisecond", roundingMode = "halfExpand" } = options;
1607
+ const polyfillDT = TemporalAdapter.toPlainDateTime(this.temporal);
1608
+ const unitValues = {
1609
+ year: polyfillDT.year,
1610
+ month: polyfillDT.month,
1611
+ day: polyfillDT.day,
1612
+ hour: polyfillDT.hour,
1613
+ minute: polyfillDT.minute,
1614
+ second: polyfillDT.second,
1615
+ millisecond: polyfillDT.millisecond,
1616
+ microsecond: polyfillDT.microsecond || 0,
1617
+ nanosecond: polyfillDT.nanosecond || 0,
1618
+ week: 0
1619
+ };
1620
+ const unitOrder = [
1621
+ "year",
1622
+ "month",
1623
+ "day",
1624
+ "hour",
1625
+ "minute",
1626
+ "second",
1627
+ "millisecond",
1628
+ "microsecond",
1629
+ "nanosecond"
1630
+ ];
1631
+ const smallestIndex = unitOrder.indexOf(smallestUnit);
1632
+ if (smallestIndex === -1) return this.clone();
1633
+ const roundedValues = {};
1634
+ for (let i = 0; i < smallestIndex; i++) {
1635
+ const unit = unitOrder[i];
1636
+ roundedValues[unit] = unitValues[unit];
1637
+ }
1638
+ const unit = unitOrder[smallestIndex];
1639
+ let value = unitValues[unit];
1640
+ if (smallestIndex + 1 < unitOrder.length) {
1641
+ const nextUnitValue = unitValues[unitOrder[smallestIndex + 1]];
1642
+ const shouldRoundUp = (mode, nextVal) => {
1643
+ switch (mode) {
1644
+ case "ceil": return nextVal > 0;
1645
+ case "floor":
1646
+ case "trunc": return false;
1647
+ case "halfExpand":
1648
+ case "halfFloor":
1649
+ case "halfCeil": return nextVal >= 5;
1650
+ case "expand": return nextVal > 0;
1651
+ default: return nextVal >= 5;
1652
+ }
1653
+ };
1654
+ if (shouldRoundUp(roundingMode, nextUnitValue)) value += 1;
1655
+ }
1656
+ roundedValues[unit] = value;
1657
+ for (let i = smallestIndex + 1; i < unitOrder.length; i++) roundedValues[unitOrder[i]] = 0;
1658
+ return this.set(roundedValues);
1659
+ }
1660
+ toPlainDate() {
1661
+ const plainDT = TemporalAdapter.toPlainDateTime(this.temporal);
1662
+ return {
1663
+ year: plainDT.year,
1664
+ month: plainDT.month,
1665
+ day: plainDT.day,
1666
+ dayOfWeek: plainDT.dayOfWeek
1667
+ };
1668
+ }
1669
+ toPlainTime() {
1670
+ const plainDT = TemporalAdapter.toPlainDateTime(this.temporal);
1671
+ return {
1672
+ hour: plainDT.hour,
1673
+ minute: plainDT.minute,
1674
+ second: plainDT.second,
1675
+ millisecond: plainDT.millisecond
1676
+ };
1677
+ }
1678
+ withDate(year, month, day) {
1679
+ return this.set({
1680
+ year,
1681
+ month,
1682
+ day
1683
+ });
1684
+ }
1685
+ withTime(hour, minute = 0, second = 0, millisecond = 0) {
1686
+ return this.set({
1687
+ hour,
1688
+ minute,
1689
+ second,
1690
+ millisecond
1691
+ });
1692
+ }
1693
+ getOffset() {
1694
+ return this.temporal?.offset || "Z";
1695
+ }
1696
+ getOffsetNanoseconds() {
1697
+ return this.temporal?.offsetNanoseconds || 0;
1698
+ }
1699
+ getTimeZoneId() {
1700
+ return this.temporal?.timeZoneId || null;
1701
+ }
1702
+ startOfDay() {
1703
+ return this.startOf("day");
1704
+ }
1705
+ endOfDay() {
1706
+ return this.endOf("day");
1707
+ }
1708
+ since(other, options) {
1709
+ const plainDT1 = TemporalAdapter.toPlainDateTime(this.temporal);
1710
+ const plainDT2 = TemporalAdapter.toPlainDateTime(other.temporal);
1711
+ const startTime = performance.now();
1712
+ try {
1713
+ const temporalOptions = {};
1714
+ if (options?.largestUnit) temporalOptions.largestUnit = options.largestUnit;
1715
+ if (options?.smallestUnit) temporalOptions.smallestUnit = options.smallestUnit;
1716
+ const duration = plainDT1.since(plainDT2, Object.keys(temporalOptions).length > 0 ? temporalOptions : void 0);
1717
+ const parts = TimeGuard.toDurationParts(duration);
1718
+ const startYear = plainDT2.year;
1719
+ const endYear = plainDT1.year;
1720
+ const leapYearFlags = [];
1721
+ for (let year = startYear; year <= endYear; year++) {
1722
+ const isLeap = TimeGuard.isLeapYearValue(year);
1723
+ leapYearFlags.push({
1724
+ year,
1725
+ isLeap,
1726
+ daysInFebruary: isLeap ? 29 : 28
1727
+ });
1728
+ }
1729
+ const steps = this.generateUntilSteps(plainDT2, plainDT1, parts, leapYearFlags);
1730
+ const calculationTimeMs = performance.now() - startTime;
1731
+ return new DurationResult(parts, this.config.locale, {
1732
+ startDate: plainDT2.toString(),
1733
+ endDate: plainDT1.toString(),
1734
+ steps,
1735
+ mode: "exact",
1736
+ leapYearFlags: leapYearFlags.filter((f) => f.isLeap),
1737
+ calculationTimeMs
1738
+ });
1739
+ } catch {
1740
+ return new DurationResult(TimeGuard.ZERO_DURATION, this.config.locale, {
1741
+ startDate: plainDT2.toString(),
1742
+ endDate: plainDT1.toString(),
1743
+ steps: ["Calculation failed, returning zero duration"],
1744
+ mode: "estimated"
1745
+ });
1746
+ }
1747
+ }
1748
+ toDurationString(other) {
1749
+ const duration = other ? this.until(other) : this.until(TimeGuard.now());
1750
+ const parts = [];
1751
+ if (duration.years) parts.push(`${duration.years}Y`);
1752
+ if (duration.months) parts.push(`${duration.months}M`);
1753
+ if (duration.days) parts.push(`${duration.days}D`);
1754
+ const timeParts = [];
1755
+ if (duration.hours) timeParts.push(`${duration.hours}H`);
1756
+ if (duration.minutes) timeParts.push(`${duration.minutes}M`);
1757
+ if (duration.seconds) timeParts.push(`${duration.seconds}S`);
1758
+ const result = `P${parts.join("")}${timeParts.length > 0 ? "T" + timeParts.join("") : ""}`;
1759
+ return result === "P" ? "PT0S" : result;
1760
+ }
1761
+ isPast() {
1762
+ return this.isBefore(TimeGuard.now());
1763
+ }
1764
+ isFuture() {
1765
+ return this.isAfter(TimeGuard.now());
1766
+ }
1767
+ isToday() {
1768
+ return this.isSame(TimeGuard.now(), "day");
1769
+ }
1770
+ isTomorrow() {
1771
+ return this.isSame(TimeGuard.now().add({ day: 1 }), "day");
1772
+ }
1773
+ isYesterday() {
1774
+ return this.isSame(TimeGuard.now().subtract({ day: 1 }), "day");
1775
+ }
1776
+ isWeekend() {
1777
+ const plainDT = TemporalAdapter.toPlainDateTime(this.temporal);
1778
+ return plainDT.dayOfWeek === 6 || plainDT.dayOfWeek === 7;
1779
+ }
1780
+ isHoliday() {
1781
+ const dateStr = this.format("YYYY-MM-DD");
1782
+ return TimeGuard.holidays.has(dateStr);
1783
+ }
1784
+ isBusinessDay() {
1785
+ return !this.isWeekend() && !this.isHoliday();
1786
+ }
1787
+ addBusinessDays(days) {
1788
+ const num = Math.trunc(days);
1789
+ if (!Number.isFinite(num) || num === 0) return this;
1790
+ let cloned = this.clone();
1791
+ let remaining = Math.abs(num);
1792
+ const step = num > 0 ? 1 : -1;
1793
+ while (remaining > 0) {
1794
+ cloned = cloned.add({ day: step });
1795
+ if (cloned.isBusinessDay()) remaining--;
1796
+ }
1797
+ return cloned;
1798
+ }
1799
+ subtractBusinessDays(days) {
1800
+ return this.addBusinessDays(-days);
1801
+ }
1802
+ };
1803
+ function timeGuard(input, config) {
1804
+ return new TimeGuard(input, config);
1805
+ }
1806
+ /** The current version of TimeGuard */
1807
+ var version = "2.7.0";
1808
+ //#endregion
1809
+ Object.defineProperty(exports, "CalendarManager", {
1810
+ enumerable: true,
1811
+ get: function() {
1812
+ return CalendarManager;
1813
+ }
1814
+ });
1815
+ Object.defineProperty(exports, "DateFormatter", {
1816
+ enumerable: true,
1817
+ get: function() {
1818
+ return DateFormatter;
1819
+ }
1820
+ });
1821
+ Object.defineProperty(exports, "DurationResult", {
1822
+ enumerable: true,
1823
+ get: function() {
1824
+ return DurationResult;
1825
+ }
1826
+ });
1827
+ Object.defineProperty(exports, "EN_LOCALE", {
1828
+ enumerable: true,
1829
+ get: function() {
1830
+ return EN_LOCALE;
1831
+ }
1832
+ });
1833
+ Object.defineProperty(exports, "ES_LOCALE", {
1834
+ enumerable: true,
1835
+ get: function() {
1836
+ return ES_LOCALE;
1837
+ }
1838
+ });
1839
+ Object.defineProperty(exports, "GregorianCalendar", {
1840
+ enumerable: true,
1841
+ get: function() {
1842
+ return GregorianCalendar;
1843
+ }
1844
+ });
1845
+ Object.defineProperty(exports, "LocaleManager", {
1846
+ enumerable: true,
1847
+ get: function() {
1848
+ return LocaleManager;
1849
+ }
1850
+ });
1851
+ Object.defineProperty(exports, "PluginManager", {
1852
+ enumerable: true,
1853
+ get: function() {
1854
+ return PluginManager;
1855
+ }
1856
+ });
1857
+ Object.defineProperty(exports, "TemporalAdapter", {
1858
+ enumerable: true,
1859
+ get: function() {
1860
+ return TemporalAdapter;
1861
+ }
1862
+ });
1863
+ Object.defineProperty(exports, "TimeGuard", {
1864
+ enumerable: true,
1865
+ get: function() {
1866
+ return TimeGuard;
1867
+ }
1868
+ });
1869
+ Object.defineProperty(exports, "TimeRange", {
1870
+ enumerable: true,
1871
+ get: function() {
1872
+ return TimeRange;
1873
+ }
1874
+ });
1875
+ Object.defineProperty(exports, "calendarManager", {
1876
+ enumerable: true,
1877
+ get: function() {
1878
+ return calendarManager;
1879
+ }
1880
+ });
1881
+ Object.defineProperty(exports, "timeGuard", {
1882
+ enumerable: true,
1883
+ get: function() {
1884
+ return timeGuard;
1885
+ }
1886
+ });
1887
+ Object.defineProperty(exports, "version", {
1888
+ enumerable: true,
1889
+ get: function() {
1890
+ return version;
1891
+ }
1892
+ });