1use crate::calendar_arithmetic::CalendarArithmetic;
43use crate::calendar_arithmetic::PrecomputedDataSource;
44use crate::chinese_based::{
45 chinese_based_ordinal_lunar_month_from_code, ChineseBasedPrecomputedData,
46 ChineseBasedWithDataLoading, ChineseBasedYearInfo,
47};
48use crate::provider::chinese_based::DangiCacheV1Marker;
49use crate::AsCalendar;
50use crate::{
51 chinese_based::ChineseBasedDateInner,
52 types::{self, Era, FormattableYear},
53 AnyCalendarKind, Calendar, CalendarError, Date, DateTime, Iso, Time,
54};
55use core::cmp::Ordering;
56use core::num::NonZeroU8;
57use icu_provider::prelude::*;
58use tinystr::tinystr;
59
60#[derive(Clone, Debug, Default)]
100pub struct Dangi {
101 data: Option<DataPayload<DangiCacheV1Marker>>,
102}
103
104#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)]
106pub struct DangiDateInner(ChineseBasedDateInner<Dangi>);
107
108type Inner = ChineseBasedDateInner<Dangi>;
109
110impl Copy for DangiDateInner {}
112impl Clone for DangiDateInner {
113 fn clone(&self) -> Self {
114 *self
115 }
116}
117
118impl PartialEq for Dangi {
121 fn eq(&self, _: &Self) -> bool {
122 true
123 }
124}
125impl Eq for Dangi {}
126#[allow(clippy::non_canonical_partial_ord_impl)] impl PartialOrd for Dangi {
128 fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
129 Some(Ordering::Equal)
130 }
131}
132
133impl Ord for Dangi {
134 fn cmp(&self, _: &Self) -> Ordering {
135 Ordering::Equal
136 }
137}
138
139impl Dangi {
140 #[cfg(feature = "compiled_data")]
146 pub const fn new() -> Self {
147 Self {
148 data: Some(DataPayload::from_static_ref(
149 crate::provider::Baked::SINGLETON_CALENDAR_DANGICACHE_V1,
150 )),
151 }
152 }
153
154 icu_provider::gen_any_buffer_data_constructors!(locale: skip, options: skip, error: CalendarError,
155 #[cfg(skip)]
156 functions: [
157 new,
158 try_new_with_any_provider,
159 try_new_with_buffer_provider,
160 try_new_unstable,
161 Self,
162 ]);
163
164 #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::new)]
165 pub fn try_new_unstable<D: DataProvider<DangiCacheV1Marker> + ?Sized>(
166 provider: &D,
167 ) -> Result<Self, CalendarError> {
168 Ok(Self {
169 data: Some(provider.load(Default::default())?.take_payload()?),
170 })
171 }
172
173 pub fn new_always_calculating() -> Self {
175 Dangi { data: None }
176 }
177
178 pub(crate) const DEBUG_NAME: &'static str = "Dangi";
179}
180
181impl Calendar for Dangi {
182 type DateInner = DangiDateInner;
183
184 fn date_from_codes(
185 &self,
186 era: crate::types::Era,
187 year: i32,
188 month_code: crate::types::MonthCode,
189 day: u8,
190 ) -> Result<Self::DateInner, crate::Error> {
191 let year_info = self.get_precomputed_data().load_or_compute_info(year);
192
193 let month = if let Some(ordinal) =
194 chinese_based_ordinal_lunar_month_from_code(month_code, year_info)
195 {
196 ordinal
197 } else {
198 return Err(CalendarError::UnknownMonthCode(
199 month_code.0,
200 self.debug_name(),
201 ));
202 };
203
204 if era.0 != tinystr!(16, "dangi") {
205 return Err(CalendarError::UnknownEra(era.0, self.debug_name()));
206 }
207
208 let arithmetic = Inner::new_from_ordinals(year, month, day, year_info);
209 Ok(DangiDateInner(ChineseBasedDateInner(arithmetic?)))
210 }
211
212 fn date_from_iso(&self, iso: Date<crate::Iso>) -> Self::DateInner {
213 let fixed = Iso::fixed_from_iso(iso.inner);
214 DangiDateInner(Inner::chinese_based_date_from_fixed(
215 self,
216 fixed,
217 iso.inner.0,
218 ))
219 }
220
221 fn date_to_iso(&self, date: &Self::DateInner) -> Date<crate::Iso> {
222 let fixed = Inner::fixed_from_chinese_based_date_inner(date.0);
223 Iso::iso_from_fixed(fixed)
224 }
225
226 fn months_in_year(&self, date: &Self::DateInner) -> u8 {
227 date.0.months_in_year_inner()
228 }
229
230 fn days_in_year(&self, date: &Self::DateInner) -> u16 {
231 date.0.days_in_year_inner()
232 }
233
234 fn days_in_month(&self, date: &Self::DateInner) -> u8 {
235 date.0.days_in_month_inner()
236 }
237
238 fn offset_date(&self, date: &mut Self::DateInner, offset: crate::DateDuration<Self>) {
239 date.0 .0.offset_date(offset, &self.get_precomputed_data());
240 }
241
242 fn until(
243 &self,
244 date1: &Self::DateInner,
245 date2: &Self::DateInner,
246 _calendar2: &Self,
247 largest_unit: crate::DateDurationUnit,
248 smallest_unit: crate::DateDurationUnit,
249 ) -> crate::DateDuration<Self> {
250 date1.0 .0.until(date2.0 .0, largest_unit, smallest_unit)
251 }
252
253 fn debug_name(&self) -> &'static str {
254 Self::DEBUG_NAME
255 }
256
257 fn year(&self, date: &Self::DateInner) -> crate::types::FormattableYear {
258 Self::format_dangi_year(date.0 .0.year, Some(date.0 .0.year_info))
259 }
260
261 fn is_in_leap_year(&self, date: &Self::DateInner) -> bool {
262 Self::is_leap_year(date.0 .0.year, date.0 .0.year_info)
263 }
264
265 fn month(&self, date: &Self::DateInner) -> crate::types::FormattableMonth {
266 date.0.month()
267 }
268
269 fn day_of_month(&self, date: &Self::DateInner) -> crate::types::DayOfMonth {
270 types::DayOfMonth(date.0 .0.day as u32)
271 }
272
273 fn day_of_year_info(&self, date: &Self::DateInner) -> crate::types::DayOfYearInfo {
274 let prev_year = date.0 .0.year.saturating_sub(1);
275 let next_year = date.0 .0.year.saturating_add(1);
276 types::DayOfYearInfo {
277 day_of_year: date.0 .0.day_of_year(),
278 days_in_year: date.0.days_in_year_inner(),
279 prev_year: Self::format_dangi_year(prev_year, None),
280 days_in_prev_year: date.0.days_in_prev_year(),
281 next_year: Self::format_dangi_year(next_year, None),
282 }
283 }
284
285 fn day_of_week(&self, date: &Self::DateInner) -> crate::types::IsoWeekday {
286 self.date_to_iso(date).day_of_week()
287 }
288
289 fn any_calendar_kind(&self) -> Option<crate::AnyCalendarKind> {
290 Some(AnyCalendarKind::Dangi)
291 }
292}
293
294impl<A: AsCalendar<Calendar = Dangi>> Date<A> {
295 pub fn try_new_dangi_date_with_calendar(
319 year: i32,
320 month: u8,
321 day: u8,
322 calendar: A,
323 ) -> Result<Date<A>, CalendarError> {
324 let year_info = calendar
325 .as_calendar()
326 .get_precomputed_data()
327 .load_or_compute_info(year);
328 let arithmetic = Inner::new_from_ordinals(year, month, day, year_info);
329 Ok(Date::from_raw(
330 DangiDateInner(ChineseBasedDateInner(arithmetic?)),
331 calendar,
332 ))
333 }
334}
335
336impl<A: AsCalendar<Calendar = Dangi>> DateTime<A> {
337 pub fn try_new_dangi_datetime_with_calendar(
363 year: i32,
364 month: u8,
365 day: u8,
366 hour: u8,
367 minute: u8,
368 second: u8,
369 calendar: A,
370 ) -> Result<DateTime<A>, CalendarError> {
371 Ok(DateTime {
372 date: Date::try_new_dangi_date_with_calendar(year, month, day, calendar)?,
373 time: Time::try_new(hour, minute, second, 0)?,
374 })
375 }
376}
377
378type DangiCB = calendrical_calculations::chinese_based::Dangi;
379impl ChineseBasedWithDataLoading for Dangi {
380 type CB = DangiCB;
381 fn get_precomputed_data(&self) -> ChineseBasedPrecomputedData<Self::CB> {
382 ChineseBasedPrecomputedData::new(self.data.as_ref().map(|d| d.get()))
383 }
384}
385
386impl Dangi {
387 fn format_dangi_year(
390 year: i32,
391 year_info_option: Option<ChineseBasedYearInfo>,
392 ) -> FormattableYear {
393 let era = Era(tinystr!(16, "dangi"));
394 let number = year;
395 let cyclic = (number as i64 - 1 + 364).rem_euclid(60) as u8;
397 let cyclic = NonZeroU8::new(cyclic + 1); let rata_die_in_year = if let Some(info) = year_info_option {
399 info.new_year::<DangiCB>(year)
400 } else {
401 Inner::fixed_mid_year_from_year(number)
402 };
403 let iso_formattable_year = Iso::iso_from_fixed(rata_die_in_year).year();
404 let related_iso = Some(iso_formattable_year.number);
405 types::FormattableYear {
406 era,
407 number,
408 cyclic,
409 related_iso,
410 }
411 }
412}
413
414#[cfg(test)]
415mod test {
416
417 use super::*;
418 use crate::chinese::Chinese;
419 use calendrical_calculations::rata_die::RataDie;
420
421 fn do_twice(
423 dangi_calculating: &Dangi,
424 dangi_cached: &Dangi,
425 test: impl Fn(crate::Ref<Dangi>, &'static str),
426 ) {
427 test(crate::Ref(dangi_calculating), "calculating");
428 test(crate::Ref(dangi_cached), "cached");
429 }
430
431 fn check_cyclic_and_rel_iso(year: i32) {
432 let iso = Date::try_new_iso_date(year, 6, 6).unwrap();
433 let chinese = iso.to_calendar(Chinese::new_always_calculating());
434 let dangi = iso.to_calendar(Dangi::new_always_calculating());
435 let chinese_year = chinese.year().cyclic;
436 let korean_year = dangi.year().cyclic;
437 assert_eq!(
438 chinese_year, korean_year,
439 "Cyclic year failed for year: {year}"
440 );
441 let chinese_rel_iso = chinese.year().related_iso;
442 let korean_rel_iso = dangi.year().related_iso;
443 assert_eq!(
444 chinese_rel_iso, korean_rel_iso,
445 "Rel. ISO year equality failed for year: {year}"
446 );
447 assert_eq!(korean_rel_iso, Some(year), "Dangi Rel. ISO failed!");
448 }
449
450 #[test]
451 fn test_cyclic_same_as_chinese_near_present_day() {
452 for year in 1923..=2123 {
453 check_cyclic_and_rel_iso(year);
454 }
455 }
456
457 #[test]
458 fn test_cyclic_same_as_chinese_near_rd_zero() {
459 for year in -100..=100 {
460 check_cyclic_and_rel_iso(year);
461 }
462 }
463
464 #[test]
465 fn test_iso_to_dangi_roundtrip() {
466 let mut fixed = -1963020;
467 let max_fixed = 1963020;
468 let mut iters = 0;
469 let max_iters = 560;
470 let dangi_calculating = Dangi::new_always_calculating();
471 let dangi_cached = Dangi::new();
472 while fixed < max_fixed && iters < max_iters {
473 let rata_die = RataDie::new(fixed);
474 let iso = Iso::iso_from_fixed(rata_die);
475 do_twice(&dangi_calculating, &dangi_cached, |dangi, calendar_type| {
476 let korean = iso.to_calendar(dangi);
477 let result = korean.to_calendar(Iso);
478 assert_eq!(
479 iso, result,
480 "[{calendar_type}] Failed roundtrip ISO -> Dangi -> ISO for fixed: {fixed}"
481 );
482 });
483
484 fixed += 7043;
485 iters += 1;
486 }
487 }
488
489 #[test]
490 fn test_dangi_consistent_with_icu() {
491 #[derive(Debug)]
498 struct TestCase {
499 iso_year: i32,
500 iso_month: u8,
501 iso_day: u8,
502 expected_rel_iso: i32,
503 expected_cyclic: u8,
504 expected_month: u32,
505 expected_day: u32,
506 }
507
508 let cases = [
509 TestCase {
510 iso_year: 4321,
512 iso_month: 1,
513 iso_day: 23,
514 expected_rel_iso: 4320,
515 expected_cyclic: 57,
516 expected_month: 13,
517 expected_day: 12,
518 },
519 TestCase {
520 iso_year: 3649,
521 iso_month: 9,
522 iso_day: 20,
523 expected_rel_iso: 3649,
524 expected_cyclic: 46,
525 expected_month: 9,
526 expected_day: 1,
527 },
528 TestCase {
529 iso_year: 3333,
530 iso_month: 3,
531 iso_day: 3,
532 expected_rel_iso: 3333,
533 expected_cyclic: 30,
534 expected_month: 1,
535 expected_day: 25,
536 },
537 TestCase {
538 iso_year: 3000,
539 iso_month: 3,
540 iso_day: 30,
541 expected_rel_iso: 3000,
542 expected_cyclic: 57,
543 expected_month: 3,
544 expected_day: 3,
545 },
546 TestCase {
547 iso_year: 2772,
548 iso_month: 7,
549 iso_day: 27,
550 expected_rel_iso: 2772,
551 expected_cyclic: 9,
552 expected_month: 7,
553 expected_day: 5,
554 },
555 TestCase {
556 iso_year: 2525,
557 iso_month: 2,
558 iso_day: 25,
559 expected_rel_iso: 2525,
560 expected_cyclic: 2,
561 expected_month: 2,
562 expected_day: 3,
563 },
564 TestCase {
565 iso_year: 2345,
566 iso_month: 3,
567 iso_day: 21,
568 expected_rel_iso: 2345,
569 expected_cyclic: 2,
570 expected_month: 2,
571 expected_day: 17,
572 },
573 TestCase {
574 iso_year: 2222,
575 iso_month: 2,
576 iso_day: 22,
577 expected_rel_iso: 2222,
578 expected_cyclic: 59,
579 expected_month: 1,
580 expected_day: 11,
581 },
582 TestCase {
583 iso_year: 2167,
584 iso_month: 6,
585 iso_day: 22,
586 expected_rel_iso: 2167,
587 expected_cyclic: 4,
588 expected_month: 5,
589 expected_day: 6,
590 },
591 TestCase {
592 iso_year: 2121,
593 iso_month: 2,
594 iso_day: 12,
595 expected_rel_iso: 2120,
596 expected_cyclic: 17,
597 expected_month: 13,
598 expected_day: 25,
599 },
600 TestCase {
601 iso_year: 2080,
602 iso_month: 12,
603 iso_day: 31,
604 expected_rel_iso: 2080,
605 expected_cyclic: 37,
606 expected_month: 12,
607 expected_day: 21,
608 },
609 TestCase {
610 iso_year: 2030,
611 iso_month: 3,
612 iso_day: 20,
613 expected_rel_iso: 2030,
614 expected_cyclic: 47,
615 expected_month: 2,
616 expected_day: 17,
617 },
618 TestCase {
619 iso_year: 2027,
620 iso_month: 2,
621 iso_day: 7,
622 expected_rel_iso: 2027,
623 expected_cyclic: 44,
624 expected_month: 1,
625 expected_day: 1,
626 },
627 TestCase {
628 iso_year: 2023,
629 iso_month: 7,
630 iso_day: 1,
631 expected_rel_iso: 2023,
632 expected_cyclic: 40,
633 expected_month: 6,
634 expected_day: 14,
635 },
636 TestCase {
637 iso_year: 2022,
638 iso_month: 3,
639 iso_day: 1,
640 expected_rel_iso: 2022,
641 expected_cyclic: 39,
642 expected_month: 1,
643 expected_day: 29,
644 },
645 TestCase {
646 iso_year: 2021,
647 iso_month: 2,
648 iso_day: 1,
649 expected_rel_iso: 2020,
650 expected_cyclic: 37,
651 expected_month: 13,
652 expected_day: 20,
653 },
654 TestCase {
655 iso_year: 2016,
656 iso_month: 3,
657 iso_day: 30,
658 expected_rel_iso: 2016,
659 expected_cyclic: 33,
660 expected_month: 2,
661 expected_day: 22,
662 },
663 TestCase {
664 iso_year: 2016,
665 iso_month: 7,
666 iso_day: 30,
667 expected_rel_iso: 2016,
668 expected_cyclic: 33,
669 expected_month: 6,
670 expected_day: 27,
671 },
672 TestCase {
673 iso_year: 2015,
674 iso_month: 9,
675 iso_day: 22,
676 expected_rel_iso: 2015,
677 expected_cyclic: 32,
678 expected_month: 8,
679 expected_day: 10,
680 },
681 TestCase {
682 iso_year: 2013,
683 iso_month: 10,
684 iso_day: 1,
685 expected_rel_iso: 2013,
686 expected_cyclic: 30,
687 expected_month: 8,
688 expected_day: 27,
689 },
690 TestCase {
691 iso_year: 2010,
692 iso_month: 2,
693 iso_day: 1,
694 expected_rel_iso: 2009,
695 expected_cyclic: 26,
696 expected_month: 13,
697 expected_day: 18,
698 },
699 TestCase {
700 iso_year: 2000,
701 iso_month: 8,
702 iso_day: 30,
703 expected_rel_iso: 2000,
704 expected_cyclic: 17,
705 expected_month: 8,
706 expected_day: 2,
707 },
708 TestCase {
709 iso_year: 1990,
710 iso_month: 11,
711 iso_day: 11,
712 expected_rel_iso: 1990,
713 expected_cyclic: 7,
714 expected_month: 10,
715 expected_day: 24,
716 },
717 TestCase {
718 iso_year: 1970,
719 iso_month: 6,
720 iso_day: 10,
721 expected_rel_iso: 1970,
722 expected_cyclic: 47,
723 expected_month: 5,
724 expected_day: 7,
725 },
726 TestCase {
727 iso_year: 1970,
728 iso_month: 1,
729 iso_day: 1,
730 expected_rel_iso: 1969,
731 expected_cyclic: 46,
732 expected_month: 11,
733 expected_day: 24,
734 },
735 TestCase {
736 iso_year: 1941,
737 iso_month: 12,
738 iso_day: 7,
739 expected_rel_iso: 1941,
740 expected_cyclic: 18,
741 expected_month: 11,
742 expected_day: 19,
743 },
744 TestCase {
745 iso_year: 1812,
746 iso_month: 5,
747 iso_day: 4,
748 expected_rel_iso: 1812,
749 expected_cyclic: 9,
750 expected_month: 3,
751 expected_day: 24,
752 },
753 TestCase {
754 iso_year: 1655,
755 iso_month: 6,
756 iso_day: 15,
757 expected_rel_iso: 1655,
758 expected_cyclic: 32,
759 expected_month: 5,
760 expected_day: 12,
761 },
762 TestCase {
763 iso_year: 1333,
764 iso_month: 3,
765 iso_day: 10,
766 expected_rel_iso: 1333,
767 expected_cyclic: 10,
768 expected_month: 2,
769 expected_day: 16,
770 },
771 TestCase {
772 iso_year: 1000,
773 iso_month: 10,
774 iso_day: 10,
775 expected_rel_iso: 1000,
776 expected_cyclic: 37,
777 expected_month: 9,
778 expected_day: 5,
779 },
780 TestCase {
781 iso_year: 842,
782 iso_month: 2,
783 iso_day: 15,
784 expected_rel_iso: 841,
785 expected_cyclic: 58,
786 expected_month: 13,
787 expected_day: 28,
788 },
789 TestCase {
790 iso_year: 101,
791 iso_month: 1,
792 iso_day: 10,
793 expected_rel_iso: 100,
794 expected_cyclic: 37,
795 expected_month: 12,
796 expected_day: 24,
797 },
798 TestCase {
799 iso_year: -1,
800 iso_month: 3,
801 iso_day: 28,
802 expected_rel_iso: -1,
803 expected_cyclic: 56,
804 expected_month: 2,
805 expected_day: 25,
806 },
807 TestCase {
808 iso_year: -3,
809 iso_month: 2,
810 iso_day: 28,
811 expected_rel_iso: -3,
812 expected_cyclic: 54,
813 expected_month: 2,
814 expected_day: 5,
815 },
816 TestCase {
817 iso_year: -365,
818 iso_month: 7,
819 iso_day: 24,
820 expected_rel_iso: -365,
821 expected_cyclic: 52,
822 expected_month: 6,
823 expected_day: 24,
824 },
825 TestCase {
826 iso_year: -999,
827 iso_month: 9,
828 iso_day: 9,
829 expected_rel_iso: -999,
830 expected_cyclic: 18,
831 expected_month: 7,
832 expected_day: 27,
833 },
834 TestCase {
835 iso_year: -1500,
836 iso_month: 1,
837 iso_day: 5,
838 expected_rel_iso: -1501,
839 expected_cyclic: 56,
840 expected_month: 12,
841 expected_day: 2,
842 },
843 TestCase {
844 iso_year: -2332,
845 iso_month: 3,
846 iso_day: 1,
847 expected_rel_iso: -2332,
848 expected_cyclic: 5,
849 expected_month: 1,
850 expected_day: 16,
851 },
852 TestCase {
853 iso_year: -2332,
854 iso_month: 2,
855 iso_day: 15,
856 expected_rel_iso: -2332,
857 expected_cyclic: 5,
858 expected_month: 1,
859 expected_day: 1,
860 },
861 TestCase {
862 iso_year: -2332,
864 iso_month: 2,
865 iso_day: 14,
866 expected_rel_iso: -2333,
867 expected_cyclic: 4,
868 expected_month: 13,
869 expected_day: 30,
870 },
871 TestCase {
872 iso_year: -2332,
874 iso_month: 1,
875 iso_day: 17,
876 expected_rel_iso: -2333,
877 expected_cyclic: 4,
878 expected_month: 13,
879 expected_day: 2,
880 },
881 TestCase {
882 iso_year: -2332,
884 iso_month: 1,
885 iso_day: 16,
886 expected_rel_iso: -2333,
887 expected_cyclic: 4,
888 expected_month: 13,
889 expected_day: 1,
890 },
891 TestCase {
892 iso_year: -2332,
893 iso_month: 1,
894 iso_day: 15,
895 expected_rel_iso: -2333,
896 expected_cyclic: 4,
897 expected_month: 12,
898 expected_day: 29,
899 },
900 TestCase {
901 iso_year: -2332,
902 iso_month: 1,
903 iso_day: 1,
904 expected_rel_iso: -2333,
905 expected_cyclic: 4,
906 expected_month: 12,
907 expected_day: 15,
908 },
909 TestCase {
910 iso_year: -2333,
911 iso_month: 1,
912 iso_day: 16,
913 expected_rel_iso: -2334,
914 expected_cyclic: 3,
915 expected_month: 12,
916 expected_day: 19,
917 },
918 TestCase {
919 iso_year: -2333,
920 iso_month: 1,
921 iso_day: 27,
922 expected_rel_iso: -2333,
923 expected_cyclic: 4,
924 expected_month: 1,
925 expected_day: 1,
926 },
927 TestCase {
928 iso_year: -2333,
929 iso_month: 1,
930 iso_day: 26,
931 expected_rel_iso: -2334,
932 expected_cyclic: 3,
933 expected_month: 12,
934 expected_day: 29,
935 },
936 TestCase {
937 iso_year: -2600,
938 iso_month: 9,
939 iso_day: 16,
940 expected_rel_iso: -2600,
941 expected_cyclic: 37,
942 expected_month: 8,
943 expected_day: 16,
944 },
945 TestCase {
946 iso_year: -2855,
947 iso_month: 2,
948 iso_day: 3,
949 expected_rel_iso: -2856,
950 expected_cyclic: 21,
951 expected_month: 12,
952 expected_day: 30,
953 },
954 TestCase {
955 iso_year: -3000,
957 iso_month: 5,
958 iso_day: 15,
959 expected_rel_iso: -3000,
960 expected_cyclic: 57,
961 expected_month: 4,
962 expected_day: 1,
963 },
964 TestCase {
965 iso_year: -3649,
967 iso_month: 9,
968 iso_day: 20,
969 expected_rel_iso: -3649,
970 expected_cyclic: 8,
971 expected_month: 8,
972 expected_day: 10,
973 },
974 TestCase {
975 iso_year: -3649,
977 iso_month: 3,
978 iso_day: 30,
979 expected_rel_iso: -3649,
980 expected_cyclic: 8,
981 expected_month: 2,
982 expected_day: 14,
983 },
984 TestCase {
985 iso_year: -3650,
987 iso_month: 3,
988 iso_day: 30,
989 expected_rel_iso: -3650,
990 expected_cyclic: 7,
991 expected_month: 3,
992 expected_day: 3,
993 },
994 ];
995
996 let dangi_calculating = Dangi::new_always_calculating();
997 let dangi_cached = Dangi::new();
998
999 for case in cases {
1000 let iso = Date::try_new_iso_date(case.iso_year, case.iso_month, case.iso_day).unwrap();
1001 do_twice(&dangi_calculating, &dangi_cached, |dangi, calendar_type| {
1002 let dangi = iso.to_calendar(dangi);
1003 let dangi_rel_iso = dangi.year().related_iso;
1004 let dangi_cyclic = dangi.year().cyclic;
1005 let dangi_month = dangi.month().ordinal;
1006 let dangi_day = dangi.day_of_month().0;
1007
1008 assert_eq!(
1009 dangi_rel_iso,
1010 Some(case.expected_rel_iso),
1011 "[{calendar_type}] Related ISO failed for test case: {case:?}"
1012 );
1013 assert_eq!(
1014 dangi_cyclic.unwrap().get(),
1015 case.expected_cyclic,
1016 "[{calendar_type}] Cyclic year failed for test case: {case:?}"
1017 );
1018 assert_eq!(
1019 dangi_month, case.expected_month,
1020 "[{calendar_type}] Month failed for test case: {case:?}"
1021 );
1022 assert_eq!(
1023 dangi_day, case.expected_day,
1024 "[{calendar_type}] Day failed for test case: {case:?}"
1025 );
1026 });
1027 }
1028 }
1029}