@@ -455,9 +455,213 @@ impl['iso8601'] = {
455
455
}
456
456
} ;
457
457
458
- // Note: other built -in calendars than iso8601 are not part of the Temporal
458
+ // Note: Built -in calendars other than iso8601 are not part of the Temporal
459
459
// proposal for ECMA-262. These calendars will be standardized as part of
460
- // ECMA-402.
460
+ // ECMA-402. Code below here includes an implementation of these calendars order
461
+ // to validate the Temporal API and to get feedback. However, non-ISO calendar
462
+ // implementation is subject to change because these calendars are
463
+ // implementation-defined.
464
+ //
465
+ // Some ES implementations don't include ECMA 402. For this reason, it's helpful
466
+ // to ensure a clean separation between the ISO calendar implementation which is
467
+ // a part of ECMA 262 and the non-ISO calendar implementation which requires
468
+ // ECMA 402.
469
+ //
470
+ // To ensure this separation, the implementation is split. The `NonIsoImpl`
471
+ // interface is the top-level implementation for all non-ISO calendars. This
472
+ // type has the same shape as the ECMA 262-only ISO calendar implementation so
473
+ // can use the same callers, tests, etc.
474
+ //
475
+ // A derived interface `NonIsoImplWithHelper` adds a `helper` property that
476
+ // includes the remaining non-ISO implementation properties and methods beyond
477
+ // the ISO implementation above. The `helper` property's shape is a base
478
+ // singleton object common to all calendars (`HelperSharedImpl`) that's extended
479
+ // (interface `HelperPerCalendarImpl`) with implementation that varies for each
480
+ // calendar.
481
+ //
482
+ // Typing of individual methods in the interfaces below uses the `this`
483
+ // "parameter" declaration definition, which is a fake parameter (stripped by TS
484
+ // during compilation and not visible at runtime) that tells TS what type `this`
485
+ // is for a method. For historical reasons, the initial implementation of
486
+ // non-ISO calendars mirrored the code style of the previous ISO-only
487
+ // implementation which didn't use ES6 classes. Using the `this` parameter is a
488
+ // hack to delay converting this file to use ES6 classes until the code was
489
+ // fully typed to make a `class` refactoring easier and safer. We'll probably do
490
+ // this conversion in the future. (PRs welcome!)
491
+
492
+ /**
493
+ * `NonIsoImpl` - The generic top-level implementation for all non-ISO
494
+ * calendars. This type has the same shape as the 262-only ISO calendar
495
+ * implementation, which means the `Calendar` class implementation can swap out
496
+ * the ISO for non-ISO implementations without changing any `Calendar` code.
497
+ */
498
+ interface NonIsoImpl {
499
+ dateFromFields (
500
+ this : NonIsoImplWithHelper ,
501
+ fieldsParam : Params [ 'dateFromFields' ] [ 0 ] ,
502
+ options : NonNullable < Params [ 'dateFromFields' ] [ 1 ] > ,
503
+ calendar : Temporal . Calendar
504
+ ) : Temporal . PlainDate ;
505
+ yearMonthFromFields (
506
+ this : NonIsoImplWithHelper ,
507
+ fieldsParam : Params [ 'yearMonthFromFields' ] [ 0 ] ,
508
+ options : NonNullable < Params [ 'yearMonthFromFields' ] [ 1 ] > ,
509
+ calendar : Temporal . Calendar
510
+ ) : Temporal . PlainYearMonth ;
511
+ monthDayFromFields (
512
+ this : NonIsoImplWithHelper ,
513
+ fieldsParam : Params [ 'monthDayFromFields' ] [ 0 ] ,
514
+ options : NonNullable < Params [ 'monthDayFromFields' ] [ 1 ] > ,
515
+ calendar : Temporal . Calendar
516
+ ) : Temporal . PlainMonthDay ;
517
+ fields ( fieldsParam : string [ ] ) : Return [ 'fields' ] ;
518
+ mergeFields ( fields : Params [ 'mergeFields' ] [ 0 ] , additionalFields : Params [ 'mergeFields' ] [ 1 ] ) : Return [ 'mergeFields' ] ;
519
+ dateAdd (
520
+ this : NonIsoImplWithHelper ,
521
+ date : Temporal . PlainDate ,
522
+ years : number ,
523
+ months : number ,
524
+ weeks : number ,
525
+ days : number ,
526
+ overflow : Overflow ,
527
+ calendar : Temporal . Calendar
528
+ ) : Temporal . PlainDate ;
529
+ dateUntil (
530
+ this : NonIsoImplWithHelper ,
531
+ one : Temporal . PlainDate ,
532
+ two : Temporal . PlainDate ,
533
+ largestUnit : Temporal . DateUnit
534
+ ) : {
535
+ years : number ;
536
+ months : number ;
537
+ weeks : number ;
538
+ days : number ;
539
+ } ;
540
+ year ( this : NonIsoImplWithHelper , date : Temporal . PlainDate ) : number ;
541
+ month ( this : NonIsoImplWithHelper , date : Temporal . PlainDate ) : number ;
542
+ day ( this : NonIsoImplWithHelper , date : Temporal . PlainDate ) : number ;
543
+ era ( this : NonIsoImplWithHelper , date : Temporal . PlainDate ) : string | undefined ;
544
+ eraYear ( this : NonIsoImplWithHelper , date : Temporal . PlainDate ) : number | undefined ;
545
+ monthCode ( this : NonIsoImplWithHelper , date : Temporal . PlainDate ) : string ;
546
+ dayOfWeek ( date : Temporal . PlainDate ) : number ;
547
+ dayOfYear ( this : NonIsoImplWithHelper , date : Temporal . PlainDate ) : number ;
548
+ weekOfYear ( date : Temporal . PlainDate ) : number ;
549
+ daysInWeek ( date : Temporal . PlainDate ) : number ;
550
+ daysInMonth ( this : NonIsoImplWithHelper , date : Temporal . PlainDate | Temporal . PlainYearMonth ) : number ;
551
+ daysInYear ( this : NonIsoImplWithHelper , dateParam : Temporal . PlainDate | Temporal . PlainYearMonth ) : number ;
552
+ monthsInYear ( this : NonIsoImplWithHelper , date : Temporal . PlainDate | Temporal . PlainYearMonth ) : number ;
553
+ inLeapYear ( this : NonIsoImplWithHelper , dateParam : Temporal . PlainDate | Temporal . PlainYearMonth ) : boolean ;
554
+ }
555
+
556
+ /**
557
+ * This type exists solely to ensure a compiler error is shown if a per-calendar
558
+ * implementation object doesn't declare a `helper` property. It will go away
559
+ * if we migrate to ES6 classes.
560
+ *
561
+ * The methods of NonIsoImpl all set their `this` to NonIsoImplWithHelper in
562
+ * order to avoid having to cast every use of `helper` to exclude `undefined`.
563
+ * */
564
+ interface NonIsoImplWithHelper extends NonIsoImpl {
565
+ helper : HelperPerCalendarImpl ;
566
+ }
567
+
568
+ /** Shape of shared implementation code that applies to all calendars */
569
+ interface HelperSharedImpl {
570
+ isoToCalendarDate ( isoDate : IsoYMD , cache : OneObjectCache ) : FullCalendarDate ;
571
+ validateCalendarDate ( calendarDate : Partial < FullCalendarDate > ) : void ;
572
+ adjustCalendarDate (
573
+ calendarDate : Partial < FullCalendarDate > ,
574
+ cache ?: OneObjectCache ,
575
+ overflow ?: Overflow ,
576
+ fromLegacyDate ?: boolean
577
+ ) : FullCalendarDate ;
578
+ regulateMonthDayNaive ( calendarDate : FullCalendarDate , overflow : Overflow , cache : OneObjectCache ) : FullCalendarDate ;
579
+ calendarToIsoDate ( date : CalendarDateFields , overflow : Overflow , cache : OneObjectCache ) : IsoYMD ;
580
+ temporalToCalendarDate (
581
+ date : Temporal . PlainDate | Temporal . PlainMonthDay | Temporal . PlainYearMonth ,
582
+ cache : OneObjectCache
583
+ ) : FullCalendarDate ;
584
+ compareCalendarDates ( date1 : Partial < CalendarYMD > , date2 : Partial < CalendarYMD > ) : 0 | 1 | - 1 ;
585
+ regulateDate ( calendarDate : CalendarYMD , overflow : Overflow , cache : OneObjectCache ) : FullCalendarDate ;
586
+ addDaysIso ( isoDate : IsoYMD , days : number , cache ?: OneObjectCache ) : IsoYMD ;
587
+ addDaysCalendar ( calendarDate : CalendarYMD , days : number , cache : OneObjectCache ) : FullCalendarDate ;
588
+ addMonthsCalendar ( calendarDate : CalendarYMD , months : number , overflow : Overflow , cache : OneObjectCache ) : CalendarYMD ;
589
+ addCalendar (
590
+ calendarDate : CalendarYMD ,
591
+ { years, months, weeks, days } : { years ?: number ; months ?: number ; weeks ?: number ; days ?: number } ,
592
+ overflow : Overflow ,
593
+ cache : OneObjectCache
594
+ ) : FullCalendarDate ;
595
+ untilCalendar (
596
+ calendarOne : FullCalendarDate ,
597
+ calendarTwo : FullCalendarDate ,
598
+ largestUnit : Temporal . DateUnit ,
599
+ cache : OneObjectCache
600
+ ) : { years : number ; months : number ; weeks : number ; days : number } ;
601
+ daysInMonth ( calendarDate : CalendarYMD , cache : OneObjectCache ) : number ;
602
+ daysInPreviousMonth ( calendarDate : CalendarYMD , cache : OneObjectCache ) : number ;
603
+ startOfCalendarYear ( calendarDate : CalendarYearOnly ) : CalendarYMD ;
604
+ startOfCalendarMonth ( calendarDate : { year : number ; month : number } ) : CalendarYMD ;
605
+ calendarDaysUntil ( calendarOne : CalendarYMD , calendarTwo : CalendarYMD , cache : OneObjectCache ) : number ;
606
+ isoDaysUntil ( oneIso : IsoYMD , twoIso : IsoYMD ) : number ;
607
+ eraLength : 'long' | 'short' | 'narrow' ;
608
+ getFormatter ( ) : globalThis . Intl . DateTimeFormat ;
609
+ formatter ?: globalThis . Intl . DateTimeFormat ;
610
+ hasEra : boolean ;
611
+ monthDayFromFields ( fields : Partial < FullCalendarDate > , overflow : Overflow , cache : OneObjectCache ) : IsoYMD ;
612
+ }
613
+
614
+ /** Calendar-specific implementation */
615
+ interface HelperPerCalendarImpl extends HelperSharedImpl {
616
+ id : string ;
617
+ reviseIntlEra ?< T extends Partial < EraAndEraYear > > ( calendarDate : T , isoDate : IsoYMD ) : T ;
618
+ constantEra ?: string ;
619
+ checkIcuBugs ?( isoDate : IsoYMD ) : void ;
620
+ calendarType ?: string ;
621
+ monthsInYear ( calendarDate : CalendarYearOnly , cache ?: OneObjectCache ) : number ;
622
+ maximumMonthLength ( calendarDate ?: CalendarYM ) : number ;
623
+ minimumMonthLength ( calendarDate ?: CalendarYM ) : number ;
624
+ estimateIsoDate ( calendarDate : CalendarYMD ) : IsoYMD ;
625
+ inLeapYear ( calendarDate : CalendarYearOnly , cache ?: OneObjectCache ) : boolean ;
626
+
627
+ // Fields below here are only present in some subclasses but not others.
628
+ eras ?: Era [ ] ;
629
+ anchorEra ?: Era ;
630
+ calendarIsVulnerableToJulianBug ?: boolean ;
631
+ v8IsVulnerableToJulianBug ?: boolean ;
632
+ }
633
+
634
+ /**
635
+ * This type is passed through from Calendar#dateFromFields().
636
+ * `monthExtra` is additional information used internally to identify lunisolar leap months.
637
+ */
638
+ type CalendarDateFields = Params [ 'dateFromFields' ] [ 0 ] & { monthExtra ?: string } ;
639
+
640
+ /**
641
+ * This is a "fully populated" calendar date record. It's only lacking
642
+ * `era`/`eraYear` (which may not be present in all calendars) and `monthExtra`
643
+ * which is only used in some cases.
644
+ */
645
+ type FullCalendarDate = {
646
+ era ?: string ;
647
+ eraYear ?: number ;
648
+ year : number ;
649
+ month : number ;
650
+ monthCode : string ;
651
+ day : number ;
652
+ monthExtra ?: string ;
653
+ } ;
654
+
655
+ // The types below are various subsets of calendar dates
656
+ type CalendarYMD = { year : number ; month : number ; day : number } ;
657
+ type CalendarYM = { year : number ; month : number } ;
658
+ type CalendarYearOnly = { year : number } ;
659
+ type EraAndEraYear = { era : string ; eraYear : number } ;
660
+
661
+ /** Record representing YMD of an ISO calendar date */
662
+ type IsoYMD = { year : number ; month : number ; day : number } ;
663
+
664
+ type Overflow = Temporal . AssignmentOptions [ 'overflow' ] ;
461
665
462
666
function monthCodeNumberPart ( monthCode : string ) {
463
667
if ( ! monthCode . startsWith ( 'M' ) ) {
@@ -1232,6 +1436,27 @@ const nonIsoHelperBase: NonIsoHelperBase = {
1232
1436
}
1233
1437
} ;
1234
1438
1439
+ interface HebrewMonthInfo {
1440
+ [ m : string ] : (
1441
+ | {
1442
+ leap : undefined ;
1443
+ regular : number ;
1444
+ }
1445
+ | {
1446
+ leap : number ;
1447
+ regular : undefined ;
1448
+ }
1449
+ ) & {
1450
+ monthCode : string ;
1451
+ days :
1452
+ | number
1453
+ | {
1454
+ min : number ;
1455
+ max : number ;
1456
+ } ;
1457
+ } ;
1458
+ }
1459
+
1235
1460
const helperHebrew : NonIsoHelperBase = ObjectAssign ( { } , nonIsoHelperBase , {
1236
1461
id : 'hebrew' ,
1237
1462
calendarType : 'lunisolar' ,
@@ -1428,6 +1653,20 @@ const helperPersian: NonIsoHelperBase = ObjectAssign({}, nonIsoHelperBase, {
1428
1653
}
1429
1654
} as Partial < NonIsoHelperBase > ) ;
1430
1655
1656
+ interface IndianMonthInfo {
1657
+ [ month : number ] : {
1658
+ length : number ;
1659
+ month : number ;
1660
+ day : number ;
1661
+ leap ?: {
1662
+ length : number ;
1663
+ month : number ;
1664
+ day : number ;
1665
+ } ;
1666
+ nextYear ?: true | undefined ;
1667
+ } ;
1668
+ }
1669
+
1431
1670
const helperIndian : NonIsoHelperBase = ObjectAssign ( { } , nonIsoHelperBase , {
1432
1671
id : 'indian' ,
1433
1672
calendarType : 'solar' ,
@@ -1958,6 +2197,13 @@ const helperJapanese: NonIsoHelperBase = ObjectAssign(
1958
2197
} as Partial < NonIsoHelperBase >
1959
2198
) ;
1960
2199
2200
+ interface ChineseMonthInfo {
2201
+ [ key : string ] : { monthIndex : number ; daysInMonth : number } ;
2202
+ }
2203
+ interface ChineseDraftMonthInfo {
2204
+ [ key : string ] : { monthIndex : number ; daysInMonth ?: number } ;
2205
+ }
2206
+
1961
2207
const helperChinese : NonIsoHelperBase = ObjectAssign ( { } , nonIsoHelperBase , {
1962
2208
id : 'chinese' ,
1963
2209
calendarType : 'lunisolar' ,
0 commit comments