@timestamp-js/core 0.1.0-rc.1 → 0.1.0-rc.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.
package/dist/index.js CHANGED
@@ -1,5 +1,64 @@
1
- import { formatCalendarDate, gregorianCalendar } from './calendar.js';
2
- export { formatCalendarDate, gregorianCalendar } from './calendar.js';
1
+ import { formatCalendarDate as formatCalendarDateImpl, getCalendarDirection as getCalendarDirectionImpl, getCalendarLocale as getCalendarLocaleImpl, getCalendarWeekdays as getCalendarWeekdaysImpl, gregorianCalendar, isCalendarRTL as isCalendarRTLImpl, } from './calendar.js';
2
+ export { gregorianCalendar } from './calendar.js';
3
+ /**
4
+ * Formats calendar fields using Timestamp's fixed `YYYY-MM-DD` date format.
5
+ *
6
+ * @param date Plain calendar date fields.
7
+ * @returns Date string in `YYYY-MM-DD` form.
8
+ * @category calendar
9
+ */
10
+ export function formatCalendarDate(date) {
11
+ return formatCalendarDateImpl(date);
12
+ }
13
+ /**
14
+ * Returns the recommended locale for a calendar system.
15
+ *
16
+ * Calendar adapters can use this to publish their normal display locale. Callers can still pass
17
+ * an explicit locale when an application needs a different language or numbering presentation.
18
+ *
19
+ * @param {CalendarSystem=} calendar Calendar system to read. Defaults to Gregorian.
20
+ * @returns {string} BCP 47 locale, defaulting to `en-US`.
21
+ * @category calendar
22
+ */
23
+ export function getCalendarLocale(calendar = gregorianCalendar) {
24
+ return getCalendarLocaleImpl(calendar);
25
+ }
26
+ /**
27
+ * Returns the recommended text direction for a calendar system.
28
+ *
29
+ * Calendar adapters can use this to publish their normal left-to-right or right-to-left
30
+ * presentation. Callers can still pass an explicit direction when an application needs one.
31
+ *
32
+ * @param {CalendarSystem=} calendar Calendar system to read. Defaults to Gregorian.
33
+ * @returns {CalendarDirection} `ltr` or `rtl`, defaulting to `ltr`.
34
+ * @category calendar
35
+ */
36
+ export function getCalendarDirection(calendar = gregorianCalendar) {
37
+ return getCalendarDirectionImpl(calendar);
38
+ }
39
+ /**
40
+ * Returns true when a calendar system recommends right-to-left presentation.
41
+ *
42
+ * @param {CalendarSystem=} calendar Calendar system to read. Defaults to Gregorian.
43
+ * @returns {boolean} True when the recommended direction is `rtl`.
44
+ * @category calendar
45
+ */
46
+ export function isCalendarRTL(calendar = gregorianCalendar) {
47
+ return isCalendarRTLImpl(calendar);
48
+ }
49
+ /**
50
+ * Returns the recommended visible weekday order for a calendar system.
51
+ *
52
+ * Calendar adapters can use this to publish their normal visible week. Callers can still pass an
53
+ * explicit weekday list for application-specific layouts such as a five-day work week.
54
+ *
55
+ * @param {CalendarSystem=} calendar Calendar system to read. Defaults to Gregorian.
56
+ * @returns {number[]} Weekday numbers where Sunday is `0` and Saturday is `6`.
57
+ * @category calendar
58
+ */
59
+ export function getCalendarWeekdays(calendar = gregorianCalendar) {
60
+ return getCalendarWeekdaysImpl(calendar);
61
+ }
3
62
  /**
4
63
  * Matches supported date and date-time input.
5
64
  *
@@ -259,26 +318,27 @@ export function parsed(input) {
259
318
  timestamp.time = getTime(timestamp);
260
319
  return freezeTimestamp(timestamp);
261
320
  }
262
- function parseDateByMode(date, utc) {
321
+ function parseDateByMode(date, utc, calendar = gregorianCalendar) {
263
322
  if (!(date instanceof Date))
264
323
  return null;
265
324
  if (Number.isNaN(date.getTime()))
266
325
  return null;
267
326
  const UTC = utc ? 'UTC' : '';
327
+ const gregorian = {
328
+ year: date[`get${UTC}FullYear`](),
329
+ month: date[`get${UTC}Month`]() + 1,
330
+ day: date[`get${UTC}Date`](),
331
+ };
268
332
  const second = date[`get${UTC}Seconds`]();
269
333
  const millisecond = date[`get${UTC}Milliseconds`]();
270
334
  const timestamp = {
271
- date: padNumber(date[`get${UTC}FullYear`](), 4) +
272
- '-' +
273
- padNumber(date[`get${UTC}Month`]() + 1, 2) +
274
- '-' +
275
- padNumber(date[`get${UTC}Date`](), 2),
335
+ date: formatCalendarDate(gregorian),
276
336
  time: padNumber(date[`get${UTC}Hours`]() || 0, 2) +
277
337
  ':' +
278
338
  padNumber(date[`get${UTC}Minutes`]() || 0, 2),
279
- year: date[`get${UTC}FullYear`](),
280
- month: date[`get${UTC}Month`]() + 1,
281
- day: date[`get${UTC}Date`](),
339
+ year: gregorian.year,
340
+ month: gregorian.month,
341
+ day: gregorian.day,
282
342
  hour: date[`get${UTC}Hours`](),
283
343
  minute: date[`get${UTC}Minutes`](),
284
344
  weekday: 0,
@@ -297,7 +357,13 @@ function parseDateByMode(date, utc) {
297
357
  if (millisecond !== 0) {
298
358
  timestamp.millisecond = millisecond;
299
359
  }
300
- return updateFormatted(timestamp);
360
+ const formatted = updateFormatted(timestamp);
361
+ if (calendar === gregorianCalendar) {
362
+ return formatted;
363
+ }
364
+ return createCalendarTimestampFromEpochDay(gregorianCalendar.toEpochDay(gregorian), calendar, {
365
+ ...getCalendarTimestampOptions(formatted),
366
+ });
301
367
  }
302
368
  /**
303
369
  * Converts a JavaScript Date into a formatted Timestamp using host-local fields.
@@ -306,11 +372,12 @@ function parseDateByMode(date, utc) {
306
372
  * with UTC getters instead of host-local getters.
307
373
  *
308
374
  * @param {Date} date JavaScript Date to convert.
375
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
309
376
  * @returns {Timestamp} Formatted Timestamp object, or `null` for invalid input.
310
377
  * @category parsing
311
378
  */
312
- export function parseDate(date) {
313
- return parseDateByMode(date, false);
379
+ export function parseDate(date, calendar = gregorianCalendar) {
380
+ return parseDateByMode(date, false, calendar);
314
381
  }
315
382
  /**
316
383
  * Converts a JavaScript Date into a formatted Timestamp using UTC fields.
@@ -319,11 +386,12 @@ export function parseDate(date) {
319
386
  * and time fields for a native Date instant.
320
387
  *
321
388
  * @param {Date} date JavaScript Date to convert.
389
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
322
390
  * @returns {Timestamp} Formatted Timestamp object, or `null` for invalid input.
323
391
  * @category parsing
324
392
  */
325
- export function parseDateUTC(date) {
326
- return parseDateByMode(date, true);
393
+ export function parseDateUTC(date, calendar = gregorianCalendar) {
394
+ return parseDateByMode(date, true, calendar);
327
395
  }
328
396
  /**
329
397
  * Pads a number to a requested string length.
@@ -344,85 +412,86 @@ export function padNumber(x, length) {
344
412
  /**
345
413
  * Returns if the passed year is a leap year
346
414
  * @param {number} year The year to check (ie: 1999, 2020)
415
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
347
416
  * @returns {boolean} True if the year is a leap year
348
417
  * @category calendar
349
418
  */
350
- export function isLeapYear(year) {
351
- return gregorianCalendar.isLeapYear(year);
419
+ export function isLeapYear(year, calendar = gregorianCalendar) {
420
+ return calendar.isLeapYear(year);
352
421
  }
353
422
  /**
354
423
  * Returns the days of the specified month in a year
355
424
  * @param {number} year The year (ie: 1999, 2020)
356
- * @param {number} month The Gregorian month number, where January is `1`
425
+ * @param {number} month The month number in the selected calendar, where January is `1` for Gregorian.
426
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
357
427
  * @returns {number} The number of days in the month (corrected for leap years)
358
428
  * @category calendar
359
429
  */
360
- export function daysInMonth(year, month) {
361
- return gregorianCalendar.daysInMonth(year, month);
430
+ export function daysInMonth(year, month, calendar = gregorianCalendar) {
431
+ return calendar.daysInMonth(year, month);
362
432
  }
363
433
  /**
364
434
  * Returns a new Timestamp for the next calendar day.
365
435
  *
366
436
  * @param {Timestamp} timestamp Base Timestamp object.
437
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
367
438
  * @returns {Timestamp} New Timestamp representing the next day.
368
439
  * @category arithmetic
369
440
  */
370
- export function nextDay(timestamp) {
371
- const date = gregorianCalendar.nextDay(toCalendarDateParts(timestamp));
372
- return updateFormatted(normalizeTimestamp({
373
- ...timestamp,
374
- year: date.year,
375
- month: date.month,
376
- day: date.day,
377
- }));
441
+ export function nextDay(timestamp, calendar = gregorianCalendar) {
442
+ return nextCalendarDay(timestamp, calendar);
378
443
  }
379
444
  /**
380
445
  * Returns a new Timestamp for the previous calendar day.
381
446
  *
382
447
  * @param {Timestamp} timestamp Base Timestamp object.
448
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
383
449
  * @returns {Timestamp} New Timestamp representing the previous day.
384
450
  * @category arithmetic
385
451
  */
386
- export function prevDay(timestamp) {
387
- const date = gregorianCalendar.prevDay(toCalendarDateParts(timestamp));
388
- return updateFormatted(normalizeTimestamp({
389
- ...timestamp,
390
- year: date.year,
391
- month: date.month,
392
- day: date.day,
393
- }));
452
+ export function prevDay(timestamp, calendar = gregorianCalendar) {
453
+ return prevCalendarDay(timestamp, calendar);
454
+ }
455
+ function formatCalendarDateFromDate(date, utc, calendar = gregorianCalendar) {
456
+ const UTC = utc ? 'UTC' : '';
457
+ const gregorian = {
458
+ year: date[`get${UTC}FullYear`](),
459
+ month: date[`get${UTC}Month`]() + 1,
460
+ day: date[`get${UTC}Date`](),
461
+ };
462
+ const epochDay = gregorianCalendar.toEpochDay(gregorian);
463
+ return formatCalendarDate(calendar.fromEpochDay(epochDay));
394
464
  }
395
465
  /**
396
466
  * Returns today's date using the host runtime timezone.
397
467
  *
398
468
  * For SSR or static rendering, server and client runtimes can produce different
399
469
  * values when they run in different timezones. Use todayUTC() when the app
400
- * wants a stable UTC calendar date instead.
470
+ * wants a stable UTC calendar date instead. Pass a calendar system to return
471
+ * today's date in that calendar's native `YYYY-MM-DD` fields.
401
472
  *
473
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
402
474
  * @returns {string} Date string in the form `YYYY-MM-DD`
403
475
  * @category state
404
476
  */
405
- export function today() {
406
- const d = new Date(), month = d.getMonth() + 1, day = d.getDate(), year = d.getFullYear();
407
- return [year, padNumber(month, 2), padNumber(day, 2)].join('-');
477
+ export function today(calendar = gregorianCalendar) {
478
+ return formatCalendarDateFromDate(new Date(), false, calendar);
408
479
  }
409
480
  /**
410
481
  * Returns today's date using UTC calendar fields.
411
482
  *
412
483
  * Pass a Date fixture to make SSR, tests, and hydration-sensitive render paths
413
484
  * deterministic. This helper reads UTC fields only; it does not convert an
414
- * existing Timestamp or timezone-suffixed string.
485
+ * existing Timestamp or timezone-suffixed string. Pass a calendar system to
486
+ * return today's UTC date in that calendar's native `YYYY-MM-DD` fields.
415
487
  *
416
488
  * @param {Date} date Date source to read. Defaults to the current Date.
489
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
417
490
  * @returns {string} UTC date string in the form `YYYY-MM-DD`
418
491
  * @category state
419
492
  */
420
- export function todayUTC(date = new Date()) {
421
- return [
422
- padNumber(date.getUTCFullYear(), 4),
423
- padNumber(date.getUTCMonth() + 1, 2),
424
- padNumber(date.getUTCDate(), 2),
425
- ].join('-');
493
+ export function todayUTC(date = new Date(), calendar = gregorianCalendar) {
494
+ return formatCalendarDateFromDate(date, true, calendar);
426
495
  }
427
496
  /**
428
497
  * Returns the current date-time as an immutable Timestamp using UTC fields.
@@ -432,20 +501,22 @@ export function todayUTC(date = new Date()) {
432
501
  * caller instead of allowing each runtime to create its own current Date.
433
502
  *
434
503
  * @param {Date} date Date source to read. Defaults to the current Date.
504
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
435
505
  * @returns {Timestamp} Immutable Timestamp built from UTC fields.
436
506
  * @category state
437
507
  */
438
- export function nowUTC(date = new Date()) {
439
- return parseDateUTC(date);
508
+ export function nowUTC(date = new Date(), calendar = gregorianCalendar) {
509
+ return parseDateUTC(date, calendar);
440
510
  }
441
511
  /**
442
512
  * Takes a date string ('YYYY-MM-DD') and validates if it is today's date
443
513
  * @param {string} date Date string in the form 'YYYY-MM-DD'
514
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
444
515
  * @returns {boolean} True if the date is today's date
445
516
  * @category comparison
446
517
  */
447
- export function isToday(date) {
448
- return date === today();
518
+ export function isToday(date, calendar = gregorianCalendar) {
519
+ return date === today(calendar);
449
520
  }
450
521
  /**
451
522
  * Checks whether a date string matches today's UTC date.
@@ -455,11 +526,12 @@ export function isToday(date) {
455
526
  *
456
527
  * @param {string} date Date string in the form `YYYY-MM-DD`.
457
528
  * @param {Date} now Date source to read. Defaults to the current Date.
529
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
458
530
  * @returns {boolean} True when the date matches the UTC date.
459
531
  * @category comparison
460
532
  */
461
- export function isTodayUTC(date, now = new Date()) {
462
- return date === todayUTC(now);
533
+ export function isTodayUTC(date, now = new Date(), calendar = gregorianCalendar) {
534
+ return date === todayUTC(now, calendar);
463
535
  }
464
536
  /**
465
537
  * Returns the start of the week for a Timestamp and weekday set.
@@ -467,25 +539,12 @@ export function isTodayUTC(date, now = new Date()) {
467
539
  * @param {Timestamp} timestamp The Timestamp to use to find the start of the week
468
540
  * @param {number[]} weekdays The array is [0,1,2,3,4,5,6] where 0=Sunday and 6=Saturday
469
541
  * @param {Timestamp=} today Current timestamp used to update relative information
542
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
470
543
  * @returns {Timestamp} A new Timestamp representing the start of the week
471
544
  * @category ranges
472
545
  */
473
- export function getStartOfWeek(timestamp, weekdays, today) {
474
- let start = cloneTimestamp(timestamp);
475
- if (!weekdays) {
476
- return freezeTimestamp(start);
477
- }
478
- if (start.day === 1 || start.weekday === 0) {
479
- while (!weekdays.includes(Number(start.weekday))) {
480
- start = nextDay(start);
481
- }
482
- }
483
- start = findWeekday(start, weekdays[0], prevDay);
484
- start = updateFormatted(start);
485
- if (today) {
486
- start = updateRelative(start, today, start.hasTime);
487
- }
488
- return start;
546
+ export function getStartOfWeek(timestamp, weekdays, today, calendar = gregorianCalendar) {
547
+ return getCalendarStartOfWeek(timestamp, weekdays, calendar, today);
489
548
  }
490
549
  /**
491
550
  * Returns the end of the week for a Timestamp and weekday set.
@@ -493,51 +552,32 @@ export function getStartOfWeek(timestamp, weekdays, today) {
493
552
  * @param {Timestamp} timestamp The Timestamp to use to find the end of the week
494
553
  * @param {number[]} weekdays The array is [0,1,2,3,4,5,6] where 0=Sunday and 6=Saturday
495
554
  * @param {Timestamp=} today Current timestamp used to update relative information
555
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
496
556
  * @returns {Timestamp} A new Timestamp representing the end of the week
497
557
  * @category ranges
498
558
  */
499
- export function getEndOfWeek(timestamp, weekdays, today) {
500
- let end = cloneTimestamp(timestamp);
501
- if (!weekdays || !Array.isArray(weekdays)) {
502
- return freezeTimestamp(end);
503
- }
504
- // is last day of month?
505
- const lastDay = daysInMonth(end.year, end.month);
506
- if (lastDay === end.day || end.weekday === weekdays[weekdays.length - 1]) {
507
- while (!weekdays.includes(Number(end.weekday))) {
508
- end = prevDay(end);
509
- }
510
- }
511
- end = findWeekday(end, weekdays[weekdays.length - 1], nextDay);
512
- end = updateFormatted(end);
513
- if (today) {
514
- end = updateRelative(end, today, end.hasTime);
515
- }
516
- return end;
559
+ export function getEndOfWeek(timestamp, weekdays, today, calendar = gregorianCalendar) {
560
+ return getCalendarEndOfWeek(timestamp, weekdays, calendar, today);
517
561
  }
518
562
  /**
519
563
  * Finds the start of the month based on the passed in Timestamp
520
564
  * @param {Timestamp} timestamp The Timestamp to use to find the start of the month
565
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
521
566
  * @returns {Timestamp} A Timestamp of the start of the month
522
567
  * @category ranges
523
568
  */
524
- export function getStartOfMonth(timestamp) {
525
- let start = cloneTimestamp(timestamp);
526
- start.day = DAY_MIN;
527
- start = updateFormatted(start);
528
- return start;
569
+ export function getStartOfMonth(timestamp, calendar = gregorianCalendar) {
570
+ return getCalendarStartOfMonth(timestamp, calendar);
529
571
  }
530
572
  /**
531
573
  * Finds the end of the month based on the passed in Timestamp
532
574
  * @param {Timestamp} timestamp The Timestamp to use to find the end of the month
575
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
533
576
  * @returns {Timestamp} A Timestamp of the end of the month
534
577
  * @category ranges
535
578
  */
536
- export function getEndOfMonth(timestamp) {
537
- let end = cloneTimestamp(timestamp);
538
- end.day = daysInMonth(end.year, end.month);
539
- end = updateFormatted(end);
540
- return end;
579
+ export function getEndOfMonth(timestamp, calendar = gregorianCalendar) {
580
+ return getCalendarEndOfMonth(timestamp, calendar);
541
581
  }
542
582
  /**
543
583
  * Converts time input into minutes since midnight.
@@ -671,7 +711,7 @@ export function getDayIdentifier(timestamp) {
671
711
  * same serial day space so ranges and comparisons can be calendar-agnostic.
672
712
  *
673
713
  * @param {Timestamp} timestamp Timestamp object to read.
674
- * @param {CalendarSystem=} calendar Calendar implementation to use.
714
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
675
715
  * @returns {number} Stable serial day.
676
716
  * @category conversion
677
717
  */
@@ -685,18 +725,43 @@ export function getEpochDay(timestamp, calendar = gregorianCalendar) {
685
725
  * range comparisons, or virtualized day rows across different calendar adapters.
686
726
  *
687
727
  * @param timestamp Timestamp object to read.
688
- * @param calendar Calendar implementation to use.
728
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
689
729
  * @returns Stable serial day.
690
730
  * @category calendar
691
731
  */
692
732
  export function getCalendarDayIdentifier(timestamp, calendar = gregorianCalendar) {
693
733
  return getEpochDay(timestamp, calendar);
694
734
  }
735
+ /**
736
+ * Creates stable native and Gregorian identities for a calendar timestamp.
737
+ *
738
+ * Use this when component APIs need to expose adapter-native values while also
739
+ * preserving a canonical Gregorian key for storage, comparisons, or interop
740
+ * with existing data.
741
+ *
742
+ * @param timestamp Timestamp object to identify.
743
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
744
+ * @returns Calendar-native date, Gregorian interop date, and shared epoch day.
745
+ * @category calendar
746
+ */
747
+ export function getCalendarDateIdentity(timestamp, calendar = gregorianCalendar) {
748
+ const native = toCalendarDateParts(timestamp);
749
+ const epochDay = calendar.toEpochDay(native);
750
+ const gregorian = gregorianCalendar.fromEpochDay(epochDay);
751
+ return Object.freeze({
752
+ calendarId: calendar.id,
753
+ nativeDate: formatCalendarDate(native),
754
+ native,
755
+ gregorianDate: formatCalendarDate(gregorian),
756
+ gregorian,
757
+ epochDay,
758
+ });
759
+ }
695
760
  /**
696
761
  * Returns true when calendar date fields are valid for a calendar system.
697
762
  *
698
763
  * @param date Calendar date fields to validate.
699
- * @param calendar Calendar implementation to use.
764
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
700
765
  * @returns True when year, month, and day can exist in the calendar.
701
766
  * @category calendar
702
767
  */
@@ -714,7 +779,7 @@ export function isValidCalendarDate(date, calendar = gregorianCalendar) {
714
779
  * `calendarId`, and derives weekday/day-of-year values from the adapter.
715
780
  *
716
781
  * @param date Calendar date fields.
717
- * @param calendar Calendar implementation to use.
782
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
718
783
  * @param options Optional time and relative comparison settings.
719
784
  * @returns Timestamp-shaped calendar value.
720
785
  * @category calendar
@@ -760,7 +825,7 @@ export function createCalendarTimestamp(date, calendar = gregorianCalendar, opti
760
825
  * calendar and derives weekday/day-of-year values through the adapter.
761
826
  *
762
827
  * @param input Date or date-time string.
763
- * @param calendar Calendar implementation to use.
828
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
764
829
  * @param now Optional comparison timestamp from the same calendar system.
765
830
  * @returns Calendar timestamp, or `null` when the input cannot be parsed or validated.
766
831
  * @category calendar
@@ -777,11 +842,26 @@ export function parseCalendarTimestamp(input, calendar = gregorianCalendar, now
777
842
  now,
778
843
  });
779
844
  }
845
+ /**
846
+ * Validates whether an input string can be parsed as a calendar adapter timestamp.
847
+ *
848
+ * The default Gregorian calendar preserves existing Timestamp semantics. When
849
+ * an alternate calendar is supplied, `YYYY-MM-DD` is interpreted as native to
850
+ * that adapter.
851
+ *
852
+ * @param input Date or date-time string.
853
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
854
+ * @returns True when the string can be parsed and exists in the calendar.
855
+ * @category calendar
856
+ */
857
+ export function validateCalendarTimestamp(input, calendar = gregorianCalendar) {
858
+ return parseCalendarTimestamp(input, calendar) !== null;
859
+ }
780
860
  /**
781
861
  * Creates a calendar timestamp from a stable serial day.
782
862
  *
783
863
  * @param epochDay Stable serial day.
784
- * @param calendar Calendar implementation to use.
864
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
785
865
  * @param options Optional time and relative comparison settings.
786
866
  * @returns Timestamp-shaped calendar value.
787
867
  * @category calendar
@@ -793,7 +873,7 @@ export function createCalendarTimestampFromEpochDay(epochDay, calendar = gregori
793
873
  * Updates formatted calendar metadata on a timestamp-shaped value.
794
874
  *
795
875
  * @param timestamp Timestamp object to transform.
796
- * @param calendar Calendar implementation to use.
876
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
797
877
  * @returns Timestamp with adapter date formatting and metadata.
798
878
  * @category calendar
799
879
  */
@@ -805,7 +885,7 @@ export function updateCalendarFormatted(timestamp, calendar = gregorianCalendar)
805
885
  *
806
886
  * @param timestamp Timestamp object to update.
807
887
  * @param now Timestamp representing the comparison point in the same calendar.
808
- * @param calendar Calendar implementation to use.
888
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
809
889
  * @param time Include time-of-day in the comparison when true.
810
890
  * @returns New Timestamp object with relative flags.
811
891
  * @category calendar
@@ -830,7 +910,7 @@ export function updateCalendarRelative(timestamp, now, calendar = gregorianCalen
830
910
  * Returns a calendar timestamp for the next day.
831
911
  *
832
912
  * @param timestamp Base timestamp.
833
- * @param calendar Calendar implementation to use.
913
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
834
914
  * @returns New timestamp for the next adapter day.
835
915
  * @category calendar
836
916
  */
@@ -841,7 +921,7 @@ export function nextCalendarDay(timestamp, calendar = gregorianCalendar) {
841
921
  * Returns a calendar timestamp for the previous day.
842
922
  *
843
923
  * @param timestamp Base timestamp.
844
- * @param calendar Calendar implementation to use.
924
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
845
925
  * @returns New timestamp for the previous adapter day.
846
926
  * @category calendar
847
927
  */
@@ -853,7 +933,7 @@ export function prevCalendarDay(timestamp, calendar = gregorianCalendar) {
853
933
  *
854
934
  * @param timestamp Base timestamp.
855
935
  * @param amount Number of days to move.
856
- * @param calendar Calendar implementation to use.
936
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
857
937
  * @returns New timestamp after moving.
858
938
  * @category calendar
859
939
  */
@@ -865,7 +945,7 @@ export function addCalendarDays(timestamp, amount, calendar = gregorianCalendar)
865
945
  *
866
946
  * @param timestamp Base timestamp.
867
947
  * @param amount Number of calendar months to move.
868
- * @param calendar Calendar implementation to use.
948
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
869
949
  * @returns New timestamp after moving.
870
950
  * @category calendar
871
951
  */
@@ -896,7 +976,7 @@ export function addCalendarMonths(timestamp, amount, calendar = gregorianCalenda
896
976
  *
897
977
  * @param timestamp Base timestamp.
898
978
  * @param amount Number of calendar years to move.
899
- * @param calendar Calendar implementation to use.
979
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
900
980
  * @returns New timestamp after moving.
901
981
  * @category calendar
902
982
  */
@@ -911,7 +991,7 @@ export function addCalendarYears(timestamp, amount, calendar = gregorianCalendar
911
991
  * Returns the start of the calendar month for a timestamp.
912
992
  *
913
993
  * @param timestamp Base timestamp.
914
- * @param calendar Calendar implementation to use.
994
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
915
995
  * @returns First day of the adapter month.
916
996
  * @category calendar
917
997
  */
@@ -922,7 +1002,7 @@ export function getCalendarStartOfMonth(timestamp, calendar = gregorianCalendar)
922
1002
  * Returns the end of the calendar month for a timestamp.
923
1003
  *
924
1004
  * @param timestamp Base timestamp.
925
- * @param calendar Calendar implementation to use.
1005
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
926
1006
  * @returns Last day of the adapter month.
927
1007
  * @category calendar
928
1008
  */
@@ -937,7 +1017,7 @@ export function getCalendarEndOfMonth(timestamp, calendar = gregorianCalendar) {
937
1017
  * Returns the start of the calendar year for a timestamp.
938
1018
  *
939
1019
  * @param timestamp Base timestamp.
940
- * @param calendar Calendar implementation to use.
1020
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
941
1021
  * @returns First day of the adapter year.
942
1022
  * @category calendar
943
1023
  */
@@ -948,7 +1028,7 @@ export function getCalendarStartOfYear(timestamp, calendar = gregorianCalendar)
948
1028
  * Returns the end of the calendar year for a timestamp.
949
1029
  *
950
1030
  * @param timestamp Base timestamp.
951
- * @param calendar Calendar implementation to use.
1031
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
952
1032
  * @returns Last day of the adapter year.
953
1033
  * @category calendar
954
1034
  */
@@ -961,7 +1041,7 @@ export function getCalendarEndOfYear(timestamp, calendar = gregorianCalendar) {
961
1041
  *
962
1042
  * @param timestamp Base timestamp.
963
1043
  * @param weekday Weekday number to find.
964
- * @param calendar Calendar implementation to use.
1044
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
965
1045
  * @param direction Direction to search.
966
1046
  * @param maxDays Maximum days to inspect.
967
1047
  * @returns Matching timestamp, or the last inspected timestamp.
@@ -980,7 +1060,7 @@ export function findCalendarWeekday(timestamp, weekday, calendar = gregorianCale
980
1060
  *
981
1061
  * @param timestamp Base timestamp.
982
1062
  * @param weekdays Weekday numbers to include, from `0` Sunday to `6` Saturday.
983
- * @param calendar Calendar implementation to use.
1063
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
984
1064
  * @param now Optional comparison timestamp from the same calendar.
985
1065
  * @returns Start of the adapter week.
986
1066
  * @category calendar
@@ -1003,7 +1083,7 @@ export function getCalendarStartOfWeek(timestamp, weekdays, calendar = gregorian
1003
1083
  *
1004
1084
  * @param timestamp Base timestamp.
1005
1085
  * @param weekdays Weekday numbers to include, from `0` Sunday to `6` Saturday.
1006
- * @param calendar Calendar implementation to use.
1086
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1007
1087
  * @param now Optional comparison timestamp from the same calendar.
1008
1088
  * @returns End of the adapter week.
1009
1089
  * @category calendar
@@ -1028,7 +1108,7 @@ export function getCalendarEndOfWeek(timestamp, weekdays, calendar = gregorianCa
1028
1108
  * @param start First day in the list.
1029
1109
  * @param end Last day boundary for the list.
1030
1110
  * @param now Timestamp used to calculate relative flags.
1031
- * @param calendar Calendar implementation to use.
1111
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1032
1112
  * @param options Optional weekday, disabled, and size filters.
1033
1113
  * @returns Timestamp days for the adapter calendar.
1034
1114
  * @category calendar
@@ -1056,12 +1136,28 @@ export function createCalendarDayList(start, end, now, calendar = gregorianCalen
1056
1136
  }
1057
1137
  let day = updateCalendarFormatted(current, calendar);
1058
1138
  day = updateCalendarRelative(day, now, calendar);
1059
- day = updateDisabled(day, disabledBefore, disabledAfter, disabledWeekdays, disabledDays);
1139
+ day = updateCalendarDisabled(day, disabledBefore, disabledAfter, disabledWeekdays, disabledDays, calendar);
1060
1140
  days.push(day);
1061
1141
  current = nextCalendarDay(current, calendar);
1062
1142
  }
1063
1143
  return days;
1064
1144
  }
1145
+ /**
1146
+ * Returns true when a timestamp falls outside the reference timestamp's adapter month.
1147
+ *
1148
+ * @param timestamp Timestamp to test.
1149
+ * @param reference Timestamp whose month defines the inside range.
1150
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1151
+ * @returns True when timestamp is outside reference's calendar month.
1152
+ * @category calendar
1153
+ */
1154
+ export function isOutsideCalendarMonth(timestamp, reference, calendar = gregorianCalendar) {
1155
+ const start = getCalendarStartOfMonth(reference, calendar);
1156
+ const end = getCalendarEndOfMonth(reference, calendar);
1157
+ const targetIdentifier = getCalendarDayIdentifier(timestamp, calendar);
1158
+ return (targetIdentifier < getCalendarDayIdentifier(start, calendar) ||
1159
+ targetIdentifier > getCalendarDayIdentifier(end, calendar));
1160
+ }
1065
1161
  /**
1066
1162
  * Converts a Timestamp time into a sortable numeric identifier.
1067
1163
  *
@@ -1117,13 +1213,14 @@ export function diffTimestamp(ts1, ts2, strict = false) {
1117
1213
  * @param {Timestamp} timestamp Timestamp object to update.
1118
1214
  * @param {Timestamp} now Timestamp representing the comparison point.
1119
1215
  * @param {boolean=} time Include time-of-day in the comparison when true.
1216
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1120
1217
  * @returns {Timestamp} New Timestamp object with relative flags.
1121
1218
  * @category state
1122
1219
  */
1123
- export function updateRelative(timestamp, now, time = false) {
1220
+ export function updateRelative(timestamp, now, time = false, calendar = gregorianCalendar) {
1124
1221
  const ts = cloneTimestamp(timestamp);
1125
- let a = getDayIdentifier(now);
1126
- let b = getDayIdentifier(ts);
1222
+ let a = getCalendarDayIdentifier(now, calendar);
1223
+ let b = getCalendarDayIdentifier(ts, calendar);
1127
1224
  let current = a === b;
1128
1225
  if (ts.hasTime && time && current) {
1129
1226
  a = getTimeComparisonValue(now);
@@ -1145,10 +1242,11 @@ export function updateRelative(timestamp, now, time = false) {
1145
1242
  * @param {Timestamp} timestamp The Timestamp to transform
1146
1243
  * @param {number} minutes The number of minutes to set from midnight
1147
1244
  * @param {Timestamp=} now Optional Timestamp representing current date and time
1245
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1148
1246
  * @returns {Timestamp} A new Timestamp
1149
1247
  * @category arithmetic
1150
1248
  */
1151
- export function updateMinutes(timestamp, minutes, now = null) {
1249
+ export function updateMinutes(timestamp, minutes, now = null, calendar = gregorianCalendar) {
1152
1250
  let ts = cloneTimestamp(timestamp);
1153
1251
  ts.hasTime = true;
1154
1252
  ts.hour = Math.floor(minutes / TIME_CONSTANTS.MINUTES_IN.HOUR);
@@ -1157,41 +1255,44 @@ export function updateMinutes(timestamp, minutes, now = null) {
1157
1255
  delete ts.millisecond;
1158
1256
  ts.time = getTime(ts);
1159
1257
  if (now) {
1160
- return updateRelative(ts, now, true);
1258
+ return updateRelative(ts, now, true, calendar);
1161
1259
  }
1162
1260
  return freezeTimestamp(ts);
1163
1261
  }
1164
1262
  /**
1165
1263
  * Updates the Timestamp with the weekday
1166
1264
  * @param {Timestamp} timestamp The Timestamp to transform
1265
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1167
1266
  * @returns A new Timestamp
1168
1267
  * @category formatting
1169
1268
  */
1170
- export function updateWeekday(timestamp) {
1269
+ export function updateWeekday(timestamp, calendar = gregorianCalendar) {
1171
1270
  const ts = cloneTimestamp(timestamp);
1172
- ts.weekday = getWeekday(ts);
1271
+ ts.weekday = getWeekday(ts, calendar);
1173
1272
  return freezeTimestamp(ts);
1174
1273
  }
1175
1274
  /**
1176
1275
  * Updates the Timestamp with the day of the year (doy)
1177
1276
  * @param {Timestamp} timestamp The Timestamp to transform
1277
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1178
1278
  * @returns A new Timestamp
1179
1279
  * @category formatting
1180
1280
  */
1181
- export function updateDayOfYear(timestamp) {
1281
+ export function updateDayOfYear(timestamp, calendar = gregorianCalendar) {
1182
1282
  const ts = cloneTimestamp(timestamp);
1183
- ts.doy = getDayOfYear(ts) || 0;
1283
+ ts.doy = getDayOfYear(ts, calendar) || 0;
1184
1284
  return freezeTimestamp(ts);
1185
1285
  }
1186
1286
  /**
1187
1287
  * Updates the Timestamp with the workweek
1188
1288
  * @param {Timestamp} timestamp The Timestamp to transform
1289
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1189
1290
  * @returns A new Timestamp
1190
1291
  * @category formatting
1191
1292
  */
1192
- export function updateWorkWeek(timestamp) {
1293
+ export function updateWorkWeek(timestamp, calendar = gregorianCalendar) {
1193
1294
  const ts = cloneTimestamp(timestamp);
1194
- ts.workweek = getWorkWeek(ts);
1295
+ ts.workweek = getWorkWeek(ts, calendar);
1195
1296
  return freezeTimestamp(ts);
1196
1297
  }
1197
1298
  function isDisabledDayConfig(value) {
@@ -1239,6 +1340,42 @@ function isTimestampInDisabledDay(timestamp, day) {
1239
1340
  const disabledDay = parseTimestamp(day);
1240
1341
  return disabledDay !== null && getDayIdentifier(disabledDay) === target;
1241
1342
  }
1343
+ function parseCalendarDateIdentifier(value, calendar) {
1344
+ const timestamp = parseCalendarTimestamp(value, calendar);
1345
+ return timestamp === null ? null : getCalendarDayIdentifier(timestamp, calendar);
1346
+ }
1347
+ function isTimestampInCalendarDisabledDay(timestamp, day, calendar) {
1348
+ const target = getCalendarDayIdentifier(timestamp, calendar);
1349
+ if (Array.isArray(day) === true) {
1350
+ if (day.length === 2 && day[0] && day[1]) {
1351
+ const start = parseCalendarDateIdentifier(day[0], calendar);
1352
+ const end = parseCalendarDateIdentifier(day[1], calendar);
1353
+ return (start !== null &&
1354
+ end !== null &&
1355
+ target >= Math.min(start, end) &&
1356
+ target <= Math.max(start, end));
1357
+ }
1358
+ return day.some((date) => parseCalendarDateIdentifier(date, calendar) === target);
1359
+ }
1360
+ if (isDisabledDayConfig(day) === true) {
1361
+ const date = day.date;
1362
+ const startDate = day.from ?? day.start;
1363
+ const endDate = day.to ?? day.end;
1364
+ if (date !== undefined) {
1365
+ return parseCalendarDateIdentifier(date, calendar) === target;
1366
+ }
1367
+ if (startDate !== undefined && endDate !== undefined) {
1368
+ const start = parseCalendarDateIdentifier(startDate, calendar);
1369
+ const end = parseCalendarDateIdentifier(endDate, calendar);
1370
+ return (start !== null &&
1371
+ end !== null &&
1372
+ target >= Math.min(start, end) &&
1373
+ target <= Math.max(start, end));
1374
+ }
1375
+ return false;
1376
+ }
1377
+ return parseCalendarDateIdentifier(day, calendar) === target;
1378
+ }
1242
1379
  /**
1243
1380
  * Updates the passed Timestamp with disabled, if needed
1244
1381
  * @param {Timestamp} timestamp The Timestamp to transform
@@ -1288,47 +1425,218 @@ export function updateDisabled(timestamp, disabledBefore, disabledAfter, disable
1288
1425
  }
1289
1426
  return freezeTimestamp(ts);
1290
1427
  }
1428
+ /**
1429
+ * Updates a timestamp with disabled state using calendar-native date strings.
1430
+ *
1431
+ * The default Gregorian calendar preserves existing Timestamp behavior. When
1432
+ * an alternate calendar is supplied, `disabledBefore`, `disabledAfter`, and
1433
+ * `disabledDays` are parsed as native dates for that adapter.
1434
+ *
1435
+ * @param timestamp Timestamp to transform.
1436
+ * @param disabledBefore Disable days on or before this adapter date.
1437
+ * @param disabledAfter Disable days on or after this adapter date.
1438
+ * @param disabledWeekdays Weekday numbers to mark disabled.
1439
+ * @param disabledDays Specific adapter dates or date ranges to mark disabled.
1440
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1441
+ * @returns New timestamp with disabled metadata applied.
1442
+ * @category calendar
1443
+ */
1444
+ export function updateCalendarDisabled(timestamp, disabledBefore, disabledAfter, disabledWeekdays, disabledDays, calendar = gregorianCalendar) {
1445
+ let ts = cloneTimestamp(timestamp);
1446
+ const target = getCalendarDayIdentifier(ts, calendar);
1447
+ if (disabledBefore !== undefined) {
1448
+ const before = parseCalendarDateIdentifier(disabledBefore, calendar);
1449
+ if (before !== null && target <= before) {
1450
+ ts.disabled = true;
1451
+ }
1452
+ }
1453
+ if (ts.disabled !== true && disabledAfter !== undefined) {
1454
+ const after = parseCalendarDateIdentifier(disabledAfter, calendar);
1455
+ if (after !== null && target >= after) {
1456
+ ts.disabled = true;
1457
+ }
1458
+ }
1459
+ if (ts.disabled !== true && Array.isArray(disabledWeekdays) && disabledWeekdays.length > 0) {
1460
+ for (const weekday of disabledWeekdays) {
1461
+ if (weekday === ts.weekday) {
1462
+ ts.disabled = true;
1463
+ break;
1464
+ }
1465
+ }
1466
+ }
1467
+ if (ts.disabled !== true && Array.isArray(disabledDays) && disabledDays.length > 0) {
1468
+ for (const day of disabledDays) {
1469
+ if (isTimestampInCalendarDisabledDay(ts, day, calendar) === true) {
1470
+ ts = applyDisabledDayConfig(ts, isDisabledDayConfig(day) === true ? day : undefined);
1471
+ break;
1472
+ }
1473
+ }
1474
+ }
1475
+ return freezeTimestamp(ts);
1476
+ }
1477
+ function isTimestampInCalendarDateCollection(timestamp, dates, calendar) {
1478
+ if (dates === undefined) {
1479
+ return false;
1480
+ }
1481
+ const target = getCalendarDayIdentifier(timestamp, calendar);
1482
+ for (const date of dates) {
1483
+ if (parseCalendarDateIdentifier(date, calendar) === target) {
1484
+ return true;
1485
+ }
1486
+ }
1487
+ return false;
1488
+ }
1489
+ /**
1490
+ * Resolves selected-date and selected-range state for a calendar timestamp.
1491
+ *
1492
+ * The default Gregorian calendar preserves existing Timestamp behavior. When
1493
+ * an alternate calendar is supplied, selected date strings are parsed as native
1494
+ * adapter dates.
1495
+ *
1496
+ * @param timestamp Timestamp to inspect.
1497
+ * @param options Selected dates and selected start/end dates.
1498
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1499
+ * @returns Selected-date state for the timestamp.
1500
+ * @category calendar
1501
+ */
1502
+ export function getCalendarSelectionState(timestamp, options = {}, calendar = gregorianCalendar) {
1503
+ const selectedDate = isTimestampInCalendarDateCollection(timestamp, options.selectedDates, calendar);
1504
+ const target = getCalendarDayIdentifier(timestamp, calendar);
1505
+ const rangeBoundaryDates = options.selectedStartEndDates ?? [];
1506
+ let rangeFirst = false;
1507
+ let range = false;
1508
+ let rangeLast = false;
1509
+ if (rangeBoundaryDates.length === 2 && rangeBoundaryDates[0] && rangeBoundaryDates[1]) {
1510
+ const first = parseCalendarDateIdentifier(rangeBoundaryDates[0], calendar);
1511
+ const last = parseCalendarDateIdentifier(rangeBoundaryDates[1], calendar);
1512
+ if (first !== null && last !== null) {
1513
+ const start = Math.min(first, last);
1514
+ const end = Math.max(first, last);
1515
+ rangeFirst = target === start;
1516
+ rangeLast = target === end;
1517
+ range = target > start && target < end;
1518
+ }
1519
+ }
1520
+ return Object.freeze({
1521
+ selectedDate,
1522
+ rangeFirst,
1523
+ range,
1524
+ rangeLast,
1525
+ selected: selectedDate || rangeFirst || range || rangeLast,
1526
+ });
1527
+ }
1528
+ /**
1529
+ * Resolves disabled, selected, identity, and outside-month state for one date.
1530
+ *
1531
+ * @param timestamp Timestamp to resolve.
1532
+ * @param options Calendar-aware disabled, selection, and outside-month options.
1533
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1534
+ * @returns Calendar date state suitable for component scopes.
1535
+ * @category calendar
1536
+ */
1537
+ export function getCalendarDateState(timestamp, options = {}, calendar = gregorianCalendar) {
1538
+ const disabledTimestamp = updateCalendarDisabled(timestamp, options.disabledBefore, options.disabledAfter, options.disabledWeekdays, options.disabledDays, calendar);
1539
+ const selection = getCalendarSelectionState(disabledTimestamp, options, calendar);
1540
+ const outside = options.outside ??
1541
+ (options.referenceMonth === undefined
1542
+ ? false
1543
+ : isOutsideCalendarMonth(disabledTimestamp, options.referenceMonth, calendar));
1544
+ return Object.freeze({
1545
+ timestamp: disabledTimestamp,
1546
+ identity: getCalendarDateIdentity(disabledTimestamp, calendar),
1547
+ outside,
1548
+ disabled: disabledTimestamp.disabled === true,
1549
+ ...selection,
1550
+ });
1551
+ }
1552
+ /**
1553
+ * Creates native calendar month view state for component rendering.
1554
+ *
1555
+ * The returned `days` use adapter-native `YYYY-MM-DD` values, while each
1556
+ * state's identity also includes Gregorian interop metadata.
1557
+ *
1558
+ * @param timestamp Reference timestamp in the adapter calendar.
1559
+ * @param now Timestamp used to calculate relative flags.
1560
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1561
+ * @param options Calendar-aware disabled, selection, weekday, and size options.
1562
+ * @returns Calendar month view state.
1563
+ * @category calendar
1564
+ */
1565
+ export function createCalendarMonthView(timestamp, now, calendar = gregorianCalendar, options = {}) {
1566
+ const weekdays = options.weekdays ?? [0, 1, 2, 3, 4, 5, 6];
1567
+ const reference = updateCalendarFormatted(timestamp, calendar);
1568
+ const start = getCalendarStartOfMonth(reference, calendar);
1569
+ const end = getCalendarEndOfMonth(reference, calendar);
1570
+ const visibleStart = getCalendarStartOfWeek(start, weekdays, calendar, now);
1571
+ const visibleEnd = getCalendarEndOfWeek(end, weekdays, calendar, now);
1572
+ const days = createCalendarDayList(visibleStart, visibleEnd, now, calendar, {
1573
+ weekdays,
1574
+ disabledBefore: options.disabledBefore,
1575
+ disabledAfter: options.disabledAfter,
1576
+ disabledWeekdays: options.disabledWeekdays,
1577
+ disabledDays: options.disabledDays,
1578
+ max: options.max ?? weekdays.length * 6,
1579
+ min: options.min ?? weekdays.length * 6,
1580
+ }).map((day) => getCalendarDateState(day, {
1581
+ ...options,
1582
+ referenceMonth: reference,
1583
+ }, calendar));
1584
+ return Object.freeze({
1585
+ reference,
1586
+ start,
1587
+ end,
1588
+ visibleStart,
1589
+ visibleEnd,
1590
+ days,
1591
+ });
1592
+ }
1291
1593
  /**
1292
1594
  * Updates the passed Timestamp with formatted data (time string, date string, weekday, day of year and workweek)
1293
1595
  * @param {Timestamp} timestamp The Timestamp to transform
1596
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1294
1597
  * @returns A new Timestamp
1295
1598
  * @category formatting
1296
1599
  */
1297
- export function updateFormatted(timestamp) {
1600
+ export function updateFormatted(timestamp, calendar = gregorianCalendar) {
1298
1601
  const ts = cloneTimestamp(timestamp);
1299
1602
  ts.hasTime = true;
1300
1603
  ts.time = getTime(ts);
1301
1604
  ts.date = getDate(ts);
1302
- ts.weekday = getWeekday(ts);
1303
- ts.doy = getDayOfYear(ts) || 0;
1304
- ts.workweek = getWorkWeek(ts);
1605
+ ts.weekday = getWeekday(ts, calendar);
1606
+ ts.doy = getDayOfYear(ts, calendar) || 0;
1607
+ ts.workweek = getWorkWeek(ts, calendar);
1305
1608
  return freezeTimestamp(ts);
1306
1609
  }
1307
1610
  /**
1308
1611
  * Returns day of the year (doy) for the passed in Timestamp
1309
1612
  * @param {Timestamp} timestamp The Timestamp to use
1613
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1310
1614
  * @returns {number} The day of the year
1311
1615
  * @category formatting
1312
1616
  */
1313
- export function getDayOfYear(timestamp) {
1617
+ export function getDayOfYear(timestamp, calendar = gregorianCalendar) {
1314
1618
  if (timestamp.year === 0)
1315
1619
  return;
1316
- return gregorianCalendar.getDayOfYear(toCalendarDateParts(timestamp));
1620
+ return calendar.getDayOfYear(toCalendarDateParts(timestamp));
1317
1621
  }
1318
1622
  /**
1319
1623
  * Returns workweek for the passed in Timestamp
1320
1624
  * @param {Timestamp} timestamp The Timestamp to use
1625
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1321
1626
  * @returns {number} The work week
1322
1627
  * @category formatting
1323
1628
  */
1324
- export function getWorkWeek(timestamp) {
1629
+ export function getWorkWeek(timestamp, calendar = gregorianCalendar) {
1325
1630
  let ts = timestamp;
1326
1631
  if (ts.year === 0) {
1327
- const parsedToday = parseTimestamp(today());
1632
+ const parsedToday = parseCalendarTimestamp(today(calendar), calendar);
1328
1633
  if (parsedToday) {
1329
1634
  ts = parsedToday;
1330
1635
  }
1331
1636
  }
1637
+ if (calendar !== gregorianCalendar) {
1638
+ return getCalendarWorkWeek(toCalendarDateParts(ts), calendar);
1639
+ }
1332
1640
  // Remove time components of date
1333
1641
  const weekday = new Date(Date.UTC(ts.year, ts.month - 1, ts.day));
1334
1642
  // Adjust the date to the correct day of the week
@@ -1346,13 +1654,14 @@ export function getWorkWeek(timestamp) {
1346
1654
  /**
1347
1655
  * Returns weekday for the passed in Timestamp
1348
1656
  * @param {Timestamp} timestamp The Timestamp to use
1657
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1349
1658
  * @returns {number} The weekday
1350
1659
  * @category formatting
1351
1660
  */
1352
- export function getWeekday(timestamp) {
1661
+ export function getWeekday(timestamp, calendar = gregorianCalendar) {
1353
1662
  let weekday = timestamp.weekday;
1354
1663
  if (timestamp.hasDay) {
1355
- weekday = gregorianCalendar.getWeekday(toCalendarDateParts(timestamp));
1664
+ weekday = calendar.getWeekday(toCalendarDateParts(timestamp));
1356
1665
  }
1357
1666
  return weekday ?? 0;
1358
1667
  }
@@ -1406,30 +1715,26 @@ export function getEndOfDay(timestamp) {
1406
1715
  return setTimeParts(timestamp, 23, 59, 59, 999);
1407
1716
  }
1408
1717
  /**
1409
- * Returns a Timestamp at the start of the same Gregorian year.
1718
+ * Returns a Timestamp at the start of the same calendar year.
1410
1719
  *
1411
1720
  * @param {Timestamp} timestamp Timestamp object to transform.
1412
- * @returns {Timestamp} New Timestamp for January 1 at `00:00`.
1721
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1722
+ * @returns {Timestamp} New Timestamp for the first calendar day of the year at `00:00`.
1413
1723
  * @category ranges
1414
1724
  */
1415
- export function getStartOfYear(timestamp) {
1416
- const ts = cloneTimestamp(timestamp);
1417
- ts.month = MONTH_MIN;
1418
- ts.day = DAY_MIN;
1419
- return getStartOfDay(updateFormatted(ts));
1725
+ export function getStartOfYear(timestamp, calendar = gregorianCalendar) {
1726
+ return getStartOfDay(getCalendarStartOfYear(timestamp, calendar));
1420
1727
  }
1421
1728
  /**
1422
- * Returns a Timestamp at the end of the same Gregorian year.
1729
+ * Returns a Timestamp at the end of the same calendar year.
1423
1730
  *
1424
1731
  * @param {Timestamp} timestamp Timestamp object to transform.
1425
- * @returns {Timestamp} New Timestamp for December 31 at `23:59:59.999`.
1732
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1733
+ * @returns {Timestamp} New Timestamp for the last calendar day of the year at `23:59:59.999`.
1426
1734
  * @category ranges
1427
1735
  */
1428
- export function getEndOfYear(timestamp) {
1429
- const ts = cloneTimestamp(timestamp);
1430
- ts.month = MONTH_MAX;
1431
- ts.day = daysInMonth(ts.year, MONTH_MAX);
1432
- return getEndOfDay(updateFormatted(ts));
1736
+ export function getEndOfYear(timestamp, calendar = gregorianCalendar) {
1737
+ return getEndOfDay(getCalendarEndOfYear(timestamp, calendar));
1433
1738
  }
1434
1739
  /**
1435
1740
  * Formats the date portion of a Timestamp object.
@@ -1483,11 +1788,12 @@ export function getDateTime(timestamp) {
1483
1788
  * @param {function} [mover=nextDay] The mover function to use (ie: {nextDay} or {prevDay}).
1484
1789
  * @param {number} [days=1] The number of days to move.
1485
1790
  * @param {number[]} [allowedWeekdays=[ 0, 1, 2, 3, 4, 5, 6 ]] An array of numbers representing the weekdays. ie: [0 = Sun, ..., 6 = Sat].
1791
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1486
1792
  * @returns A new Timestamp
1487
1793
  * @category ranges
1488
1794
  */
1489
- export function moveRelativeDays(timestamp, mover = nextDay, days = 1, allowedWeekdays = [0, 1, 2, 3, 4, 5, 6]) {
1490
- return relativeDays(timestamp, mover, days, allowedWeekdays);
1795
+ export function moveRelativeDays(timestamp, mover = nextDay, days = 1, allowedWeekdays = [0, 1, 2, 3, 4, 5, 6], calendar = gregorianCalendar) {
1796
+ return relativeDays(timestamp, mover, days, allowedWeekdays, calendar);
1491
1797
  }
1492
1798
  /**
1493
1799
  * Moves the Timestamp the number of relative days
@@ -1495,16 +1801,17 @@ export function moveRelativeDays(timestamp, mover = nextDay, days = 1, allowedWe
1495
1801
  * @param {function} [mover=nextDay] The mover function to use (ie: {nextDay} or {prevDay}).
1496
1802
  * @param {number} [days=1] The number of days to move.
1497
1803
  * @param {number[]} [allowedWeekdays=[ 0, 1, 2, 3, 4, 5, 6 ]] An array of numbers representing the weekdays. ie: [0 = Sun, ..., 6 = Sat].
1804
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1498
1805
  * @returns A new Timestamp
1499
1806
  * @category ranges
1500
1807
  */
1501
- export function relativeDays(timestamp, mover = nextDay, days = 1, allowedWeekdays = [0, 1, 2, 3, 4, 5, 6]) {
1808
+ export function relativeDays(timestamp, mover = nextDay, days = 1, allowedWeekdays = [0, 1, 2, 3, 4, 5, 6], calendar = gregorianCalendar) {
1502
1809
  let ts = copyTimestamp(timestamp);
1503
1810
  if (!allowedWeekdays.includes(Number(ts.weekday)) && ts.weekday === 0 && mover === nextDay) {
1504
1811
  ++days;
1505
1812
  }
1506
1813
  while (--days >= 0) {
1507
- ts = mover(ts);
1814
+ ts = mover(ts, calendar);
1508
1815
  if (allowedWeekdays.length < 7 && !allowedWeekdays.includes(Number(ts.weekday))) {
1509
1816
  ++days;
1510
1817
  }
@@ -1517,13 +1824,14 @@ export function relativeDays(timestamp, mover = nextDay, days = 1, allowedWeekda
1517
1824
  * @param {number} weekday The weekday number (Sun = 0, ..., Sat = 6)
1518
1825
  * @param {function} [mover=nextDay] The function to use ({prevDay} or {nextDay}).
1519
1826
  * @param {number} [maxDays=6] The number of days to look forward or back.
1827
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1520
1828
  * @returns A new Timestamp
1521
1829
  * @category ranges
1522
1830
  */
1523
- export function findWeekday(timestamp, weekday, mover = nextDay, maxDays = 6) {
1831
+ export function findWeekday(timestamp, weekday, mover = nextDay, maxDays = 6, calendar = gregorianCalendar) {
1524
1832
  let ts = copyTimestamp(timestamp);
1525
1833
  while (ts.weekday !== weekday && --maxDays >= 0)
1526
- ts = mover(ts);
1834
+ ts = mover(ts, calendar);
1527
1835
  return ts;
1528
1836
  }
1529
1837
  /**
@@ -1542,10 +1850,22 @@ export function findWeekday(timestamp, weekday, mover = nextDay, maxDays = 6) {
1542
1850
  * @param {DisabledDays} [disabledDays] Specific dates or date ranges to mark disabled.
1543
1851
  * @param {number} [max=42] Maximum number of days to return.
1544
1852
  * @param {number} [min=0] Minimum number of days to return.
1853
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1545
1854
  * @returns {Timestamp[]} Timestamp days.
1546
1855
  * @category ranges
1547
1856
  */
1548
- export function createDayList(start, end, now, weekdays = [0, 1, 2, 3, 4, 5, 6], disabledBefore = undefined, disabledAfter = undefined, disabledWeekdays = [], disabledDays = [], max = 42, min = 0) {
1857
+ export function createDayList(start, end, now, weekdays = [0, 1, 2, 3, 4, 5, 6], disabledBefore = undefined, disabledAfter = undefined, disabledWeekdays = [], disabledDays = [], max = 42, min = 0, calendar = gregorianCalendar) {
1858
+ if (calendar !== gregorianCalendar) {
1859
+ return createCalendarDayList(start, end, now, calendar, {
1860
+ weekdays,
1861
+ disabledBefore,
1862
+ disabledAfter,
1863
+ disabledWeekdays,
1864
+ disabledDays,
1865
+ max,
1866
+ min,
1867
+ });
1868
+ }
1549
1869
  const begin = getDayIdentifier(start);
1550
1870
  const stop = getDayIdentifier(end);
1551
1871
  const days = [];
@@ -1663,7 +1983,7 @@ export function createNativeLocaleFormatterUTC(locale, cb) {
1663
1983
  * `calendar` option. The helper supplies `timeZone: "UTC"` unless the caller
1664
1984
  * provides a different timezone.
1665
1985
  *
1666
- * @param calendar Calendar implementation to use.
1986
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1667
1987
  * @param locale The locale to use.
1668
1988
  * @param cb Callback that returns Intl formatting options.
1669
1989
  * @returns Function that formats a calendar timestamp.
@@ -1714,7 +2034,7 @@ export function makeDateUTC(timestamp) {
1714
2034
  * can format the adapter date correctly when paired with a calendar option.
1715
2035
  *
1716
2036
  * @param timestamp Calendar timestamp object to convert.
1717
- * @param calendar Calendar implementation to use.
2037
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1718
2038
  * @returns JavaScript Date object built with `Date.UTC()`.
1719
2039
  * @category calendar
1720
2040
  */
@@ -1736,7 +2056,7 @@ export function makeDateTime(timestamp) {
1736
2056
  * Converts an adapter calendar timestamp date-time into a UTC JavaScript Date.
1737
2057
  *
1738
2058
  * @param timestamp Calendar timestamp object to convert.
1739
- * @param calendar Calendar implementation to use.
2059
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
1740
2060
  * @returns JavaScript Date object built with `Date.UTC()`.
1741
2061
  * @category calendar
1742
2062
  */
@@ -2063,10 +2383,80 @@ export function isOverlappingDates(startTimestamp, endTimestamp, firstTimestamp,
2063
2383
  * @param {number=} options.minute If positive, adds minutes. If negative, removes minutes.
2064
2384
  * @param {number=} options.second If positive, adds seconds. If negative, removes seconds.
2065
2385
  * @param {number=} options.millisecond If positive, adds milliseconds. If negative, removes milliseconds.
2386
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
2066
2387
  * @returns {Timestamp} New normalized Timestamp object.
2067
2388
  * @category arithmetic
2068
2389
  */
2069
- export function addToDate(timestamp, options) {
2390
+ function addToCalendarDateTime(timestamp, options, calendar) {
2391
+ let ts = updateCalendarFormatted(timestamp, calendar);
2392
+ if (options.year)
2393
+ ts = addCalendarYears(ts, options.year, calendar);
2394
+ if (options.month)
2395
+ ts = addCalendarMonths(ts, options.month, calendar);
2396
+ if (options.day)
2397
+ ts = addCalendarDays(ts, options.day, calendar);
2398
+ const hasTimeOffset = options.hour !== undefined ||
2399
+ options.minute !== undefined ||
2400
+ options.second !== undefined ||
2401
+ options.millisecond !== undefined;
2402
+ if (hasTimeOffset) {
2403
+ const totalMilliseconds = (ts.hour + (options.hour ?? 0)) * MILLISECONDS_IN_HOUR +
2404
+ (ts.minute + (options.minute ?? 0)) * MILLISECONDS_IN_MINUTE +
2405
+ ((ts.second ?? 0) + (options.second ?? 0)) * MILLISECONDS_IN_SECOND +
2406
+ ((ts.millisecond ?? 0) + (options.millisecond ?? 0));
2407
+ const dayOffset = Math.floor(totalMilliseconds / MILLISECONDS_IN_DAY);
2408
+ let timeMilliseconds = totalMilliseconds % MILLISECONDS_IN_DAY;
2409
+ if (timeMilliseconds < 0) {
2410
+ timeMilliseconds += MILLISECONDS_IN_DAY;
2411
+ }
2412
+ if (dayOffset !== 0) {
2413
+ ts = addCalendarDays(ts, dayOffset, calendar);
2414
+ }
2415
+ const next = cloneTimestamp(ts);
2416
+ next.hasTime = true;
2417
+ next.hour = Math.floor(timeMilliseconds / MILLISECONDS_IN_HOUR);
2418
+ timeMilliseconds %= MILLISECONDS_IN_HOUR;
2419
+ next.minute = Math.floor(timeMilliseconds / MILLISECONDS_IN_MINUTE);
2420
+ timeMilliseconds %= MILLISECONDS_IN_MINUTE;
2421
+ next.second = Math.floor(timeMilliseconds / MILLISECONDS_IN_SECOND);
2422
+ next.millisecond = timeMilliseconds % MILLISECONDS_IN_SECOND;
2423
+ if (next.second === 0 && timestamp.second === undefined && options.second === undefined) {
2424
+ delete next.second;
2425
+ }
2426
+ if (next.millisecond === 0 &&
2427
+ timestamp.millisecond === undefined &&
2428
+ options.millisecond === undefined) {
2429
+ delete next.millisecond;
2430
+ }
2431
+ ts = next;
2432
+ }
2433
+ return updateCalendarFormatted(ts, calendar);
2434
+ }
2435
+ /**
2436
+ * Adds or subtracts date/time units from a timestamp.
2437
+ *
2438
+ * This function returns a new frozen Timestamp; it does not mutate the
2439
+ * timestamp passed in. Gregorian dates are normalized through JavaScript Date
2440
+ * rules. Adapter-native dates use the supplied calendar system for year,
2441
+ * month, and day math.
2442
+ *
2443
+ * @param {Timestamp} timestamp Timestamp object to offset.
2444
+ * @param {Object} options Date/time units to add or subtract.
2445
+ * @param {number=} options.year If positive, adds years. If negative, removes years.
2446
+ * @param {number=} options.month If positive, adds months. If negative, removes month.
2447
+ * @param {number=} options.day If positive, adds days. If negative, removes days.
2448
+ * @param {number=} options.hour If positive, adds hours. If negative, removes hours.
2449
+ * @param {number=} options.minute If positive, adds minutes. If negative, removes minutes.
2450
+ * @param {number=} options.second If positive, adds seconds. If negative, removes seconds.
2451
+ * @param {number=} options.millisecond If positive, adds milliseconds. If negative, removes milliseconds.
2452
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
2453
+ * @returns {Timestamp} New normalized Timestamp object.
2454
+ * @category arithmetic
2455
+ */
2456
+ export function addToDate(timestamp, options, calendar = gregorianCalendar) {
2457
+ if (calendar !== gregorianCalendar) {
2458
+ return addToCalendarDateTime(timestamp, options, calendar);
2459
+ }
2070
2460
  const ts = cloneTimestamp(timestamp);
2071
2461
  if (options.year)
2072
2462
  ts.year += options.year;
@@ -2105,10 +2495,14 @@ export function addToDate(timestamp, options) {
2105
2495
  * @param {number=} options.minute If positive, adds minutes. If negative, removes minutes.
2106
2496
  * @param {number=} options.second If positive, adds seconds. If negative, removes seconds.
2107
2497
  * @param {number=} options.millisecond If positive, adds milliseconds. If negative, removes milliseconds.
2498
+ * @param {CalendarSystem=} calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
2108
2499
  * @returns {Timestamp} New normalized Timestamp object.
2109
2500
  * @category arithmetic
2110
2501
  */
2111
- export function addToDateClamped(timestamp, options) {
2502
+ export function addToDateClamped(timestamp, options, calendar = gregorianCalendar) {
2503
+ if (calendar !== gregorianCalendar) {
2504
+ return addToCalendarDateTime(timestamp, options, calendar);
2505
+ }
2112
2506
  const ts = cloneTimestamp(timestamp);
2113
2507
  if (options.year || options.month) {
2114
2508
  const target = normalizeYearMonth(ts.year + (options.year ?? 0), ts.month + (options.month ?? 0));
@@ -2456,6 +2850,61 @@ export function getMonthFormatter() {
2456
2850
  }
2457
2851
  return monthFormatter;
2458
2852
  }
2853
+ /**
2854
+ * Returns a function that formats one-based calendar adapter month numbers.
2855
+ *
2856
+ * This is the calendar-aware counterpart to getMonthFormatter(). It converts
2857
+ * adapter fields through the adapter's epoch-day mapping, then asks Intl to
2858
+ * format the equivalent Gregorian Date with the adapter's Intl calendar id
2859
+ * when one is available.
2860
+ *
2861
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
2862
+ * @returns Function that formats one-based month numbers for the adapter.
2863
+ * @category calendar
2864
+ */
2865
+ export function getCalendarMonthFormatter(calendar = gregorianCalendar) {
2866
+ const options = {
2867
+ long: { timeZone: 'UTC', month: 'long' },
2868
+ short: { timeZone: 'UTC', month: 'short' },
2869
+ narrow: { timeZone: 'UTC', month: 'narrow' },
2870
+ };
2871
+ const fallbackFormatter = (month) => Number.isFinite(month) && month >= 1 ? `Month ${month}` : '';
2872
+ if (typeof Intl === 'undefined' || typeof Intl.DateTimeFormat === 'undefined') {
2873
+ return fallbackFormatter;
2874
+ }
2875
+ return (month, type = 'long', locale, year = 1) => {
2876
+ const calendarMonth = Math.trunc(month);
2877
+ const calendarYear = Math.trunc(year);
2878
+ const date = {
2879
+ year: calendarYear,
2880
+ month: calendarMonth,
2881
+ day: 1,
2882
+ };
2883
+ if (Number.isFinite(calendarMonth) === false ||
2884
+ Number.isFinite(calendarYear) === false ||
2885
+ isValidCalendarDate(date, calendar) === false) {
2886
+ return '';
2887
+ }
2888
+ try {
2889
+ const resolvedOptions = resolveIntlNameFormat(options, type);
2890
+ const formatterOptions = calendar.intlCalendar === undefined || resolvedOptions.calendar !== undefined
2891
+ ? resolvedOptions
2892
+ : {
2893
+ ...resolvedOptions,
2894
+ calendar: calendar.intlCalendar,
2895
+ };
2896
+ const gregorianDate = gregorianCalendar.fromEpochDay(calendar.toEpochDay(date));
2897
+ const nativeDate = new Date(Date.UTC(gregorianDate.year, gregorianDate.month - 1, gregorianDate.day));
2898
+ return new Intl.DateTimeFormat(locale || undefined, formatterOptions).format(nativeDate);
2899
+ }
2900
+ catch (e) {
2901
+ if (e instanceof Error) {
2902
+ console.error(`Intl.DateTimeFormat: ${e.message} -> calendar month: ${calendarMonth}`);
2903
+ }
2904
+ return fallbackFormatter(calendarMonth);
2905
+ }
2906
+ };
2907
+ }
2459
2908
  /**
2460
2909
  * Retrieves localized month names.
2461
2910
  *
@@ -2468,4 +2917,22 @@ export function getMonthNames(type, locale) {
2468
2917
  const monthFormatter = getMonthFormatter();
2469
2918
  return [...Array(12).keys()].map((month) => monthFormatter(month, type, locale));
2470
2919
  }
2920
+ /**
2921
+ * Retrieves localized month names for a calendar adapter.
2922
+ *
2923
+ * Month numbers are generated from `1` through `calendar.monthsInYear(year)`.
2924
+ * Pass a year when the calendar can have leap months or year-specific month
2925
+ * naming rules.
2926
+ *
2927
+ * @param calendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.
2928
+ * @param type Format type: `narrow`, `short`, or `long`.
2929
+ * @param locale Locale to use for formatting, such as `en-US`.
2930
+ * @param year Calendar year to sample. Defaults to `1`.
2931
+ * @returns Localized month names in calendar-native order.
2932
+ * @category calendar
2933
+ */
2934
+ export function getCalendarMonthNames(calendar = gregorianCalendar, type = 'long', locale, year = 1) {
2935
+ const monthFormatter = getCalendarMonthFormatter(calendar);
2936
+ return [...Array(calendar.monthsInYear(year)).keys()].map((month) => monthFormatter(month + 1, type, locale, year));
2937
+ }
2471
2938
  //# sourceMappingURL=index.js.map