1use crate::cal::chinese_based::{ChineseBasedPrecomputedData, ChineseBasedWithDataLoading};
21use crate::cal::iso::{Iso, IsoDateInner};
22use crate::calendar_arithmetic::PrecomputedDataSource;
23use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic};
24use crate::error::DateError;
25use crate::provider::chinese_based::CalendarChineseV1;
26use crate::AsCalendar;
27use crate::{types, Calendar, Date, DateDuration, DateDurationUnit};
28use calendrical_calculations::chinese_based;
29use calendrical_calculations::rata_die::RataDie;
30use core::cmp::Ordering;
31use icu_provider::prelude::*;
32
33#[derive(Clone, Debug, Default)]
77pub struct Chinese {
78 data: Option<DataPayload<CalendarChineseV1>>,
79}
80
81#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)]
83pub struct ChineseDateInner(ArithmeticDate<Chinese>);
84
85impl Copy for ChineseDateInner {}
87impl Clone for ChineseDateInner {
88 fn clone(&self) -> Self {
89 *self
90 }
91}
92
93impl PartialEq for Chinese {
96 fn eq(&self, _: &Self) -> bool {
97 true
98 }
99}
100impl Eq for Chinese {}
101#[allow(clippy::non_canonical_partial_ord_impl)] impl PartialOrd for Chinese {
103 fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
104 Some(Ordering::Equal)
105 }
106}
107
108impl Ord for Chinese {
109 fn cmp(&self, _: &Self) -> Ordering {
110 Ordering::Equal
111 }
112}
113
114impl Chinese {
115 #[cfg(feature = "compiled_data")]
121 pub const fn new() -> Self {
122 Self {
123 data: Some(DataPayload::from_static_ref(
124 crate::provider::Baked::SINGLETON_CALENDAR_CHINESE_V1,
125 )),
126 }
127 }
128
129 icu_provider::gen_buffer_data_constructors!(() -> error: DataError,
130 functions: [
131 new: skip,
132 try_new_with_buffer_provider,
133 try_new_unstable,
134 Self,
135 ]);
136
137 #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new)]
138 pub fn try_new_unstable<D: DataProvider<CalendarChineseV1> + ?Sized>(
139 provider: &D,
140 ) -> Result<Self, DataError> {
141 Ok(Self {
142 data: Some(provider.load(Default::default())?.payload),
143 })
144 }
145
146 pub fn new_always_calculating() -> Self {
148 Chinese { data: None }
149 }
150
151 pub(crate) const DEBUG_NAME: &'static str = "Chinese";
152}
153
154impl crate::cal::scaffold::UnstableSealed for Chinese {}
155impl Calendar for Chinese {
156 type DateInner = ChineseDateInner;
157 type Year = types::CyclicYear;
158
159 fn from_codes(
161 &self,
162 era: Option<&str>,
163 year: i32,
164 month_code: types::MonthCode,
165 day: u8,
166 ) -> Result<Self::DateInner, DateError> {
167 match era {
168 None => {}
169 _ => return Err(DateError::UnknownEra),
170 }
171
172 let year = self.get_precomputed_data().load_or_compute_info(year);
173
174 let Some(month) = year.parse_month_code(month_code) else {
175 return Err(DateError::UnknownMonthCode(month_code));
176 };
177
178 year.validate_md(month, day)?;
179
180 Ok(ChineseDateInner(ArithmeticDate::new_unchecked(
181 year, month, day,
182 )))
183 }
184
185 fn from_rata_die(&self, rd: RataDie) -> Self::DateInner {
186 let iso = Iso.from_rata_die(rd);
187 let y = self
188 .get_precomputed_data()
189 .load_or_compute_info_for_rd(rd, iso.0);
190 let (m, d) = y.md_from_rd(rd);
191 ChineseDateInner(ArithmeticDate::new_unchecked(y, m, d))
192 }
193
194 fn to_rata_die(&self, date: &Self::DateInner) -> RataDie {
195 date.0.year.rd_from_md(date.0.month, date.0.day)
196 }
197
198 fn from_iso(&self, iso: IsoDateInner) -> Self::DateInner {
199 let rd = Iso.to_rata_die(&iso);
200 let y = self
201 .get_precomputed_data()
202 .load_or_compute_info_for_rd(rd, iso.0);
203 let (m, d) = y.md_from_rd(rd);
204 ChineseDateInner(ArithmeticDate::new_unchecked(y, m, d))
205 }
206
207 fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner {
208 Iso.from_rata_die(self.to_rata_die(date))
209 }
210
211 fn days_in_year(&self, date: &Self::DateInner) -> u16 {
214 date.0.days_in_year()
215 }
216
217 fn days_in_month(&self, date: &Self::DateInner) -> u8 {
218 date.0.days_in_month()
219 }
220
221 #[doc(hidden)] fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration<Self>) {
223 date.0.offset_date(offset, &self.get_precomputed_data());
224 }
225
226 #[doc(hidden)] #[allow(clippy::field_reassign_with_default)]
228 fn until(
233 &self,
234 date1: &Self::DateInner,
235 date2: &Self::DateInner,
236 _calendar2: &Self,
237 _largest_unit: DateDurationUnit,
238 _smallest_unit: DateDurationUnit,
239 ) -> DateDuration<Self> {
240 date1.0.until(date2.0, _largest_unit, _smallest_unit)
241 }
242
243 fn debug_name(&self) -> &'static str {
245 Self::DEBUG_NAME
246 }
247
248 fn year_info(&self, date: &Self::DateInner) -> Self::Year {
249 let year = date.0.year;
250 types::CyclicYear {
251 year: (year.related_iso - 4).rem_euclid(60) as u8 + 1,
252 related_iso: year.related_iso,
253 }
254 }
255
256 fn extended_year(&self, date: &Self::DateInner) -> i32 {
257 chinese_based::extended_from_iso::<chinese_based::Chinese>(date.0.year.related_iso)
258 }
259
260 fn is_in_leap_year(&self, date: &Self::DateInner) -> bool {
261 Self::provided_year_is_leap(date.0.year)
262 }
263
264 fn month(&self, date: &Self::DateInner) -> types::MonthInfo {
269 date.0.year.month(date.0.month)
270 }
271
272 fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth {
274 date.0.day_of_month()
275 }
276
277 fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear {
279 types::DayOfYear(date.0.year.day_of_year(date.0.month, date.0.day))
280 }
281
282 fn calendar_algorithm(&self) -> Option<crate::preferences::CalendarAlgorithm> {
283 Some(crate::preferences::CalendarAlgorithm::Chinese)
284 }
285
286 fn months_in_year(&self, date: &Self::DateInner) -> u8 {
287 date.0.months_in_year()
288 }
289}
290
291impl<A: AsCalendar<Calendar = Chinese>> Date<A> {
292 pub fn try_new_chinese_with_calendar(
315 related_iso_year: i32,
316 month: u8,
317 day: u8,
318 calendar: A,
319 ) -> Result<Date<A>, DateError> {
320 let year = calendar
321 .as_calendar()
322 .get_precomputed_data()
323 .load_or_compute_info(related_iso_year);
324 year.validate_md(month, day)?;
325 Ok(Date::from_raw(
326 ChineseDateInner(ArithmeticDate::new_unchecked(year, month, day)),
327 calendar,
328 ))
329 }
330}
331
332type ChineseCB = calendrical_calculations::chinese_based::Chinese;
333impl ChineseBasedWithDataLoading for Chinese {
334 type CB = ChineseCB;
335 fn get_precomputed_data(&self) -> ChineseBasedPrecomputedData<Self::CB> {
336 ChineseBasedPrecomputedData::new(self.data.as_ref().map(|d| d.get()))
337 }
338}
339
340#[cfg(test)]
341mod test {
342 use super::*;
343 use crate::types::MonthCode;
344 use calendrical_calculations::{iso::fixed_from_iso, rata_die::RataDie};
345 use tinystr::tinystr;
346
347 fn do_twice(
349 chinese_calculating: &Chinese,
350 chinese_cached: &Chinese,
351 test: impl Fn(crate::Ref<Chinese>, &'static str),
352 ) {
353 test(crate::Ref(chinese_calculating), "calculating");
354 test(crate::Ref(chinese_cached), "cached");
355 }
356
357 #[test]
358 fn test_chinese_from_rd() {
359 #[derive(Debug)]
360 struct TestCase {
361 rd: i64,
362 expected_year: i32,
363 expected_month: u8,
364 expected_day: u8,
365 }
366
367 let cases = [
368 TestCase {
369 rd: -964192,
370 expected_year: -2,
371 expected_month: 1,
372 expected_day: 1,
373 },
374 TestCase {
375 rd: -963838,
376 expected_year: -1,
377 expected_month: 1,
378 expected_day: 1,
379 },
380 TestCase {
381 rd: -963129,
382 expected_year: 0,
383 expected_month: 13,
384 expected_day: 1,
385 },
386 TestCase {
387 rd: -963100,
388 expected_year: 0,
389 expected_month: 13,
390 expected_day: 30,
391 },
392 TestCase {
393 rd: -963099,
394 expected_year: 1,
395 expected_month: 1,
396 expected_day: 1,
397 },
398 TestCase {
399 rd: 738700,
400 expected_year: 4660,
401 expected_month: 6,
402 expected_day: 12,
403 },
404 TestCase {
405 rd: fixed_from_iso(2319, 2, 20).to_i64_date(),
406 expected_year: 2319 + 2636,
407 expected_month: 13,
408 expected_day: 30,
409 },
410 TestCase {
411 rd: fixed_from_iso(2319, 2, 21).to_i64_date(),
412 expected_year: 2319 + 2636 + 1,
413 expected_month: 1,
414 expected_day: 1,
415 },
416 TestCase {
417 rd: 738718,
418 expected_year: 4660,
419 expected_month: 6,
420 expected_day: 30,
421 },
422 TestCase {
423 rd: 738747,
424 expected_year: 4660,
425 expected_month: 7,
426 expected_day: 29,
427 },
428 TestCase {
429 rd: 738748,
430 expected_year: 4660,
431 expected_month: 8,
432 expected_day: 1,
433 },
434 TestCase {
435 rd: 738865,
436 expected_year: 4660,
437 expected_month: 11,
438 expected_day: 29,
439 },
440 TestCase {
441 rd: 738895,
442 expected_year: 4660,
443 expected_month: 12,
444 expected_day: 29,
445 },
446 TestCase {
447 rd: 738925,
448 expected_year: 4660,
449 expected_month: 13,
450 expected_day: 30,
451 },
452 ];
453
454 let chinese_calculating = Chinese::new_always_calculating();
455 let chinese_cached = Chinese::new();
456 for case in cases {
457 let rata_die = RataDie::new(case.rd);
458
459 do_twice(
460 &chinese_calculating,
461 &chinese_cached,
462 |chinese, calendar_type| {
463 let chinese = Date::from_rata_die(rata_die, chinese);
464 assert_eq!(
465 case.expected_year,
466 chinese.extended_year(),
467 "[{calendar_type}] Chinese from RD failed, case: {case:?}"
468 );
469 assert_eq!(
470 case.expected_month,
471 chinese.month().ordinal,
472 "[{calendar_type}] Chinese from RD failed, case: {case:?}"
473 );
474 assert_eq!(
475 case.expected_day,
476 chinese.day_of_month().0,
477 "[{calendar_type}] Chinese from RD failed, case: {case:?}"
478 );
479 },
480 );
481 }
482 }
483
484 #[test]
485 fn test_rd_from_chinese() {
486 #[derive(Debug)]
487 struct TestCase {
488 year: i32,
489 month: u8,
490 day: u8,
491 expected: i64,
492 }
493
494 let cases = [
495 TestCase {
496 year: 2023,
497 month: 6,
498 day: 6,
499 expected: 738694,
501 },
502 TestCase {
503 year: -2636,
504 month: 1,
505 day: 1,
506 expected: -963099,
507 },
508 ];
509
510 let chinese_calculating = Chinese::new_always_calculating();
511 let chinese_cached = Chinese::new();
512 for case in cases {
513 do_twice(
514 &chinese_calculating,
515 &chinese_cached,
516 |chinese, calendar_type| {
517 let date = Date::try_new_chinese_with_calendar(
518 case.year, case.month, case.day, chinese,
519 )
520 .unwrap();
521 let rd = date.to_rata_die().to_i64_date();
522 let expected = case.expected;
523 assert_eq!(rd, expected, "[{calendar_type}] RD from Chinese failed, with expected: {expected} and calculated: {rd}, for test case: {case:?}");
524 },
525 );
526 }
527 }
528
529 #[test]
530 fn test_rd_chinese_roundtrip() {
531 let mut rd = -1963020;
532 let max_rd = 1963020;
533 let mut iters = 0;
534 let max_iters = 560;
535 let chinese_calculating = Chinese::new_always_calculating();
536 let chinese_cached = Chinese::new();
537 while rd < max_rd && iters < max_iters {
538 let rata_die = RataDie::new(rd);
539
540 do_twice(
541 &chinese_calculating,
542 &chinese_cached,
543 |chinese, calendar_type| {
544 let chinese = Date::from_rata_die(rata_die, chinese);
545 let result = chinese.to_rata_die();
546 assert_eq!(result, rata_die, "[{calendar_type}] Failed roundtrip RD -> Chinese -> RD for RD: {rata_die:?}, with calculated: {result:?} from Chinese date:\n{chinese:?}");
547 },
548 );
549 rd += 7043;
550 iters += 1;
551 }
552 }
553
554 #[test]
555 fn test_chinese_epoch() {
556 let iso = Date::try_new_iso(-2636, 2, 15).unwrap();
557
558 do_twice(
559 &Chinese::new_always_calculating(),
560 &Chinese::new(),
561 |chinese, _calendar_type| {
562 let chinese = iso.to_calendar(chinese);
563
564 assert_eq!(chinese.cyclic_year().related_iso, -2636);
565 assert_eq!(chinese.month().ordinal, 1);
566 assert_eq!(chinese.month().standard_code.0, "M01");
567 assert_eq!(chinese.day_of_month().0, 1);
568 assert_eq!(chinese.cyclic_year().year, 1);
569 assert_eq!(chinese.cyclic_year().related_iso, -2636);
570 },
571 )
572 }
573
574 #[test]
575 fn test_iso_to_chinese_negative_years() {
576 #[derive(Debug)]
577 struct TestCase {
578 iso_year: i32,
579 iso_month: u8,
580 iso_day: u8,
581 expected_year: i32,
582 expected_month: u8,
583 expected_day: u8,
584 }
585
586 let cases = [
587 TestCase {
588 iso_year: -2636,
589 iso_month: 2,
590 iso_day: 14,
591 expected_year: -2637,
592 expected_month: 13,
593 expected_day: 30,
594 },
595 TestCase {
596 iso_year: -2636,
597 iso_month: 1,
598 iso_day: 15,
599 expected_year: -2637,
600 expected_month: 12,
601 expected_day: 30,
602 },
603 ];
604
605 let chinese_calculating = Chinese::new_always_calculating();
606 let chinese_cached = Chinese::new();
607
608 for case in cases {
609 let iso = Date::try_new_iso(case.iso_year, case.iso_month, case.iso_day).unwrap();
610 do_twice(
611 &chinese_calculating,
612 &chinese_cached,
613 |chinese, calendar_type| {
614 let chinese = iso.to_calendar(chinese);
615 assert_eq!(
616 case.expected_year,
617 chinese.cyclic_year().related_iso,
618 "[{calendar_type}] ISO to Chinese failed for case: {case:?}"
619 );
620 assert_eq!(
621 case.expected_month,
622 chinese.month().ordinal,
623 "[{calendar_type}] ISO to Chinese failed for case: {case:?}"
624 );
625 assert_eq!(
626 case.expected_day,
627 chinese.day_of_month().0,
628 "[{calendar_type}] ISO to Chinese failed for case: {case:?}"
629 );
630 },
631 );
632 }
633 }
634
635 #[test]
636 fn test_chinese_leap_months() {
637 let expected = [
638 (1933, 6),
639 (1938, 8),
640 (1984, 11),
641 (2009, 6),
642 (2017, 7),
643 (2028, 6),
644 ];
645 let chinese_calculating = Chinese::new_always_calculating();
646 let chinese_cached = Chinese::new();
647
648 for case in expected {
649 let year = case.0;
650 let expected_month = case.1;
651 let iso = Date::try_new_iso(year, 6, 1).unwrap();
652 do_twice(
653 &chinese_calculating,
654 &chinese_cached,
655 |chinese, calendar_type| {
656 let chinese_date = iso.to_calendar(chinese);
657 assert!(
658 chinese_date.is_in_leap_year(),
659 "[{calendar_type}] {year} should be a leap year"
660 );
661 let new_year = chinese_date.inner.0.year.new_year();
662 assert_eq!(
663 expected_month,
664 calendrical_calculations::chinese_based::get_leap_month_from_new_year::<
665 calendrical_calculations::chinese_based::Chinese,
666 >(new_year),
667 "[{calendar_type}] {year} have leap month {expected_month}"
668 );
669 },
670 );
671 }
672 }
673
674 #[test]
675 fn test_month_days() {
676 let year =
677 ChineseBasedPrecomputedData::<<Chinese as ChineseBasedWithDataLoading>::CB>::default()
678 .load_or_compute_info(2023);
679 let cases = [
680 (1, 29),
681 (2, 30),
682 (3, 29),
683 (4, 29),
684 (5, 30),
685 (6, 30),
686 (7, 29),
687 (8, 30),
688 (9, 30),
689 (10, 29),
690 (11, 30),
691 (12, 29),
692 (13, 30),
693 ];
694 for case in cases {
695 let days_in_month = Chinese::days_in_provided_month(year, case.0);
696 assert_eq!(
697 case.1, days_in_month,
698 "month_days test failed for case: {case:?}"
699 );
700 }
701 }
702
703 #[test]
704 fn test_ordinal_to_month_code() {
705 #[derive(Debug)]
706 struct TestCase {
707 year: i32,
708 month: u8,
709 day: u8,
710 expected_code: &'static str,
711 }
712
713 let cases = [
714 TestCase {
715 year: 2023,
716 month: 1,
717 day: 9,
718 expected_code: "M12",
719 },
720 TestCase {
721 year: 2023,
722 month: 2,
723 day: 9,
724 expected_code: "M01",
725 },
726 TestCase {
727 year: 2023,
728 month: 3,
729 day: 9,
730 expected_code: "M02",
731 },
732 TestCase {
733 year: 2023,
734 month: 4,
735 day: 9,
736 expected_code: "M02L",
737 },
738 TestCase {
739 year: 2023,
740 month: 5,
741 day: 9,
742 expected_code: "M03",
743 },
744 TestCase {
745 year: 2023,
746 month: 6,
747 day: 9,
748 expected_code: "M04",
749 },
750 TestCase {
751 year: 2023,
752 month: 7,
753 day: 9,
754 expected_code: "M05",
755 },
756 TestCase {
757 year: 2023,
758 month: 8,
759 day: 9,
760 expected_code: "M06",
761 },
762 TestCase {
763 year: 2023,
764 month: 9,
765 day: 9,
766 expected_code: "M07",
767 },
768 TestCase {
769 year: 2023,
770 month: 10,
771 day: 9,
772 expected_code: "M08",
773 },
774 TestCase {
775 year: 2023,
776 month: 11,
777 day: 9,
778 expected_code: "M09",
779 },
780 TestCase {
781 year: 2023,
782 month: 12,
783 day: 9,
784 expected_code: "M10",
785 },
786 TestCase {
787 year: 2024,
788 month: 1,
789 day: 9,
790 expected_code: "M11",
791 },
792 TestCase {
793 year: 2024,
794 month: 2,
795 day: 9,
796 expected_code: "M12",
797 },
798 TestCase {
799 year: 2024,
800 month: 2,
801 day: 10,
802 expected_code: "M01",
803 },
804 ];
805
806 let chinese_calculating = Chinese::new_always_calculating();
807 let chinese_cached = Chinese::new();
808
809 for case in cases {
810 let iso = Date::try_new_iso(case.year, case.month, case.day).unwrap();
811 do_twice(
812 &chinese_calculating,
813 &chinese_cached,
814 |chinese, calendar_type| {
815 let chinese = iso.to_calendar(chinese);
816 let result_code = chinese.month().standard_code.0;
817 let expected_code = case.expected_code.to_string();
818 assert_eq!(
819 expected_code, result_code,
820 "[{calendar_type}] Month codes did not match for test case: {case:?}"
821 );
822 },
823 );
824 }
825 }
826
827 #[test]
828 fn test_month_code_to_ordinal() {
829 let year =
831 ChineseBasedPrecomputedData::<<Chinese as ChineseBasedWithDataLoading>::CB>::default()
832 .load_or_compute_info(2023);
833 let codes = [
834 (1, tinystr!(4, "M01")),
835 (2, tinystr!(4, "M02")),
836 (3, tinystr!(4, "M02L")),
837 (4, tinystr!(4, "M03")),
838 (5, tinystr!(4, "M04")),
839 (6, tinystr!(4, "M05")),
840 (7, tinystr!(4, "M06")),
841 (8, tinystr!(4, "M07")),
842 (9, tinystr!(4, "M08")),
843 (10, tinystr!(4, "M09")),
844 (11, tinystr!(4, "M10")),
845 (12, tinystr!(4, "M11")),
846 (13, tinystr!(4, "M12")),
847 ];
848 for ordinal_code_pair in codes {
849 let code = MonthCode(ordinal_code_pair.1);
850 let ordinal = year.parse_month_code(code);
851 assert_eq!(
852 ordinal,
853 Some(ordinal_code_pair.0),
854 "Code to ordinal failed for year: {}, code: {code}",
855 year.related_iso
856 );
857 }
858 }
859
860 #[test]
861 fn check_invalid_month_code_to_ordinal() {
862 let non_leap_year = 4659;
863 let leap_year = 4660;
864 let invalid_codes = [
865 (non_leap_year, tinystr!(4, "M2")),
866 (leap_year, tinystr!(4, "M0")),
867 (non_leap_year, tinystr!(4, "J01")),
868 (leap_year, tinystr!(4, "3M")),
869 (non_leap_year, tinystr!(4, "M04L")),
870 (leap_year, tinystr!(4, "M04L")),
871 (non_leap_year, tinystr!(4, "M13")),
872 (leap_year, tinystr!(4, "M13")),
873 ];
874 for (year, code) in invalid_codes {
875 let year = ChineseBasedPrecomputedData::<
877 <Chinese as ChineseBasedWithDataLoading>::CB,
878 >::default()
879 .load_or_compute_info(year);
880 let code = MonthCode(code);
881 let ordinal = year.parse_month_code(code);
882 assert_eq!(
883 ordinal, None,
884 "Invalid month code failed for year: {}, code: {code}",
885 year.related_iso
886 );
887 }
888 }
889
890 #[test]
891 fn test_iso_chinese_roundtrip() {
892 let chinese_calculating = Chinese::new_always_calculating();
893 let chinese_cached = Chinese::new();
894
895 for i in -1000..=1000 {
896 let year = i;
897 let month = i as u8 % 12 + 1;
898 let day = i as u8 % 28 + 1;
899 let iso = Date::try_new_iso(year, month, day).unwrap();
900 do_twice(
901 &chinese_calculating,
902 &chinese_cached,
903 |chinese, calendar_type| {
904 let chinese = iso.to_calendar(chinese);
905 let result = chinese.to_calendar(Iso);
906 assert_eq!(iso, result, "[{calendar_type}] ISO to Chinese roundtrip failed!\nIso: {iso:?}\nChinese: {chinese:?}\nResult: {result:?}");
907 },
908 );
909 }
910 }
911
912 #[test]
913 fn test_consistent_with_icu() {
914 #[derive(Debug)]
915 struct TestCase {
916 iso_year: i32,
917 iso_month: u8,
918 iso_day: u8,
919 expected_rel_iso: i32,
920 expected_cyclic: u8,
921 expected_month: u8,
922 expected_day: u8,
923 }
924
925 let cases = [
926 TestCase {
927 iso_year: -2332,
928 iso_month: 3,
929 iso_day: 1,
930 expected_rel_iso: -2332,
931 expected_cyclic: 5,
932 expected_month: 1,
933 expected_day: 16,
934 },
935 TestCase {
936 iso_year: -2332,
937 iso_month: 2,
938 iso_day: 15,
939 expected_rel_iso: -2332,
940 expected_cyclic: 5,
941 expected_month: 1,
942 expected_day: 1,
943 },
944 TestCase {
945 iso_year: -2332,
947 iso_month: 2,
948 iso_day: 14,
949 expected_rel_iso: -2333,
950 expected_cyclic: 4,
951 expected_month: 13,
952 expected_day: 30,
953 },
954 TestCase {
955 iso_year: -2332,
957 iso_month: 1,
958 iso_day: 17,
959 expected_rel_iso: -2333,
960 expected_cyclic: 4,
961 expected_month: 13,
962 expected_day: 2,
963 },
964 TestCase {
965 iso_year: -2332,
967 iso_month: 1,
968 iso_day: 16,
969 expected_rel_iso: -2333,
970 expected_cyclic: 4,
971 expected_month: 13,
972 expected_day: 1,
973 },
974 TestCase {
975 iso_year: -2332,
976 iso_month: 1,
977 iso_day: 15,
978 expected_rel_iso: -2333,
979 expected_cyclic: 4,
980 expected_month: 12,
981 expected_day: 29,
982 },
983 TestCase {
984 iso_year: -2332,
985 iso_month: 1,
986 iso_day: 1,
987 expected_rel_iso: -2333,
988 expected_cyclic: 4,
989 expected_month: 12,
990 expected_day: 15,
991 },
992 TestCase {
993 iso_year: -2333,
994 iso_month: 1,
995 iso_day: 16,
996 expected_rel_iso: -2334,
997 expected_cyclic: 3,
998 expected_month: 12,
999 expected_day: 19,
1000 },
1001 ];
1002
1003 let chinese_calculating = Chinese::new_always_calculating();
1004 let chinese_cached = Chinese::new();
1005
1006 for case in cases {
1007 let iso = Date::try_new_iso(case.iso_year, case.iso_month, case.iso_day).unwrap();
1008
1009 do_twice(
1010 &chinese_calculating,
1011 &chinese_cached,
1012 |chinese, calendar_type| {
1013 let chinese = iso.to_calendar(chinese);
1014 let chinese_rel_iso = chinese.cyclic_year().related_iso;
1015 let chinese_cyclic = chinese.cyclic_year().year;
1016 let chinese_month = chinese.month().ordinal;
1017 let chinese_day = chinese.day_of_month().0;
1018
1019 assert_eq!(
1020 chinese_rel_iso, case.expected_rel_iso,
1021 "[{calendar_type}] Related ISO failed for test case: {case:?}"
1022 );
1023 assert_eq!(
1024 chinese_cyclic, case.expected_cyclic,
1025 "[{calendar_type}] Cyclic year failed for test case: {case:?}"
1026 );
1027 assert_eq!(
1028 chinese_month, case.expected_month,
1029 "[{calendar_type}] Month failed for test case: {case:?}"
1030 );
1031 assert_eq!(
1032 chinese_day, case.expected_day,
1033 "[{calendar_type}] Day failed for test case: {case:?}"
1034 );
1035 },
1036 );
1037 }
1038 }
1039}