1use crate::cal::hijri::HijriSimulatedLocation;
8use crate::cal::iso::IsoDateInner;
9use crate::cal::{
10    Buddhist, Chinese, Coptic, Dangi, Ethiopian, EthiopianEraStyle, Gregorian, Hebrew,
11    HijriSimulated, HijriTabular, HijriTabularEpoch, HijriTabularLeapYears, HijriUmmAlQura, Indian,
12    Iso, Japanese, JapaneseExtended, Persian, Roc,
13};
14use crate::error::DateError;
15use crate::types::YearInfo;
16use crate::{types, AsCalendar, Calendar, Date, DateDuration, DateDurationUnit, Ref};
17
18use crate::preferences::{CalendarAlgorithm, HijriCalendarAlgorithm};
19use icu_locale_core::preferences::define_preferences;
20use icu_locale_core::subtags::region;
21use icu_provider::prelude::*;
22
23use core::fmt;
24
25define_preferences!(
26    [Copy]
28    CalendarPreferences,
29    {
30        calendar_algorithm: CalendarAlgorithm
32    }
33);
34
35#[derive(Debug, Clone)]
77#[non_exhaustive]
78pub enum AnyCalendar {
79    Buddhist(Buddhist),
81    Chinese(Chinese),
83    Coptic(Coptic),
85    Dangi(Dangi),
87    Ethiopian(Ethiopian),
89    Gregorian(Gregorian),
91    Hebrew(Hebrew),
93    Indian(Indian),
95    HijriTabular(HijriTabular),
97    HijriSimulated(HijriSimulated),
99    HijriUmmAlQura(HijriUmmAlQura),
101    Iso(Iso),
103    Japanese(Japanese),
105    JapaneseExtended(JapaneseExtended),
107    Persian(Persian),
109    Roc(Roc),
111}
112
113#[derive(Clone, PartialEq, Eq, Debug, Copy)]
116#[non_exhaustive]
117pub enum AnyDateInner {
118    Buddhist(<Buddhist as Calendar>::DateInner),
120    Chinese(<Chinese as Calendar>::DateInner),
122    Coptic(<Coptic as Calendar>::DateInner),
124    Dangi(<Dangi as Calendar>::DateInner),
126    Ethiopian(<Ethiopian as Calendar>::DateInner),
128    Gregorian(<Gregorian as Calendar>::DateInner),
130    Hebrew(<Hebrew as Calendar>::DateInner),
132    Indian(<Indian as Calendar>::DateInner),
134    HijriTabular(
136        <HijriTabular as Calendar>::DateInner,
137        HijriTabularLeapYears,
138        HijriTabularEpoch,
139    ),
140    HijriSimulated(<HijriSimulated as Calendar>::DateInner),
142    HijriUmmAlQura(<HijriUmmAlQura as Calendar>::DateInner),
144    Iso(<Iso as Calendar>::DateInner),
146    Japanese(<Japanese as Calendar>::DateInner),
148    JapaneseExtended(<JapaneseExtended as Calendar>::DateInner),
150    Persian(<Persian as Calendar>::DateInner),
152    Roc(<Roc as Calendar>::DateInner),
154}
155
156macro_rules! match_cal_and_date {
157    (match ($cal:ident, $date:ident): ($cal_matched:ident, $date_matched:ident) => $e:expr) => {
158        match ($cal, $date) {
159            (&Self::Buddhist(ref $cal_matched), &AnyDateInner::Buddhist(ref $date_matched)) => $e,
160            (&Self::Chinese(ref $cal_matched), &AnyDateInner::Chinese(ref $date_matched)) => $e,
161            (&Self::Coptic(ref $cal_matched), &AnyDateInner::Coptic(ref $date_matched)) => $e,
162            (&Self::Dangi(ref $cal_matched), &AnyDateInner::Dangi(ref $date_matched)) => $e,
163            (&Self::Ethiopian(ref $cal_matched), &AnyDateInner::Ethiopian(ref $date_matched)) => $e,
164            (&Self::Gregorian(ref $cal_matched), &AnyDateInner::Gregorian(ref $date_matched)) => $e,
165            (&Self::Hebrew(ref $cal_matched), &AnyDateInner::Hebrew(ref $date_matched)) => $e,
166            (&Self::Indian(ref $cal_matched), &AnyDateInner::Indian(ref $date_matched)) => $e,
167            (
168                &Self::HijriTabular(ref $cal_matched),
169                &AnyDateInner::HijriTabular(ref $date_matched, leap_years, epoch),
170            ) if $cal_matched.epoch == epoch && $cal_matched.leap_years == leap_years => $e,
171            (
172                &Self::HijriSimulated(ref $cal_matched),
173                &AnyDateInner::HijriSimulated(ref $date_matched),
174            ) => $e,
175            (
176                &Self::HijriUmmAlQura(ref $cal_matched),
177                &AnyDateInner::HijriUmmAlQura(ref $date_matched),
178            ) => $e,
179            (&Self::Iso(ref $cal_matched), &AnyDateInner::Iso(ref $date_matched)) => $e,
180            (&Self::Japanese(ref $cal_matched), &AnyDateInner::Japanese(ref $date_matched)) => $e,
181            (
182                &Self::JapaneseExtended(ref $cal_matched),
183                &AnyDateInner::JapaneseExtended(ref $date_matched),
184            ) => $e,
185            (&Self::Persian(ref $cal_matched), &AnyDateInner::Persian(ref $date_matched)) => $e,
186            (&Self::Roc(ref $cal_matched), &AnyDateInner::Roc(ref $date_matched)) => $e,
187            _ => panic!(
188                "Found AnyCalendar with mixed calendar type {:?} and date type {:?}!",
189                $cal.kind().debug_name(),
190                $date.kind().debug_name()
191            ),
192        }
193    };
194}
195
196macro_rules! match_cal {
197    (match $cal:ident: ($cal_matched:ident) => $e:expr) => {
198        match $cal {
199            &Self::Buddhist(ref $cal_matched) => AnyDateInner::Buddhist($e),
200            &Self::Chinese(ref $cal_matched) => AnyDateInner::Chinese($e),
201            &Self::Coptic(ref $cal_matched) => AnyDateInner::Coptic($e),
202            &Self::Dangi(ref $cal_matched) => AnyDateInner::Dangi($e),
203            &Self::Ethiopian(ref $cal_matched) => AnyDateInner::Ethiopian($e),
204            &Self::Gregorian(ref $cal_matched) => AnyDateInner::Gregorian($e),
205            &Self::Hebrew(ref $cal_matched) => AnyDateInner::Hebrew($e),
206            &Self::Indian(ref $cal_matched) => AnyDateInner::Indian($e),
207            &Self::HijriSimulated(ref $cal_matched) => AnyDateInner::HijriSimulated($e),
208            &Self::HijriTabular(ref $cal_matched) => {
209                AnyDateInner::HijriTabular($e, $cal_matched.leap_years, $cal_matched.epoch)
210            }
211            &Self::HijriUmmAlQura(ref $cal_matched) => AnyDateInner::HijriUmmAlQura($e),
212            &Self::Iso(ref $cal_matched) => AnyDateInner::Iso($e),
213            &Self::Japanese(ref $cal_matched) => AnyDateInner::Japanese($e),
214            &Self::JapaneseExtended(ref $cal_matched) => AnyDateInner::JapaneseExtended($e),
215            &Self::Persian(ref $cal_matched) => AnyDateInner::Persian($e),
216            &Self::Roc(ref $cal_matched) => AnyDateInner::Roc($e),
217        }
218    };
219}
220
221impl crate::cal::scaffold::UnstableSealed for AnyCalendar {}
222impl Calendar for AnyCalendar {
223    type DateInner = AnyDateInner;
224    type Year = YearInfo;
225
226    fn from_codes(
227        &self,
228        era: Option<&str>,
229        year: i32,
230        month_code: types::MonthCode,
231        day: u8,
232    ) -> Result<Self::DateInner, DateError> {
233        Ok(match_cal!(match self: (c) => c.from_codes(era, year, month_code, day)?))
234    }
235
236    fn from_iso(&self, iso: IsoDateInner) -> AnyDateInner {
237        match_cal!(match self: (c) => c.from_iso(iso))
238    }
239
240    fn from_rata_die(&self, rd: calendrical_calculations::rata_die::RataDie) -> Self::DateInner {
241        match_cal!(match self: (c) => c.from_rata_die(rd))
242    }
243
244    fn to_rata_die(&self, date: &Self::DateInner) -> calendrical_calculations::rata_die::RataDie {
245        match_cal_and_date!(match (self, date): (c, d) => c.to_rata_die(d))
246    }
247
248    fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner {
249        match_cal_and_date!(match (self, date): (c, d) => c.to_iso(d))
250    }
251
252    fn months_in_year(&self, date: &Self::DateInner) -> u8 {
253        match_cal_and_date!(match (self, date): (c, d) => c.months_in_year(d))
254    }
255
256    fn days_in_year(&self, date: &Self::DateInner) -> u16 {
257        match_cal_and_date!(match (self, date): (c, d) => c.days_in_year(d))
258    }
259
260    fn days_in_month(&self, date: &Self::DateInner) -> u8 {
261        match_cal_and_date!(match (self, date): (c, d) => c.days_in_month(d))
262    }
263
264    fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration<Self>) {
265        match (self, date) {
266            (Self::Buddhist(c), AnyDateInner::Buddhist(ref mut d)) => {
267                c.offset_date(d, offset.cast_unit())
268            }
269            (Self::Chinese(c), AnyDateInner::Chinese(ref mut d)) => {
270                c.offset_date(d, offset.cast_unit())
271            }
272            (Self::Coptic(c), AnyDateInner::Coptic(ref mut d)) => {
273                c.offset_date(d, offset.cast_unit())
274            }
275            (Self::Dangi(c), AnyDateInner::Dangi(ref mut d)) => {
276                c.offset_date(d, offset.cast_unit())
277            }
278            (Self::Ethiopian(c), AnyDateInner::Ethiopian(ref mut d)) => {
279                c.offset_date(d, offset.cast_unit())
280            }
281            (Self::Gregorian(c), AnyDateInner::Gregorian(ref mut d)) => {
282                c.offset_date(d, offset.cast_unit())
283            }
284            (Self::Hebrew(c), AnyDateInner::Hebrew(ref mut d)) => {
285                c.offset_date(d, offset.cast_unit())
286            }
287            (Self::Indian(c), AnyDateInner::Indian(ref mut d)) => {
288                c.offset_date(d, offset.cast_unit())
289            }
290            (
291                Self::HijriTabular(c),
292                &mut AnyDateInner::HijriTabular(ref mut d, leap_years, epoch),
293            ) if c.epoch == epoch && c.leap_years == leap_years => {
294                c.offset_date(d, offset.cast_unit())
295            }
296            (Self::HijriSimulated(c), AnyDateInner::HijriSimulated(ref mut d)) => {
297                c.offset_date(d, offset.cast_unit())
298            }
299            (Self::HijriUmmAlQura(c), AnyDateInner::HijriUmmAlQura(ref mut d)) => {
300                c.offset_date(d, offset.cast_unit())
301            }
302            (Self::Iso(c), AnyDateInner::Iso(ref mut d)) => c.offset_date(d, offset.cast_unit()),
303            (Self::Japanese(c), AnyDateInner::Japanese(ref mut d)) => {
304                c.offset_date(d, offset.cast_unit())
305            }
306            (Self::JapaneseExtended(c), AnyDateInner::JapaneseExtended(ref mut d)) => {
307                c.offset_date(d, offset.cast_unit())
308            }
309            (Self::Persian(c), AnyDateInner::Persian(ref mut d)) => {
310                c.offset_date(d, offset.cast_unit())
311            }
312            (Self::Roc(c), AnyDateInner::Roc(ref mut d)) => c.offset_date(d, offset.cast_unit()),
313            #[allow(clippy::panic)]
315            (_, d) => panic!(
316                "Found AnyCalendar with mixed calendar type {} and date type {}!",
317                self.kind().debug_name(),
318                d.kind().debug_name()
319            ),
320        }
321    }
322
323    fn until(
324        &self,
325        date1: &Self::DateInner,
326        date2: &Self::DateInner,
327        calendar2: &Self,
328        largest_unit: DateDurationUnit,
329        smallest_unit: DateDurationUnit,
330    ) -> DateDuration<Self> {
331        match (self, calendar2, date1, date2) {
332            (
333                Self::Buddhist(c1),
334                Self::Buddhist(c2),
335                AnyDateInner::Buddhist(d1),
336                AnyDateInner::Buddhist(d2),
337            ) => c1
338                .until(d1, d2, c2, largest_unit, smallest_unit)
339                .cast_unit(),
340            (
341                Self::Chinese(c1),
342                Self::Chinese(c2),
343                AnyDateInner::Chinese(d1),
344                AnyDateInner::Chinese(d2),
345            ) => c1
346                .until(d1, d2, c2, largest_unit, smallest_unit)
347                .cast_unit(),
348            (
349                Self::Coptic(c1),
350                Self::Coptic(c2),
351                AnyDateInner::Coptic(d1),
352                AnyDateInner::Coptic(d2),
353            ) => c1
354                .until(d1, d2, c2, largest_unit, smallest_unit)
355                .cast_unit(),
356            (
357                Self::Dangi(c1),
358                Self::Dangi(c2),
359                AnyDateInner::Dangi(d1),
360                AnyDateInner::Dangi(d2),
361            ) => c1
362                .until(d1, d2, c2, largest_unit, smallest_unit)
363                .cast_unit(),
364            (
365                Self::Ethiopian(c1),
366                Self::Ethiopian(c2),
367                AnyDateInner::Ethiopian(d1),
368                AnyDateInner::Ethiopian(d2),
369            ) => c1
370                .until(d1, d2, c2, largest_unit, smallest_unit)
371                .cast_unit(),
372            (
373                Self::Gregorian(c1),
374                Self::Gregorian(c2),
375                AnyDateInner::Gregorian(d1),
376                AnyDateInner::Gregorian(d2),
377            ) => c1
378                .until(d1, d2, c2, largest_unit, smallest_unit)
379                .cast_unit(),
380            (
381                Self::Hebrew(c1),
382                Self::Hebrew(c2),
383                AnyDateInner::Hebrew(d1),
384                AnyDateInner::Hebrew(d2),
385            ) => c1
386                .until(d1, d2, c2, largest_unit, smallest_unit)
387                .cast_unit(),
388            (
389                Self::Indian(c1),
390                Self::Indian(c2),
391                AnyDateInner::Indian(d1),
392                AnyDateInner::Indian(d2),
393            ) => c1
394                .until(d1, d2, c2, largest_unit, smallest_unit)
395                .cast_unit(),
396            (
397                Self::HijriTabular(c1),
398                Self::HijriTabular(c2),
399                &AnyDateInner::HijriTabular(ref d1, l1, e1),
400                &AnyDateInner::HijriTabular(ref d2, l2, e2),
401            ) if c1.epoch == c2.epoch
402                && c2.epoch == e1
403                && e1 == e2
404                && c1.leap_years == c2.leap_years
405                && c2.leap_years == l1
406                && l1 == l2 =>
407            {
408                c1.until(d1, d2, c2, largest_unit, smallest_unit)
409                    .cast_unit()
410            }
411            (
412                Self::HijriSimulated(c1),
413                Self::HijriSimulated(c2),
414                AnyDateInner::HijriSimulated(d1),
415                AnyDateInner::HijriSimulated(d2),
416            ) => c1
417                .until(d1, d2, c2, largest_unit, smallest_unit)
418                .cast_unit(),
419            (
420                Self::HijriUmmAlQura(c1),
421                Self::HijriUmmAlQura(c2),
422                AnyDateInner::HijriUmmAlQura(d1),
423                AnyDateInner::HijriUmmAlQura(d2),
424            ) => c1
425                .until(d1, d2, c2, largest_unit, smallest_unit)
426                .cast_unit(),
427            (Self::Iso(c1), Self::Iso(c2), AnyDateInner::Iso(d1), AnyDateInner::Iso(d2)) => c1
428                .until(d1, d2, c2, largest_unit, smallest_unit)
429                .cast_unit(),
430            (
431                Self::Japanese(c1),
432                Self::Japanese(c2),
433                AnyDateInner::Japanese(d1),
434                AnyDateInner::Japanese(d2),
435            ) => c1
436                .until(d1, d2, c2, largest_unit, smallest_unit)
437                .cast_unit(),
438            (
439                Self::JapaneseExtended(c1),
440                Self::JapaneseExtended(c2),
441                AnyDateInner::JapaneseExtended(d1),
442                AnyDateInner::JapaneseExtended(d2),
443            ) => c1
444                .until(d1, d2, c2, largest_unit, smallest_unit)
445                .cast_unit(),
446            (
447                Self::Persian(c1),
448                Self::Persian(c2),
449                AnyDateInner::Persian(d1),
450                AnyDateInner::Persian(d2),
451            ) => c1
452                .until(d1, d2, c2, largest_unit, smallest_unit)
453                .cast_unit(),
454            (Self::Roc(c1), Self::Roc(c2), AnyDateInner::Roc(d1), AnyDateInner::Roc(d2)) => c1
455                .until(d1, d2, c2, largest_unit, smallest_unit)
456                .cast_unit(),
457            _ => {
458                let iso = calendar2.to_iso(date2);
460
461                match_cal_and_date!(match (self, date1):
462                    (c1, d1) => {
463                        let d2 = c1.from_iso(iso);
464                        let until = c1.until(d1, &d2, c1, largest_unit, smallest_unit);
465                        until.cast_unit::<AnyCalendar>()
466                    }
467                )
468            }
469        }
470    }
471
472    fn year_info(&self, date: &Self::DateInner) -> types::YearInfo {
473        match_cal_and_date!(match (self, date): (c, d) => c.year_info(d).into())
474    }
475
476    fn extended_year(&self, date: &Self::DateInner) -> i32 {
477        match_cal_and_date!(match (self, date): (c, d) => c.extended_year(d))
478    }
479
480    fn is_in_leap_year(&self, date: &Self::DateInner) -> bool {
482        match_cal_and_date!(match (self, date): (c, d) => c.is_in_leap_year(d))
483    }
484
485    fn month(&self, date: &Self::DateInner) -> types::MonthInfo {
487        match_cal_and_date!(match (self, date): (c, d) => c.month(d))
488    }
489
490    fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth {
492        match_cal_and_date!(match (self, date): (c, d) => c.day_of_month(d))
493    }
494
495    fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear {
497        match_cal_and_date!(match (self, date): (c, d) => c.day_of_year(d))
498    }
499
500    fn debug_name(&self) -> &'static str {
501        match self.kind() {
502            AnyCalendarKind::Buddhist => "AnyCalendar (Buddhist)",
503            AnyCalendarKind::Chinese => "AnyCalendar (Chinese)",
504            AnyCalendarKind::Coptic => "AnyCalendar (Coptic)",
505            AnyCalendarKind::Dangi => "AnyCalendar (Dangi)",
506            AnyCalendarKind::Ethiopian => "AnyCalendar (Ethiopian, Amete Miret)",
507            AnyCalendarKind::EthiopianAmeteAlem => "AnyCalendar (Ethiopian, Amete Alem)",
508            AnyCalendarKind::Gregorian => "AnyCalendar (Gregorian)",
509            AnyCalendarKind::Hebrew => "AnyCalendar (Hebrew)",
510            AnyCalendarKind::Indian => "AnyCalendar (Indian)",
511            AnyCalendarKind::HijriTabularTypeIIFriday => {
512                "AnyCalendar (Hijri, tabular, type II leap years, Friday epoch)"
513            }
514            AnyCalendarKind::HijriTabularTypeIIThursday => {
515                "AnyCalendar (Hijri, tabular, type II leap years, Thursday epoch)"
516            }
517            AnyCalendarKind::HijriSimulatedMecca => "AnyCalendar (Hijri, simulated Mecca)",
518            AnyCalendarKind::HijriUmmAlQura => "AnyCalendar (Hijri, Umm al-Qura)",
519            AnyCalendarKind::Iso => "AnyCalendar (Iso)",
520            AnyCalendarKind::Japanese => "AnyCalendar (Japanese)",
521            AnyCalendarKind::JapaneseExtended => "AnyCalendar (Japanese, historical era data)",
522            AnyCalendarKind::Persian => "AnyCalendar (Persian)",
523            AnyCalendarKind::Roc => "AnyCalendar (Roc)",
524        }
525    }
526
527    fn calendar_algorithm(&self) -> Option<CalendarAlgorithm> {
528        match self {
529            Self::Buddhist(ref c) => c.calendar_algorithm(),
530            Self::Chinese(ref c) => c.calendar_algorithm(),
531            Self::Coptic(ref c) => c.calendar_algorithm(),
532            Self::Dangi(ref c) => c.calendar_algorithm(),
533            Self::Ethiopian(ref c) => c.calendar_algorithm(),
534            Self::Gregorian(ref c) => c.calendar_algorithm(),
535            Self::Hebrew(ref c) => c.calendar_algorithm(),
536            Self::Indian(ref c) => c.calendar_algorithm(),
537            Self::HijriSimulated(ref c) => c.calendar_algorithm(),
538            Self::HijriTabular(ref c) => c.calendar_algorithm(),
539            Self::HijriUmmAlQura(ref c) => c.calendar_algorithm(),
540            Self::Iso(ref c) => c.calendar_algorithm(),
541            Self::Japanese(ref c) => c.calendar_algorithm(),
542            Self::JapaneseExtended(ref c) => c.calendar_algorithm(),
543            Self::Persian(ref c) => c.calendar_algorithm(),
544            Self::Roc(ref c) => c.calendar_algorithm(),
545        }
546    }
547}
548
549impl AnyCalendar {
550    #[cfg(feature = "compiled_data")]
556    pub const fn new(kind: AnyCalendarKind) -> Self {
557        match kind {
558            AnyCalendarKind::Buddhist => AnyCalendar::Buddhist(Buddhist),
559            AnyCalendarKind::Chinese => AnyCalendar::Chinese(Chinese::new()),
560            AnyCalendarKind::Coptic => AnyCalendar::Coptic(Coptic),
561            AnyCalendarKind::Dangi => AnyCalendar::Dangi(Dangi::new()),
562            AnyCalendarKind::Ethiopian => AnyCalendar::Ethiopian(Ethiopian::new_with_era_style(
563                EthiopianEraStyle::AmeteMihret,
564            )),
565            AnyCalendarKind::EthiopianAmeteAlem => {
566                AnyCalendar::Ethiopian(Ethiopian::new_with_era_style(EthiopianEraStyle::AmeteAlem))
567            }
568            AnyCalendarKind::Gregorian => AnyCalendar::Gregorian(Gregorian),
569            AnyCalendarKind::Hebrew => AnyCalendar::Hebrew(Hebrew),
570            AnyCalendarKind::Indian => AnyCalendar::Indian(Indian),
571            AnyCalendarKind::HijriTabularTypeIIFriday => {
572                AnyCalendar::HijriTabular(HijriTabular::new(
573                    crate::cal::hijri::HijriTabularLeapYears::TypeII,
574                    HijriTabularEpoch::Friday,
575                ))
576            }
577            AnyCalendarKind::HijriSimulatedMecca => {
578                AnyCalendar::HijriSimulated(HijriSimulated::new_mecca())
579            }
580            AnyCalendarKind::HijriTabularTypeIIThursday => {
581                AnyCalendar::HijriTabular(HijriTabular::new(
582                    crate::cal::hijri::HijriTabularLeapYears::TypeII,
583                    HijriTabularEpoch::Thursday,
584                ))
585            }
586            AnyCalendarKind::HijriUmmAlQura => AnyCalendar::HijriUmmAlQura(HijriUmmAlQura::new()),
587            AnyCalendarKind::Iso => AnyCalendar::Iso(Iso),
588            AnyCalendarKind::Japanese => AnyCalendar::Japanese(Japanese::new()),
589            AnyCalendarKind::JapaneseExtended => {
590                AnyCalendar::JapaneseExtended(JapaneseExtended::new())
591            }
592            AnyCalendarKind::Persian => AnyCalendar::Persian(Persian),
593            AnyCalendarKind::Roc => AnyCalendar::Roc(Roc),
594        }
595    }
596
597    #[cfg(feature = "serde")]
598    #[doc = icu_provider::gen_buffer_unstable_docs!(BUFFER, Self::new)]
599    pub fn try_new_with_buffer_provider<P>(
600        provider: &P,
601        kind: AnyCalendarKind,
602    ) -> Result<Self, DataError>
603    where
604        P: BufferProvider + ?Sized,
605    {
606        Ok(match kind {
607            AnyCalendarKind::Buddhist => AnyCalendar::Buddhist(Buddhist),
608            AnyCalendarKind::Chinese => {
609                AnyCalendar::Chinese(Chinese::try_new_with_buffer_provider(provider)?)
610            }
611            AnyCalendarKind::Coptic => AnyCalendar::Coptic(Coptic),
612            AnyCalendarKind::Dangi => {
613                AnyCalendar::Dangi(Dangi::try_new_with_buffer_provider(provider)?)
614            }
615            AnyCalendarKind::Ethiopian => AnyCalendar::Ethiopian(Ethiopian::new_with_era_style(
616                EthiopianEraStyle::AmeteMihret,
617            )),
618            AnyCalendarKind::EthiopianAmeteAlem => {
619                AnyCalendar::Ethiopian(Ethiopian::new_with_era_style(EthiopianEraStyle::AmeteAlem))
620            }
621            AnyCalendarKind::Gregorian => AnyCalendar::Gregorian(Gregorian),
622            AnyCalendarKind::Hebrew => AnyCalendar::Hebrew(Hebrew),
623            AnyCalendarKind::Indian => AnyCalendar::Indian(Indian),
624            AnyCalendarKind::HijriTabularTypeIIFriday => {
625                AnyCalendar::HijriTabular(HijriTabular::new(
626                    crate::cal::hijri::HijriTabularLeapYears::TypeII,
627                    HijriTabularEpoch::Friday,
628                ))
629            }
630            AnyCalendarKind::HijriSimulatedMecca => AnyCalendar::HijriSimulated(
631                HijriSimulated::try_new_mecca_with_buffer_provider(provider)?,
632            ),
633            AnyCalendarKind::HijriTabularTypeIIThursday => {
634                AnyCalendar::HijriTabular(HijriTabular::new(
635                    crate::cal::hijri::HijriTabularLeapYears::TypeII,
636                    HijriTabularEpoch::Thursday,
637                ))
638            }
639            AnyCalendarKind::HijriUmmAlQura => AnyCalendar::HijriUmmAlQura(HijriUmmAlQura::new()),
640            AnyCalendarKind::Iso => AnyCalendar::Iso(Iso),
641            AnyCalendarKind::Japanese => {
642                AnyCalendar::Japanese(Japanese::try_new_with_buffer_provider(provider)?)
643            }
644            AnyCalendarKind::JapaneseExtended => AnyCalendar::JapaneseExtended(
645                JapaneseExtended::try_new_with_buffer_provider(provider)?,
646            ),
647            AnyCalendarKind::Persian => AnyCalendar::Persian(Persian),
648            AnyCalendarKind::Roc => AnyCalendar::Roc(Roc),
649        })
650    }
651
652    #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new)]
653    pub fn try_new_unstable<P>(provider: &P, kind: AnyCalendarKind) -> Result<Self, DataError>
654    where
655        P: DataProvider<crate::provider::CalendarJapaneseModernV1>
656            + DataProvider<crate::provider::CalendarJapaneseExtendedV1>
657            + DataProvider<crate::provider::CalendarChineseV1>
658            + DataProvider<crate::provider::CalendarDangiV1>
659            + DataProvider<crate::provider::CalendarHijriSimulatedMeccaV1>
660            + ?Sized,
661    {
662        Ok(match kind {
663            AnyCalendarKind::Buddhist => AnyCalendar::Buddhist(Buddhist),
664            AnyCalendarKind::Chinese => AnyCalendar::Chinese(Chinese::try_new_unstable(provider)?),
665            AnyCalendarKind::Coptic => AnyCalendar::Coptic(Coptic),
666            AnyCalendarKind::Dangi => AnyCalendar::Dangi(Dangi::try_new_unstable(provider)?),
667            AnyCalendarKind::Ethiopian => AnyCalendar::Ethiopian(Ethiopian::new_with_era_style(
668                EthiopianEraStyle::AmeteMihret,
669            )),
670            AnyCalendarKind::EthiopianAmeteAlem => {
671                AnyCalendar::Ethiopian(Ethiopian::new_with_era_style(EthiopianEraStyle::AmeteAlem))
672            }
673            AnyCalendarKind::Gregorian => AnyCalendar::Gregorian(Gregorian),
674            AnyCalendarKind::Hebrew => AnyCalendar::Hebrew(Hebrew),
675            AnyCalendarKind::Indian => AnyCalendar::Indian(Indian),
676            AnyCalendarKind::HijriTabularTypeIIFriday => {
677                AnyCalendar::HijriTabular(HijriTabular::new(
678                    crate::cal::hijri::HijriTabularLeapYears::TypeII,
679                    HijriTabularEpoch::Friday,
680                ))
681            }
682            AnyCalendarKind::HijriSimulatedMecca => {
683                AnyCalendar::HijriSimulated(HijriSimulated::try_new_mecca_unstable(provider)?)
684            }
685            AnyCalendarKind::HijriTabularTypeIIThursday => {
686                AnyCalendar::HijriTabular(HijriTabular::new(
687                    crate::cal::hijri::HijriTabularLeapYears::TypeII,
688                    HijriTabularEpoch::Thursday,
689                ))
690            }
691            AnyCalendarKind::HijriUmmAlQura => AnyCalendar::HijriUmmAlQura(HijriUmmAlQura::new()),
692            AnyCalendarKind::Iso => AnyCalendar::Iso(Iso),
693            AnyCalendarKind::Japanese => {
694                AnyCalendar::Japanese(Japanese::try_new_unstable(provider)?)
695            }
696            AnyCalendarKind::JapaneseExtended => {
697                AnyCalendar::JapaneseExtended(JapaneseExtended::try_new_unstable(provider)?)
698            }
699            AnyCalendarKind::Persian => AnyCalendar::Persian(Persian),
700            AnyCalendarKind::Roc => AnyCalendar::Roc(Roc),
701        })
702    }
703
704    pub fn kind(&self) -> AnyCalendarKind {
706        match *self {
707            Self::Buddhist(_) => AnyCalendarKind::Buddhist,
708            Self::Chinese(_) => AnyCalendarKind::Chinese,
709            Self::Coptic(_) => AnyCalendarKind::Coptic,
710            Self::Dangi(_) => AnyCalendarKind::Dangi,
711            Self::Ethiopian(ref e) => IntoAnyCalendar::kind(e),
712            Self::Gregorian(_) => AnyCalendarKind::Gregorian,
713            Self::Hebrew(_) => AnyCalendarKind::Hebrew,
714            Self::Indian(_) => AnyCalendarKind::Indian,
715            Self::HijriTabular(ref h) => IntoAnyCalendar::kind(h),
716            Self::HijriSimulated(ref h) => IntoAnyCalendar::kind(h),
717            Self::HijriUmmAlQura(_) => AnyCalendarKind::HijriUmmAlQura,
718            Self::Iso(_) => AnyCalendarKind::Iso,
719            Self::Japanese(_) => AnyCalendarKind::Japanese,
720            Self::JapaneseExtended(_) => AnyCalendarKind::JapaneseExtended,
721            Self::Persian(_) => AnyCalendarKind::Persian,
722            Self::Roc(_) => AnyCalendarKind::Roc,
723        }
724    }
725}
726
727impl<C: AsCalendar<Calendar = AnyCalendar>> Date<C> {
728    pub fn convert_any<'a>(&self, calendar: &'a AnyCalendar) -> Date<Ref<'a, AnyCalendar>> {
730        if calendar.kind() != self.calendar.as_calendar().kind() {
731            Date::new_from_iso(self.to_iso(), Ref(calendar))
732        } else {
733            Date {
734                inner: self.inner,
735                calendar: Ref(calendar),
736            }
737        }
738    }
739}
740
741impl AnyDateInner {
742    fn kind(&self) -> AnyCalendarKind {
743        match *self {
744            AnyDateInner::Buddhist(_) => AnyCalendarKind::Buddhist,
745            AnyDateInner::Chinese(_) => AnyCalendarKind::Chinese,
746            AnyDateInner::Coptic(_) => AnyCalendarKind::Coptic,
747            AnyDateInner::Dangi(_) => AnyCalendarKind::Dangi,
748            AnyDateInner::Ethiopian(_) => AnyCalendarKind::Ethiopian,
749            AnyDateInner::Gregorian(_) => AnyCalendarKind::Gregorian,
750            AnyDateInner::Hebrew(_) => AnyCalendarKind::Hebrew,
751            AnyDateInner::Indian(_) => AnyCalendarKind::Indian,
752            AnyDateInner::HijriTabular(
753                _,
754                HijriTabularLeapYears::TypeII,
755                HijriTabularEpoch::Friday,
756            ) => AnyCalendarKind::HijriTabularTypeIIFriday,
757            AnyDateInner::HijriSimulated(_) => AnyCalendarKind::HijriSimulatedMecca,
758            AnyDateInner::HijriTabular(
759                _,
760                HijriTabularLeapYears::TypeII,
761                HijriTabularEpoch::Thursday,
762            ) => AnyCalendarKind::HijriTabularTypeIIThursday,
763            AnyDateInner::HijriUmmAlQura(_) => AnyCalendarKind::HijriUmmAlQura,
764            AnyDateInner::Iso(_) => AnyCalendarKind::Iso,
765            AnyDateInner::Japanese(_) => AnyCalendarKind::Japanese,
766            AnyDateInner::JapaneseExtended(_) => AnyCalendarKind::JapaneseExtended,
767            AnyDateInner::Persian(_) => AnyCalendarKind::Persian,
768            AnyDateInner::Roc(_) => AnyCalendarKind::Roc,
769        }
770    }
771}
772
773#[non_exhaustive]
775#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
776pub enum AnyCalendarKind {
777    Buddhist,
779    Chinese,
781    Coptic,
783    Dangi,
785    Ethiopian,
787    EthiopianAmeteAlem,
789    Gregorian,
791    Hebrew,
793    Indian,
795    HijriTabularTypeIIFriday,
797    HijriSimulatedMecca,
799    HijriTabularTypeIIThursday,
801    HijriUmmAlQura,
803    Iso,
805    Japanese,
807    JapaneseExtended,
809    Persian,
811    Roc,
813}
814
815impl AnyCalendarKind {
816    pub fn new(prefs: CalendarPreferences) -> Self {
818        let algo = prefs.calendar_algorithm;
819        let region = prefs.locale_preferences.region();
820        if let Some(kind) = algo.and_then(|a| a.try_into().ok()) {
821            return kind;
822        }
823        if region == Some(region!("TH")) {
824            AnyCalendarKind::Buddhist
825        } else if region == Some(region!("AF")) || region == Some(region!("IR")) {
826            AnyCalendarKind::Persian
827        } else if region == Some(region!("SA")) && algo == Some(CalendarAlgorithm::Hijri(None)) {
828            AnyCalendarKind::HijriSimulatedMecca
829        } else {
830            AnyCalendarKind::Gregorian
831        }
832    }
833
834    fn debug_name(self) -> &'static str {
835        match self {
836            AnyCalendarKind::Buddhist => Buddhist.debug_name(),
837            AnyCalendarKind::Chinese => Chinese::DEBUG_NAME,
838            AnyCalendarKind::Coptic => Coptic.debug_name(),
839            AnyCalendarKind::Dangi => Dangi::DEBUG_NAME,
840            AnyCalendarKind::Ethiopian => Ethiopian(false).debug_name(),
841            AnyCalendarKind::EthiopianAmeteAlem => Ethiopian(true).debug_name(),
842            AnyCalendarKind::Gregorian => Gregorian.debug_name(),
843            AnyCalendarKind::Hebrew => Hebrew.debug_name(),
844            AnyCalendarKind::Indian => Indian.debug_name(),
845            AnyCalendarKind::HijriTabularTypeIIFriday => HijriTabular::new(
846                crate::cal::hijri::HijriTabularLeapYears::TypeII,
847                HijriTabularEpoch::Friday,
848            )
849            .debug_name(),
850            AnyCalendarKind::HijriSimulatedMecca => HijriSimulated::DEBUG_NAME,
851            AnyCalendarKind::HijriTabularTypeIIThursday => HijriTabular::new(
852                crate::cal::hijri::HijriTabularLeapYears::TypeII,
853                HijriTabularEpoch::Thursday,
854            )
855            .debug_name(),
856            AnyCalendarKind::HijriUmmAlQura => HijriUmmAlQura::DEBUG_NAME,
857            AnyCalendarKind::Iso => Iso.debug_name(),
858            AnyCalendarKind::Japanese => Japanese::DEBUG_NAME,
859            AnyCalendarKind::JapaneseExtended => JapaneseExtended::DEBUG_NAME,
860            AnyCalendarKind::Persian => Persian.debug_name(),
861            AnyCalendarKind::Roc => Roc.debug_name(),
862        }
863    }
864}
865
866impl TryFrom<CalendarAlgorithm> for AnyCalendarKind {
867    type Error = ();
868    fn try_from(v: CalendarAlgorithm) -> Result<Self, Self::Error> {
869        use CalendarAlgorithm::*;
870        match v {
871            Buddhist => Ok(AnyCalendarKind::Buddhist),
872            Chinese => Ok(AnyCalendarKind::Chinese),
873            Coptic => Ok(AnyCalendarKind::Coptic),
874            Dangi => Ok(AnyCalendarKind::Dangi),
875            Ethioaa => Ok(AnyCalendarKind::EthiopianAmeteAlem),
876            Ethiopic => Ok(AnyCalendarKind::Ethiopian),
877            Gregory => Ok(AnyCalendarKind::Gregorian),
878            Hebrew => Ok(AnyCalendarKind::Hebrew),
879            Indian => Ok(AnyCalendarKind::Indian),
880            Hijri(None) => Err(()),
881            Hijri(Some(HijriCalendarAlgorithm::Umalqura)) => Ok(AnyCalendarKind::HijriUmmAlQura),
882            Hijri(Some(HijriCalendarAlgorithm::Tbla)) => {
883                Ok(AnyCalendarKind::HijriTabularTypeIIThursday)
884            }
885            Hijri(Some(HijriCalendarAlgorithm::Civil)) => {
886                Ok(AnyCalendarKind::HijriTabularTypeIIFriday)
887            }
888            Hijri(Some(HijriCalendarAlgorithm::Rgsa)) => Ok(AnyCalendarKind::HijriSimulatedMecca),
889            Iso8601 => Ok(AnyCalendarKind::Iso),
890            Japanese => Ok(AnyCalendarKind::Japanese),
891            Persian => Ok(AnyCalendarKind::Persian),
892            Roc => Ok(AnyCalendarKind::Roc),
893            _ => {
894                debug_assert!(false, "unknown calendar algorithm {v:?}");
895                Err(())
896            }
897        }
898    }
899}
900
901impl fmt::Display for AnyCalendarKind {
902    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
903        fmt::Debug::fmt(self, f)
904    }
905}
906
907pub trait IntoAnyCalendar: Calendar + Sized {
909    fn to_any(self) -> AnyCalendar;
913
914    fn kind(&self) -> AnyCalendarKind;
916
917    fn from_any(any: AnyCalendar) -> Result<Self, AnyCalendar>;
922
923    fn from_any_ref(any: &AnyCalendar) -> Option<&Self>;
927
928    fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner;
932}
933
934impl IntoAnyCalendar for AnyCalendar {
935    #[inline]
936    fn to_any(self) -> AnyCalendar {
937        self
938    }
939    #[inline]
940    fn kind(&self) -> AnyCalendarKind {
941        self.kind()
942    }
943    #[inline]
944    fn from_any(any: AnyCalendar) -> Result<Self, AnyCalendar> {
945        Ok(any)
946    }
947    #[inline]
948    fn from_any_ref(any: &AnyCalendar) -> Option<&Self> {
949        Some(any)
950    }
951    #[inline]
952    fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
953        *d
954    }
955}
956
957impl IntoAnyCalendar for Buddhist {
958    #[inline]
959    fn to_any(self) -> AnyCalendar {
960        AnyCalendar::Buddhist(Buddhist)
961    }
962    #[inline]
963    fn kind(&self) -> AnyCalendarKind {
964        AnyCalendarKind::Buddhist
965    }
966    #[inline]
967    fn from_any(any: AnyCalendar) -> Result<Self, AnyCalendar> {
968        if let AnyCalendar::Buddhist(cal) = any {
969            Ok(cal)
970        } else {
971            Err(any)
972        }
973    }
974    #[inline]
975    fn from_any_ref(any: &AnyCalendar) -> Option<&Self> {
976        if let AnyCalendar::Buddhist(cal) = any {
977            Some(cal)
978        } else {
979            None
980        }
981    }
982    #[inline]
983    fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
984        AnyDateInner::Buddhist(*d)
985    }
986}
987
988impl From<Buddhist> for AnyCalendar {
989    fn from(value: Buddhist) -> AnyCalendar {
990        value.to_any()
991    }
992}
993
994impl IntoAnyCalendar for Chinese {
995    #[inline]
996    fn to_any(self) -> AnyCalendar {
997        AnyCalendar::Chinese(self)
998    }
999    #[inline]
1000    fn kind(&self) -> AnyCalendarKind {
1001        AnyCalendarKind::Chinese
1002    }
1003    #[inline]
1004    fn from_any(any: AnyCalendar) -> Result<Self, AnyCalendar> {
1005        if let AnyCalendar::Chinese(cal) = any {
1006            Ok(cal)
1007        } else {
1008            Err(any)
1009        }
1010    }
1011    #[inline]
1012    fn from_any_ref(any: &AnyCalendar) -> Option<&Self> {
1013        if let AnyCalendar::Chinese(cal) = any {
1014            Some(cal)
1015        } else {
1016            None
1017        }
1018    }
1019    #[inline]
1020    fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
1021        AnyDateInner::Chinese(*d)
1022    }
1023}
1024
1025impl From<Chinese> for AnyCalendar {
1026    fn from(value: Chinese) -> AnyCalendar {
1027        value.to_any()
1028    }
1029}
1030
1031impl IntoAnyCalendar for Coptic {
1032    #[inline]
1033    fn to_any(self) -> AnyCalendar {
1034        AnyCalendar::Coptic(Coptic)
1035    }
1036    #[inline]
1037    fn kind(&self) -> AnyCalendarKind {
1038        AnyCalendarKind::Coptic
1039    }
1040    #[inline]
1041    fn from_any(any: AnyCalendar) -> Result<Self, AnyCalendar> {
1042        if let AnyCalendar::Coptic(cal) = any {
1043            Ok(cal)
1044        } else {
1045            Err(any)
1046        }
1047    }
1048    #[inline]
1049    fn from_any_ref(any: &AnyCalendar) -> Option<&Self> {
1050        if let AnyCalendar::Coptic(cal) = any {
1051            Some(cal)
1052        } else {
1053            None
1054        }
1055    }
1056    #[inline]
1057    fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
1058        AnyDateInner::Coptic(*d)
1059    }
1060}
1061
1062impl From<Coptic> for AnyCalendar {
1063    fn from(value: Coptic) -> AnyCalendar {
1064        value.to_any()
1065    }
1066}
1067
1068impl IntoAnyCalendar for Dangi {
1069    #[inline]
1070    fn to_any(self) -> AnyCalendar {
1071        AnyCalendar::Dangi(self)
1072    }
1073    #[inline]
1074    fn kind(&self) -> AnyCalendarKind {
1075        AnyCalendarKind::Dangi
1076    }
1077    #[inline]
1078    fn from_any(any: AnyCalendar) -> Result<Self, AnyCalendar> {
1079        if let AnyCalendar::Dangi(cal) = any {
1080            Ok(cal)
1081        } else {
1082            Err(any)
1083        }
1084    }
1085    #[inline]
1086    fn from_any_ref(any: &AnyCalendar) -> Option<&Self> {
1087        if let AnyCalendar::Dangi(cal) = any {
1088            Some(cal)
1089        } else {
1090            None
1091        }
1092    }
1093    #[inline]
1094    fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
1095        AnyDateInner::Dangi(*d)
1096    }
1097}
1098
1099impl From<Dangi> for AnyCalendar {
1100    fn from(value: Dangi) -> AnyCalendar {
1101        value.to_any()
1102    }
1103}
1104
1105impl IntoAnyCalendar for Ethiopian {
1106    #[inline]
1108    fn to_any(self) -> AnyCalendar {
1109        AnyCalendar::Ethiopian(self)
1110    }
1111    #[inline]
1112    fn kind(&self) -> AnyCalendarKind {
1113        if self.0 {
1114            AnyCalendarKind::EthiopianAmeteAlem
1115        } else {
1116            AnyCalendarKind::Ethiopian
1117        }
1118    }
1119    #[inline]
1120    fn from_any(any: AnyCalendar) -> Result<Self, AnyCalendar> {
1121        if let AnyCalendar::Ethiopian(cal) = any {
1122            Ok(cal)
1123        } else {
1124            Err(any)
1125        }
1126    }
1127    #[inline]
1128    fn from_any_ref(any: &AnyCalendar) -> Option<&Self> {
1129        if let AnyCalendar::Ethiopian(cal) = any {
1130            Some(cal)
1131        } else {
1132            None
1133        }
1134    }
1135    #[inline]
1136    fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
1137        AnyDateInner::Ethiopian(*d)
1138    }
1139}
1140
1141impl From<Ethiopian> for AnyCalendar {
1142    fn from(value: Ethiopian) -> AnyCalendar {
1143        value.to_any()
1144    }
1145}
1146
1147impl IntoAnyCalendar for Gregorian {
1148    #[inline]
1149    fn to_any(self) -> AnyCalendar {
1150        AnyCalendar::Gregorian(Gregorian)
1151    }
1152    #[inline]
1153    fn kind(&self) -> AnyCalendarKind {
1154        AnyCalendarKind::Gregorian
1155    }
1156    #[inline]
1157    fn from_any(any: AnyCalendar) -> Result<Self, AnyCalendar> {
1158        if let AnyCalendar::Gregorian(cal) = any {
1159            Ok(cal)
1160        } else {
1161            Err(any)
1162        }
1163    }
1164    #[inline]
1165    fn from_any_ref(any: &AnyCalendar) -> Option<&Self> {
1166        if let AnyCalendar::Gregorian(cal) = any {
1167            Some(cal)
1168        } else {
1169            None
1170        }
1171    }
1172    #[inline]
1173    fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
1174        AnyDateInner::Gregorian(*d)
1175    }
1176}
1177
1178impl From<Gregorian> for AnyCalendar {
1179    fn from(value: Gregorian) -> AnyCalendar {
1180        value.to_any()
1181    }
1182}
1183
1184impl IntoAnyCalendar for Hebrew {
1185    #[inline]
1186    fn to_any(self) -> AnyCalendar {
1187        AnyCalendar::Hebrew(Hebrew)
1188    }
1189    #[inline]
1190    fn kind(&self) -> AnyCalendarKind {
1191        AnyCalendarKind::Hebrew
1192    }
1193    #[inline]
1194    fn from_any(any: AnyCalendar) -> Result<Self, AnyCalendar> {
1195        if let AnyCalendar::Hebrew(cal) = any {
1196            Ok(cal)
1197        } else {
1198            Err(any)
1199        }
1200    }
1201    #[inline]
1202    fn from_any_ref(any: &AnyCalendar) -> Option<&Self> {
1203        if let AnyCalendar::Hebrew(cal) = any {
1204            Some(cal)
1205        } else {
1206            None
1207        }
1208    }
1209    #[inline]
1210    fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
1211        AnyDateInner::Hebrew(*d)
1212    }
1213}
1214
1215impl From<Hebrew> for AnyCalendar {
1216    fn from(value: Hebrew) -> AnyCalendar {
1217        value.to_any()
1218    }
1219}
1220
1221impl IntoAnyCalendar for Indian {
1222    #[inline]
1223    fn to_any(self) -> AnyCalendar {
1224        AnyCalendar::Indian(Indian)
1225    }
1226    #[inline]
1227    fn kind(&self) -> AnyCalendarKind {
1228        AnyCalendarKind::Indian
1229    }
1230    #[inline]
1231    fn from_any(any: AnyCalendar) -> Result<Self, AnyCalendar> {
1232        if let AnyCalendar::Indian(cal) = any {
1233            Ok(cal)
1234        } else {
1235            Err(any)
1236        }
1237    }
1238    #[inline]
1239    fn from_any_ref(any: &AnyCalendar) -> Option<&Self> {
1240        if let AnyCalendar::Indian(cal) = any {
1241            Some(cal)
1242        } else {
1243            None
1244        }
1245    }
1246    #[inline]
1247    fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
1248        AnyDateInner::Indian(*d)
1249    }
1250}
1251
1252impl From<Indian> for AnyCalendar {
1253    fn from(value: Indian) -> AnyCalendar {
1254        value.to_any()
1255    }
1256}
1257
1258impl IntoAnyCalendar for HijriTabular {
1259    #[inline]
1260    fn to_any(self) -> AnyCalendar {
1261        AnyCalendar::HijriTabular(self)
1262    }
1263    #[inline]
1264    fn kind(&self) -> AnyCalendarKind {
1265        match (self.leap_years, self.epoch) {
1266            (HijriTabularLeapYears::TypeII, HijriTabularEpoch::Friday) => {
1267                AnyCalendarKind::HijriTabularTypeIIFriday
1268            }
1269            (HijriTabularLeapYears::TypeII, HijriTabularEpoch::Thursday) => {
1270                AnyCalendarKind::HijriTabularTypeIIThursday
1271            }
1272        }
1273    }
1274    #[inline]
1275    fn from_any(any: AnyCalendar) -> Result<Self, AnyCalendar> {
1276        if let AnyCalendar::HijriTabular(cal) = any {
1277            Ok(cal)
1278        } else {
1279            Err(any)
1280        }
1281    }
1282    #[inline]
1283    fn from_any_ref(any: &AnyCalendar) -> Option<&Self> {
1284        if let AnyCalendar::HijriTabular(cal) = any {
1285            Some(cal)
1286        } else {
1287            None
1288        }
1289    }
1290    #[inline]
1291    fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
1292        AnyDateInner::HijriTabular(*d, self.leap_years, self.epoch)
1293    }
1294}
1295
1296impl From<HijriTabular> for AnyCalendar {
1297    fn from(value: HijriTabular) -> AnyCalendar {
1298        value.to_any()
1299    }
1300}
1301
1302impl IntoAnyCalendar for HijriSimulated {
1303    #[inline]
1304    fn to_any(self) -> AnyCalendar {
1305        AnyCalendar::HijriSimulated(self)
1306    }
1307    #[inline]
1308    fn kind(&self) -> AnyCalendarKind {
1309        match self.location {
1310            HijriSimulatedLocation::Mecca => AnyCalendarKind::HijriSimulatedMecca,
1311        }
1312    }
1313    #[inline]
1314    fn from_any(any: AnyCalendar) -> Result<Self, AnyCalendar> {
1315        if let AnyCalendar::HijriSimulated(cal) = any {
1316            Ok(cal)
1317        } else {
1318            Err(any)
1319        }
1320    }
1321    #[inline]
1322    fn from_any_ref(any: &AnyCalendar) -> Option<&Self> {
1323        if let AnyCalendar::HijriSimulated(cal) = any {
1324            Some(cal)
1325        } else {
1326            None
1327        }
1328    }
1329    #[inline]
1330    fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
1331        AnyDateInner::HijriSimulated(*d)
1332    }
1333}
1334
1335impl From<HijriSimulated> for AnyCalendar {
1336    fn from(value: HijriSimulated) -> AnyCalendar {
1337        value.to_any()
1338    }
1339}
1340
1341impl IntoAnyCalendar for HijriUmmAlQura {
1342    #[inline]
1343    fn to_any(self) -> AnyCalendar {
1344        AnyCalendar::HijriUmmAlQura(self)
1345    }
1346    #[inline]
1347    fn kind(&self) -> AnyCalendarKind {
1348        AnyCalendarKind::HijriUmmAlQura
1349    }
1350    #[inline]
1351    fn from_any(any: AnyCalendar) -> Result<Self, AnyCalendar> {
1352        if let AnyCalendar::HijriUmmAlQura(cal) = any {
1353            Ok(cal)
1354        } else {
1355            Err(any)
1356        }
1357    }
1358    #[inline]
1359    fn from_any_ref(any: &AnyCalendar) -> Option<&Self> {
1360        if let AnyCalendar::HijriUmmAlQura(cal) = any {
1361            Some(cal)
1362        } else {
1363            None
1364        }
1365    }
1366    #[inline]
1367    fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
1368        AnyDateInner::HijriUmmAlQura(*d)
1369    }
1370}
1371
1372impl From<HijriUmmAlQura> for AnyCalendar {
1373    fn from(value: HijriUmmAlQura) -> AnyCalendar {
1374        value.to_any()
1375    }
1376}
1377
1378impl IntoAnyCalendar for Iso {
1379    #[inline]
1380    fn to_any(self) -> AnyCalendar {
1381        AnyCalendar::Iso(Iso)
1382    }
1383    #[inline]
1384    fn kind(&self) -> AnyCalendarKind {
1385        AnyCalendarKind::Iso
1386    }
1387    #[inline]
1388    fn from_any(any: AnyCalendar) -> Result<Self, AnyCalendar> {
1389        if let AnyCalendar::Iso(cal) = any {
1390            Ok(cal)
1391        } else {
1392            Err(any)
1393        }
1394    }
1395    #[inline]
1396    fn from_any_ref(any: &AnyCalendar) -> Option<&Self> {
1397        if let AnyCalendar::Iso(cal) = any {
1398            Some(cal)
1399        } else {
1400            None
1401        }
1402    }
1403    #[inline]
1404    fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
1405        AnyDateInner::Iso(*d)
1406    }
1407}
1408
1409impl From<Iso> for AnyCalendar {
1410    fn from(value: Iso) -> AnyCalendar {
1411        value.to_any()
1412    }
1413}
1414
1415impl IntoAnyCalendar for Japanese {
1416    #[inline]
1417    fn to_any(self) -> AnyCalendar {
1418        AnyCalendar::Japanese(self)
1419    }
1420    #[inline]
1421    fn kind(&self) -> AnyCalendarKind {
1422        AnyCalendarKind::Japanese
1423    }
1424    #[inline]
1425    fn from_any(any: AnyCalendar) -> Result<Self, AnyCalendar> {
1426        if let AnyCalendar::Japanese(cal) = any {
1427            Ok(cal)
1428        } else {
1429            Err(any)
1430        }
1431    }
1432    #[inline]
1433    fn from_any_ref(any: &AnyCalendar) -> Option<&Self> {
1434        if let AnyCalendar::Japanese(cal) = any {
1435            Some(cal)
1436        } else {
1437            None
1438        }
1439    }
1440    #[inline]
1441    fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
1442        AnyDateInner::Japanese(*d)
1443    }
1444}
1445
1446impl From<Japanese> for AnyCalendar {
1447    fn from(value: Japanese) -> AnyCalendar {
1448        value.to_any()
1449    }
1450}
1451
1452impl IntoAnyCalendar for JapaneseExtended {
1453    #[inline]
1454    fn to_any(self) -> AnyCalendar {
1455        AnyCalendar::JapaneseExtended(self)
1456    }
1457    #[inline]
1458    fn kind(&self) -> AnyCalendarKind {
1459        AnyCalendarKind::JapaneseExtended
1460    }
1461    #[inline]
1462    fn from_any(any: AnyCalendar) -> Result<Self, AnyCalendar> {
1463        if let AnyCalendar::JapaneseExtended(cal) = any {
1464            Ok(cal)
1465        } else {
1466            Err(any)
1467        }
1468    }
1469    #[inline]
1470    fn from_any_ref(any: &AnyCalendar) -> Option<&Self> {
1471        if let AnyCalendar::JapaneseExtended(cal) = any {
1472            Some(cal)
1473        } else {
1474            None
1475        }
1476    }
1477    #[inline]
1478    fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
1479        AnyDateInner::JapaneseExtended(*d)
1480    }
1481}
1482
1483impl From<JapaneseExtended> for AnyCalendar {
1484    fn from(value: JapaneseExtended) -> AnyCalendar {
1485        value.to_any()
1486    }
1487}
1488
1489impl IntoAnyCalendar for Persian {
1490    #[inline]
1491    fn to_any(self) -> AnyCalendar {
1492        AnyCalendar::Persian(Persian)
1493    }
1494    #[inline]
1495    fn kind(&self) -> AnyCalendarKind {
1496        AnyCalendarKind::Persian
1497    }
1498    #[inline]
1499    fn from_any(any: AnyCalendar) -> Result<Self, AnyCalendar> {
1500        if let AnyCalendar::Persian(cal) = any {
1501            Ok(cal)
1502        } else {
1503            Err(any)
1504        }
1505    }
1506    #[inline]
1507    fn from_any_ref(any: &AnyCalendar) -> Option<&Self> {
1508        if let AnyCalendar::Persian(cal) = any {
1509            Some(cal)
1510        } else {
1511            None
1512        }
1513    }
1514    #[inline]
1515    fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
1516        AnyDateInner::Persian(*d)
1517    }
1518}
1519
1520impl From<Persian> for AnyCalendar {
1521    fn from(value: Persian) -> AnyCalendar {
1522        value.to_any()
1523    }
1524}
1525
1526impl IntoAnyCalendar for Roc {
1527    #[inline]
1528    fn to_any(self) -> AnyCalendar {
1529        AnyCalendar::Roc(Roc)
1530    }
1531    #[inline]
1532    fn kind(&self) -> AnyCalendarKind {
1533        AnyCalendarKind::Roc
1534    }
1535    #[inline]
1536    fn from_any(any: AnyCalendar) -> Result<Self, AnyCalendar> {
1537        if let AnyCalendar::Roc(cal) = any {
1538            Ok(cal)
1539        } else {
1540            Err(any)
1541        }
1542    }
1543    #[inline]
1544    fn from_any_ref(any: &AnyCalendar) -> Option<&Self> {
1545        if let AnyCalendar::Roc(cal) = any {
1546            Some(cal)
1547        } else {
1548            None
1549        }
1550    }
1551    #[inline]
1552    fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
1553        AnyDateInner::Roc(*d)
1554    }
1555}
1556
1557impl From<Roc> for AnyCalendar {
1558    fn from(value: Roc) -> AnyCalendar {
1559        value.to_any()
1560    }
1561}
1562
1563#[cfg(test)]
1564mod tests {
1565    use tinystr::tinystr;
1566    use types::MonthCode;
1567
1568    use super::*;
1569    use crate::Ref;
1570
1571    #[track_caller]
1572    fn single_test_roundtrip(
1573        calendar: Ref<AnyCalendar>,
1574        era: Option<(&str, Option<u8>)>,
1575        year: i32,
1576        month_code: &str,
1577        day: u8,
1578    ) {
1579        let month = types::MonthCode(month_code.parse().expect("month code must parse"));
1580
1581        let date = Date::try_new_from_codes(era.map(|x| x.0), year, month, day, calendar)
1582            .unwrap_or_else(|e| {
1583                panic!(
1584                    "Failed to construct date for {} with {era:?}, {year}, {month}, {day}: {e:?}",
1585                    calendar.debug_name(),
1586                )
1587            });
1588
1589        let roundtrip_year = date.year();
1590        let roundtrip_year = roundtrip_year.era_year_or_related_iso();
1592        let roundtrip_month = date.month().standard_code;
1593        let roundtrip_day = date.day_of_month().0;
1594
1595        assert_eq!(
1596            (year, month, day),
1597            (roundtrip_year, roundtrip_month, roundtrip_day),
1598            "Failed to roundtrip for calendar {}",
1599            calendar.debug_name()
1600        );
1601
1602        if let Some((era_code, era_index)) = era {
1603            let roundtrip_era_year = date.year().era().expect("year type should be era");
1604            assert_eq!(
1605                (era_code, era_index),
1606                (
1607                    roundtrip_era_year.era.as_str(),
1608                    roundtrip_era_year.era_index
1609                ),
1610                "Failed to roundtrip era for calendar {}",
1611                calendar.debug_name()
1612            )
1613        }
1614
1615        let iso = date.to_iso();
1616        let reconstructed = Date::new_from_iso(iso, calendar);
1617        assert_eq!(
1618            date, reconstructed,
1619            "Failed to roundtrip via iso with {era:?}, {year}, {month}, {day}"
1620        )
1621    }
1622
1623    #[track_caller]
1624    fn single_test_error(
1625        calendar: Ref<AnyCalendar>,
1626        era: Option<(&str, Option<u8>)>,
1627        year: i32,
1628        month_code: &str,
1629        day: u8,
1630        error: DateError,
1631    ) {
1632        let month = types::MonthCode(month_code.parse().expect("month code must parse"));
1633
1634        let date = Date::try_new_from_codes(era.map(|x| x.0), year, month, day, calendar);
1635        assert_eq!(
1636            date,
1637            Err(error),
1638            "Construction with {era:?}, {year}, {month}, {day} did not return {error:?}"
1639        )
1640    }
1641
1642    #[test]
1643    fn test_any_construction() {
1644        let buddhist = AnyCalendar::new(AnyCalendarKind::Buddhist);
1645        let chinese = AnyCalendar::new(AnyCalendarKind::Chinese);
1646        let coptic = AnyCalendar::new(AnyCalendarKind::Coptic);
1647        let dangi = AnyCalendar::new(AnyCalendarKind::Dangi);
1648        let ethioaa = AnyCalendar::new(AnyCalendarKind::EthiopianAmeteAlem);
1649        let ethiopian = AnyCalendar::new(AnyCalendarKind::Ethiopian);
1650        let gregorian = AnyCalendar::new(AnyCalendarKind::Gregorian);
1651        let hebrew = AnyCalendar::new(AnyCalendarKind::Hebrew);
1652        let indian = AnyCalendar::new(AnyCalendarKind::Indian);
1653        let hijri_civil: AnyCalendar = AnyCalendar::new(AnyCalendarKind::HijriTabularTypeIIFriday);
1654        let hijri_simulated: AnyCalendar = AnyCalendar::new(AnyCalendarKind::HijriSimulatedMecca);
1655        let hijri_astronomical: AnyCalendar =
1656            AnyCalendar::new(AnyCalendarKind::HijriTabularTypeIIThursday);
1657        let hijri_umm_al_qura: AnyCalendar = AnyCalendar::new(AnyCalendarKind::HijriUmmAlQura);
1658        let japanese = AnyCalendar::new(AnyCalendarKind::Japanese);
1659        let japanext = AnyCalendar::new(AnyCalendarKind::JapaneseExtended);
1660        let persian = AnyCalendar::new(AnyCalendarKind::Persian);
1661        let roc = AnyCalendar::new(AnyCalendarKind::Roc);
1662        let buddhist = Ref(&buddhist);
1663        let chinese = Ref(&chinese);
1664        let coptic = Ref(&coptic);
1665        let dangi = Ref(&dangi);
1666        let ethioaa = Ref(ðioaa);
1667        let ethiopian = Ref(ðiopian);
1668        let gregorian = Ref(&gregorian);
1669        let hebrew = Ref(&hebrew);
1670        let indian = Ref(&indian);
1671        let hijri_civil = Ref(&hijri_civil);
1672        let hijri_simulated = Ref(&hijri_simulated);
1673        let hijri_astronomical = Ref(&hijri_astronomical);
1674        let hijri_umm_al_qura = Ref(&hijri_umm_al_qura);
1675        let japanese = Ref(&japanese);
1676        let japanext = Ref(&japanext);
1677        let persian = Ref(&persian);
1678        let roc = Ref(&roc);
1679
1680        single_test_roundtrip(buddhist, Some(("be", Some(0))), 100, "M03", 1);
1681        single_test_roundtrip(buddhist, None, 2000, "M03", 1);
1682        single_test_roundtrip(buddhist, Some(("be", Some(0))), -100, "M03", 1);
1683        single_test_error(
1684            buddhist,
1685            Some(("be", Some(0))),
1686            100,
1687            "M13",
1688            1,
1689            DateError::UnknownMonthCode(MonthCode(tinystr!(4, "M13"))),
1690        );
1691
1692        single_test_roundtrip(coptic, Some(("am", Some(0))), 100, "M03", 1);
1693        single_test_roundtrip(coptic, None, 2000, "M03", 1);
1694        single_test_roundtrip(coptic, Some(("am", Some(0))), -99, "M03", 1);
1695        single_test_roundtrip(coptic, Some(("am", Some(0))), 100, "M13", 1);
1696        single_test_error(
1697            coptic,
1698            Some(("am", Some(0))),
1699            100,
1700            "M14",
1701            1,
1702            DateError::UnknownMonthCode(MonthCode(tinystr!(4, "M14"))),
1703        );
1704
1705        single_test_roundtrip(ethiopian, Some(("am", Some(1))), 100, "M03", 1);
1706        single_test_roundtrip(ethiopian, None, 2000, "M03", 1);
1707        single_test_roundtrip(ethiopian, Some(("am", Some(1))), 2000, "M13", 1);
1708        single_test_roundtrip(ethiopian, Some(("aa", Some(0))), 5400, "M03", 1);
1709        single_test_error(
1710            ethiopian,
1711            Some(("am", Some(0))),
1712            0,
1713            "M03",
1714            1,
1715            DateError::Range {
1716                field: "year",
1717                value: 0,
1718                min: 1,
1719                max: i32::MAX,
1720            },
1721        );
1722        single_test_error(
1723            ethiopian,
1724            Some(("aa", Some(0))),
1725            5600,
1726            "M03",
1727            1,
1728            DateError::Range {
1729                field: "year",
1730                value: 5600,
1731                min: i32::MIN,
1732                max: 5500,
1733            },
1734        );
1735        single_test_error(
1736            ethiopian,
1737            Some(("am", Some(0))),
1738            100,
1739            "M14",
1740            1,
1741            DateError::UnknownMonthCode(MonthCode(tinystr!(4, "M14"))),
1742        );
1743
1744        single_test_roundtrip(ethioaa, Some(("aa", Some(0))), 7000, "M13", 1);
1745        single_test_roundtrip(ethioaa, None, 7000, "M13", 1);
1746        single_test_roundtrip(ethioaa, Some(("aa", Some(0))), 100, "M03", 1);
1747        single_test_error(
1748            ethiopian,
1749            Some(("aa", Some(0))),
1750            100,
1751            "M14",
1752            1,
1753            DateError::UnknownMonthCode(MonthCode(tinystr!(4, "M14"))),
1754        );
1755
1756        single_test_roundtrip(gregorian, Some(("ce", Some(1))), 100, "M03", 1);
1757        single_test_roundtrip(gregorian, None, 2000, "M03", 1);
1758        single_test_roundtrip(gregorian, Some(("bce", Some(0))), 100, "M03", 1);
1759        single_test_error(
1760            gregorian,
1761            Some(("ce", Some(1))),
1762            0,
1763            "M03",
1764            1,
1765            DateError::Range {
1766                field: "year",
1767                value: 0,
1768                min: 1,
1769                max: i32::MAX,
1770            },
1771        );
1772        single_test_error(
1773            gregorian,
1774            Some(("bce", Some(0))),
1775            0,
1776            "M03",
1777            1,
1778            DateError::Range {
1779                field: "year",
1780                value: 0,
1781                min: 1,
1782                max: i32::MAX,
1783            },
1784        );
1785
1786        single_test_error(
1787            gregorian,
1788            Some(("bce", Some(0))),
1789            100,
1790            "M13",
1791            1,
1792            DateError::UnknownMonthCode(MonthCode(tinystr!(4, "M13"))),
1793        );
1794
1795        single_test_roundtrip(indian, Some(("shaka", Some(0))), 100, "M03", 1);
1796        single_test_roundtrip(indian, None, 2000, "M12", 1);
1797        single_test_roundtrip(indian, None, -100, "M03", 1);
1798        single_test_roundtrip(indian, Some(("shaka", Some(0))), 0, "M03", 1);
1799        single_test_error(
1800            indian,
1801            Some(("shaka", Some(0))),
1802            100,
1803            "M13",
1804            1,
1805            DateError::UnknownMonthCode(MonthCode(tinystr!(4, "M13"))),
1806        );
1807
1808        single_test_roundtrip(chinese, None, 400, "M02", 5);
1809        single_test_roundtrip(chinese, None, 4660, "M07", 29);
1810        single_test_roundtrip(chinese, None, -100, "M11", 12);
1811        single_test_error(
1812            chinese,
1813            None,
1814            4658,
1815            "M13",
1816            1,
1817            DateError::UnknownMonthCode(MonthCode(tinystr!(4, "M13"))),
1818        );
1819
1820        single_test_roundtrip(dangi, None, 400, "M02", 5);
1821        single_test_roundtrip(dangi, None, 4660, "M08", 29);
1822        single_test_roundtrip(dangi, None, -1300, "M11", 12);
1823        single_test_error(
1824            dangi,
1825            None,
1826            10393,
1827            "M00L",
1828            1,
1829            DateError::UnknownMonthCode(MonthCode(tinystr!(4, "M00L"))),
1830        );
1831
1832        single_test_roundtrip(japanese, Some(("reiwa", None)), 3, "M03", 1);
1833        single_test_roundtrip(japanese, Some(("heisei", None)), 6, "M12", 1);
1834        single_test_roundtrip(japanese, Some(("meiji", None)), 10, "M03", 1);
1835        single_test_roundtrip(japanese, Some(("ce", None)), 1000, "M03", 1);
1836        single_test_roundtrip(japanese, None, 1000, "M03", 1);
1837        single_test_roundtrip(japanese, Some(("bce", None)), 10, "M03", 1);
1838        single_test_error(
1839            japanese,
1840            Some(("ce", None)),
1841            0,
1842            "M03",
1843            1,
1844            DateError::Range {
1845                field: "year",
1846                value: 0,
1847                min: 1,
1848                max: i32::MAX,
1849            },
1850        );
1851        single_test_error(
1852            japanese,
1853            Some(("bce", Some(0))),
1854            0,
1855            "M03",
1856            1,
1857            DateError::Range {
1858                field: "year",
1859                value: 0,
1860                min: 1,
1861                max: i32::MAX,
1862            },
1863        );
1864
1865        single_test_error(
1866            japanese,
1867            Some(("reiwa", None)),
1868            2,
1869            "M13",
1870            1,
1871            DateError::UnknownMonthCode(MonthCode(tinystr!(4, "M13"))),
1872        );
1873
1874        single_test_roundtrip(japanext, Some(("reiwa", None)), 3, "M03", 1);
1875        single_test_roundtrip(japanext, Some(("heisei", None)), 6, "M12", 1);
1876        single_test_roundtrip(japanext, Some(("meiji", None)), 10, "M03", 1);
1877        single_test_roundtrip(japanext, Some(("tenpyokampo-749", None)), 1, "M04", 20);
1878        single_test_roundtrip(japanext, Some(("ce", None)), 100, "M03", 1);
1879        single_test_roundtrip(japanext, Some(("bce", None)), 10, "M03", 1);
1880        single_test_error(
1881            japanext,
1882            Some(("ce", None)),
1883            0,
1884            "M03",
1885            1,
1886            DateError::Range {
1887                field: "year",
1888                value: 0,
1889                min: 1,
1890                max: i32::MAX,
1891            },
1892        );
1893        single_test_error(
1894            japanext,
1895            Some(("bce", Some(0))),
1896            0,
1897            "M03",
1898            1,
1899            DateError::Range {
1900                field: "year",
1901                value: 0,
1902                min: 1,
1903                max: i32::MAX,
1904            },
1905        );
1906
1907        single_test_error(
1908            japanext,
1909            Some(("reiwa", None)),
1910            2,
1911            "M13",
1912            1,
1913            DateError::UnknownMonthCode(MonthCode(tinystr!(4, "M13"))),
1914        );
1915
1916        single_test_roundtrip(persian, Some(("ap", Some(0))), 477, "M03", 1);
1917        single_test_roundtrip(persian, None, 2083, "M07", 21);
1918        single_test_roundtrip(persian, Some(("ap", Some(0))), 1600, "M12", 20);
1919        single_test_error(
1920            persian,
1921            Some(("ap", Some(0))),
1922            100,
1923            "M9",
1924            1,
1925            DateError::UnknownMonthCode(MonthCode(tinystr!(4, "M9"))),
1926        );
1927
1928        single_test_roundtrip(hebrew, Some(("am", Some(0))), 5773, "M03", 1);
1929        single_test_roundtrip(hebrew, None, 4993, "M07", 21);
1930        single_test_roundtrip(hebrew, Some(("am", Some(0))), 5012, "M12", 20);
1931        single_test_error(
1932            hebrew,
1933            Some(("am", Some(0))),
1934            100,
1935            "M9",
1936            1,
1937            DateError::UnknownMonthCode(MonthCode(tinystr!(4, "M9"))),
1938        );
1939
1940        single_test_roundtrip(roc, Some(("roc", Some(1))), 10, "M05", 3);
1941        single_test_roundtrip(roc, Some(("broc", Some(0))), 15, "M01", 10);
1942        single_test_roundtrip(roc, None, 100, "M10", 30);
1943
1944        single_test_roundtrip(hijri_simulated, Some(("ah", Some(0))), 477, "M03", 1);
1945        single_test_roundtrip(hijri_simulated, None, 2083, "M07", 21);
1946        single_test_roundtrip(hijri_simulated, Some(("ah", Some(0))), 1600, "M12", 20);
1947        single_test_error(
1948            hijri_simulated,
1949            Some(("ah", Some(0))),
1950            100,
1951            "M9",
1952            1,
1953            DateError::UnknownMonthCode(MonthCode(tinystr!(4, "M9"))),
1954        );
1955
1956        single_test_roundtrip(hijri_civil, Some(("ah", Some(0))), 477, "M03", 1);
1957        single_test_roundtrip(hijri_civil, None, 2083, "M07", 21);
1958        single_test_roundtrip(hijri_civil, Some(("ah", Some(0))), 1600, "M12", 20);
1959        single_test_error(
1960            hijri_civil,
1961            Some(("ah", Some(0))),
1962            100,
1963            "M9",
1964            1,
1965            DateError::UnknownMonthCode(MonthCode(tinystr!(4, "M9"))),
1966        );
1967
1968        single_test_roundtrip(hijri_umm_al_qura, Some(("ah", Some(0))), 477, "M03", 1);
1969        single_test_roundtrip(hijri_umm_al_qura, None, 2083, "M07", 21);
1970        single_test_roundtrip(hijri_umm_al_qura, Some(("ah", Some(0))), 1600, "M12", 20);
1971        single_test_error(
1972            hijri_umm_al_qura,
1973            Some(("ah", Some(0))),
1974            100,
1975            "M9",
1976            1,
1977            DateError::UnknownMonthCode(MonthCode(tinystr!(4, "M9"))),
1978        );
1979
1980        single_test_roundtrip(hijri_astronomical, Some(("ah", Some(0))), 477, "M03", 1);
1981        single_test_roundtrip(hijri_astronomical, None, 2083, "M07", 21);
1982        single_test_roundtrip(hijri_astronomical, Some(("ah", Some(0))), 1600, "M12", 20);
1983        single_test_error(
1984            hijri_astronomical,
1985            Some(("ah", Some(0))),
1986            100,
1987            "M9",
1988            1,
1989            DateError::UnknownMonthCode(MonthCode(tinystr!(4, "M9"))),
1990        );
1991    }
1992}