1use crate::any_calendar::AnyCalendarKind;
45use crate::iso::{Iso, IsoDateInner};
46use crate::provider::{EraStartDate, JapaneseErasV1Marker, JapaneseExtendedErasV1Marker};
47use crate::{
48 types, AsCalendar, Calendar, CalendarError, Date, DateDuration, DateDurationUnit, DateTime,
49 Ref, Time,
50};
51use icu_provider::prelude::*;
52use tinystr::{tinystr, TinyStr16};
53
54#[derive(Clone, Debug, Default)]
81pub struct Japanese {
82 eras: DataPayload<JapaneseErasV1Marker>,
83}
84
85#[derive(Clone, Debug, Default)]
107pub struct JapaneseExtended(Japanese);
108
109#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
110pub struct JapaneseDateInner {
112 inner: IsoDateInner,
113 adjusted_year: i32,
114 era: TinyStr16,
115}
116
117impl Japanese {
118 #[cfg(feature = "compiled_data")]
124 pub const fn new() -> Self {
125 Self {
126 eras: DataPayload::from_static_ref(
127 crate::provider::Baked::SINGLETON_CALENDAR_JAPANESE_V1,
128 ),
129 }
130 }
131
132 icu_provider::gen_any_buffer_data_constructors!(locale: skip, options: skip, error: CalendarError,
133 #[cfg(skip)]
134 functions: [
135 new,
136 try_new_with_any_provider,
137 try_new_with_buffer_provider,
138 try_new_unstable,
139 Self,
140 ]);
141
142 #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::new)]
143 pub fn try_new_unstable<D: DataProvider<JapaneseErasV1Marker> + ?Sized>(
144 provider: &D,
145 ) -> Result<Self, CalendarError> {
146 Ok(Self {
147 eras: provider.load(Default::default())?.take_payload()?,
148 })
149 }
150
151 fn japanese_date_from_codes(
152 &self,
153 era: types::Era,
154 year: i32,
155 month_code: types::MonthCode,
156 day: u8,
157 debug_name: &'static str,
158 ) -> Result<JapaneseDateInner, CalendarError> {
159 let month = month_code.parsed();
160 let month = if let Some((month, false)) = month {
161 month
162 } else {
163 return Err(CalendarError::UnknownMonthCode(month_code.0, debug_name));
164 };
165
166 if month > 12 {
167 return Err(CalendarError::UnknownMonthCode(month_code.0, debug_name));
168 }
169
170 self.new_japanese_date_inner(era, year, month, day)
171 }
172
173 pub(crate) const DEBUG_NAME: &'static str = "Japanese";
174}
175
176impl JapaneseExtended {
177 #[cfg(feature = "compiled_data")]
183 pub const fn new() -> Self {
184 Self(Japanese {
185 eras: DataPayload::from_static_ref(
186 crate::provider::Baked::SINGLETON_CALENDAR_JAPANEXT_V1,
187 ),
188 })
189 }
190
191 icu_provider::gen_any_buffer_data_constructors!(locale: skip, options: skip, error: CalendarError,
192 #[cfg(skip)]
193 functions: [
194 new,
195 try_new_with_any_provider,
196 try_new_with_buffer_provider,
197 try_new_unstable,
198 Self,
199 ]);
200
201 #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::new)]
202 pub fn try_new_unstable<D: DataProvider<JapaneseExtendedErasV1Marker> + ?Sized>(
203 provider: &D,
204 ) -> Result<Self, CalendarError> {
205 Ok(Self(Japanese {
206 eras: provider.load(Default::default())?.take_payload()?.cast(),
207 }))
208 }
209
210 pub(crate) const DEBUG_NAME: &'static str = "Japanese (historical era data)";
211}
212
213impl Calendar for Japanese {
214 type DateInner = JapaneseDateInner;
215
216 fn date_from_codes(
217 &self,
218 era: types::Era,
219 year: i32,
220 month_code: types::MonthCode,
221 day: u8,
222 ) -> Result<Self::DateInner, CalendarError> {
223 self.japanese_date_from_codes(era, year, month_code, day, self.debug_name())
224 }
225
226 fn date_from_iso(&self, iso: Date<Iso>) -> JapaneseDateInner {
227 let (adjusted_year, era) = self.adjusted_year_for(iso.inner());
228 JapaneseDateInner {
229 inner: *iso.inner(),
230 adjusted_year,
231 era,
232 }
233 }
234
235 fn date_to_iso(&self, date: &Self::DateInner) -> Date<Iso> {
236 Date::from_raw(date.inner, Iso)
237 }
238
239 fn months_in_year(&self, date: &Self::DateInner) -> u8 {
240 Iso.months_in_year(&date.inner)
241 }
242
243 fn days_in_year(&self, date: &Self::DateInner) -> u16 {
244 Iso.days_in_year(&date.inner)
245 }
246
247 fn days_in_month(&self, date: &Self::DateInner) -> u8 {
248 Iso.days_in_month(&date.inner)
249 }
250
251 fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration<Self>) {
252 Iso.offset_date(&mut date.inner, offset.cast_unit());
253 let (adjusted_year, era) = self.adjusted_year_for(&date.inner);
254 date.adjusted_year = adjusted_year;
255 date.era = era
256 }
257
258 fn until(
259 &self,
260 date1: &Self::DateInner,
261 date2: &Self::DateInner,
262 _calendar2: &Self,
263 largest_unit: DateDurationUnit,
264 smallest_unit: DateDurationUnit,
265 ) -> DateDuration<Self> {
266 Iso.until(
267 &date1.inner,
268 &date2.inner,
269 &Iso,
270 largest_unit,
271 smallest_unit,
272 )
273 .cast_unit()
274 }
275
276 fn year(&self, date: &Self::DateInner) -> types::FormattableYear {
278 types::FormattableYear {
279 era: types::Era(date.era),
280 number: date.adjusted_year,
281 cyclic: None,
282 related_iso: None,
283 }
284 }
285
286 fn is_in_leap_year(&self, date: &Self::DateInner) -> bool {
287 Iso.is_in_leap_year(&date.inner)
288 }
289
290 fn month(&self, date: &Self::DateInner) -> types::FormattableMonth {
292 Iso.month(&date.inner)
293 }
294
295 fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth {
297 Iso.day_of_month(&date.inner)
298 }
299
300 fn day_of_year_info(&self, date: &Self::DateInner) -> types::DayOfYearInfo {
302 let prev_dec_31 = IsoDateInner::dec_31(date.inner.0.year - 1);
303 let next_jan_1 = IsoDateInner::jan_1(date.inner.0.year + 1);
304
305 let prev_dec_31 = self.date_from_iso(Date::from_raw(prev_dec_31, Iso));
306 let next_jan_1 = self.date_from_iso(Date::from_raw(next_jan_1, Iso));
307 types::DayOfYearInfo {
308 day_of_year: Iso::days_in_year_direct(date.inner.0.year),
309 days_in_year: Iso::days_in_year_direct(date.inner.0.year),
310 prev_year: self.year(&prev_dec_31),
311 days_in_prev_year: Iso::days_in_year_direct(prev_dec_31.inner.0.year),
312 next_year: self.year(&next_jan_1),
313 }
314 }
315
316 fn debug_name(&self) -> &'static str {
317 Self::DEBUG_NAME
318 }
319
320 fn any_calendar_kind(&self) -> Option<AnyCalendarKind> {
321 Some(AnyCalendarKind::Japanese)
322 }
323}
324
325impl Calendar for JapaneseExtended {
326 type DateInner = JapaneseDateInner;
327
328 fn date_from_codes(
329 &self,
330 era: types::Era,
331 year: i32,
332 month_code: types::MonthCode,
333 day: u8,
334 ) -> Result<Self::DateInner, CalendarError> {
335 self.0
336 .japanese_date_from_codes(era, year, month_code, day, self.debug_name())
337 }
338
339 fn date_from_iso(&self, iso: Date<Iso>) -> JapaneseDateInner {
340 Japanese::date_from_iso(&self.0, iso)
341 }
342
343 fn date_to_iso(&self, date: &Self::DateInner) -> Date<Iso> {
344 Japanese::date_to_iso(&self.0, date)
345 }
346
347 fn months_in_year(&self, date: &Self::DateInner) -> u8 {
348 Japanese::months_in_year(&self.0, date)
349 }
350
351 fn days_in_year(&self, date: &Self::DateInner) -> u16 {
352 Japanese::days_in_year(&self.0, date)
353 }
354
355 fn days_in_month(&self, date: &Self::DateInner) -> u8 {
356 Japanese::days_in_month(&self.0, date)
357 }
358
359 fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration<Self>) {
360 Japanese::offset_date(&self.0, date, offset.cast_unit())
361 }
362
363 fn until(
364 &self,
365 date1: &Self::DateInner,
366 date2: &Self::DateInner,
367 calendar2: &Self,
368 largest_unit: DateDurationUnit,
369 smallest_unit: DateDurationUnit,
370 ) -> DateDuration<Self> {
371 Japanese::until(
372 &self.0,
373 date1,
374 date2,
375 &calendar2.0,
376 largest_unit,
377 smallest_unit,
378 )
379 .cast_unit()
380 }
381
382 fn year(&self, date: &Self::DateInner) -> types::FormattableYear {
384 Japanese::year(&self.0, date)
385 }
386
387 fn is_in_leap_year(&self, date: &Self::DateInner) -> bool {
388 Japanese::is_in_leap_year(&self.0, date)
389 }
390
391 fn month(&self, date: &Self::DateInner) -> types::FormattableMonth {
393 Japanese::month(&self.0, date)
394 }
395
396 fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth {
398 Japanese::day_of_month(&self.0, date)
399 }
400
401 fn day_of_year_info(&self, date: &Self::DateInner) -> types::DayOfYearInfo {
403 Japanese::day_of_year_info(&self.0, date)
404 }
405
406 fn debug_name(&self) -> &'static str {
407 Self::DEBUG_NAME
408 }
409
410 fn any_calendar_kind(&self) -> Option<AnyCalendarKind> {
411 Some(AnyCalendarKind::JapaneseExtended)
412 }
413}
414
415impl Date<Japanese> {
416 pub fn try_new_japanese_date<A: AsCalendar<Calendar = Japanese>>(
456 era: types::Era,
457 year: i32,
458 month: u8,
459 day: u8,
460 japanese_calendar: A,
461 ) -> Result<Date<A>, CalendarError> {
462 let inner = japanese_calendar
463 .as_calendar()
464 .new_japanese_date_inner(era, year, month, day)?;
465 Ok(Date::from_raw(inner, japanese_calendar))
466 }
467}
468
469impl Date<JapaneseExtended> {
470 pub fn try_new_japanese_extended_date<A: AsCalendar<Calendar = JapaneseExtended>>(
499 era: types::Era,
500 year: i32,
501 month: u8,
502 day: u8,
503 japanext_calendar: A,
504 ) -> Result<Date<A>, CalendarError> {
505 let inner = japanext_calendar
506 .as_calendar()
507 .0
508 .new_japanese_date_inner(era, year, month, day)?;
509 Ok(Date::from_raw(inner, japanext_calendar))
510 }
511
512 #[doc(hidden)]
514 pub fn into_japanese_date(self) -> Date<Japanese> {
515 Date::from_raw(self.inner, self.calendar.0)
516 }
517}
518
519impl DateTime<Japanese> {
520 #[allow(clippy::too_many_arguments)] pub fn try_new_japanese_datetime<A: AsCalendar<Calendar = Japanese>>(
557 era: types::Era,
558 year: i32,
559 month: u8,
560 day: u8,
561 hour: u8,
562 minute: u8,
563 second: u8,
564 japanese_calendar: A,
565 ) -> Result<DateTime<A>, CalendarError> {
566 Ok(DateTime {
567 date: Date::try_new_japanese_date(era, year, month, day, japanese_calendar)?,
568 time: Time::try_new(hour, minute, second, 0)?,
569 })
570 }
571}
572
573impl DateTime<JapaneseExtended> {
574 #[allow(clippy::too_many_arguments)] pub fn try_new_japanese_extended_datetime<A: AsCalendar<Calendar = JapaneseExtended>>(
611 era: types::Era,
612 year: i32,
613 month: u8,
614 day: u8,
615 hour: u8,
616 minute: u8,
617 second: u8,
618 japanext_calendar: A,
619 ) -> Result<DateTime<A>, CalendarError> {
620 Ok(DateTime {
621 date: Date::try_new_japanese_extended_date(era, year, month, day, japanext_calendar)?,
622 time: Time::try_new(hour, minute, second, 0)?,
623 })
624 }
625}
626
627const MEIJI_START: EraStartDate = EraStartDate {
628 year: 1868,
629 month: 9,
630 day: 8,
631};
632const TAISHO_START: EraStartDate = EraStartDate {
633 year: 1912,
634 month: 7,
635 day: 30,
636};
637const SHOWA_START: EraStartDate = EraStartDate {
638 year: 1926,
639 month: 12,
640 day: 25,
641};
642const HEISEI_START: EraStartDate = EraStartDate {
643 year: 1989,
644 month: 1,
645 day: 8,
646};
647const REIWA_START: EraStartDate = EraStartDate {
648 year: 2019,
649 month: 5,
650 day: 1,
651};
652
653const FALLBACK_ERA: (EraStartDate, TinyStr16) = (REIWA_START, tinystr!(16, "reiwa"));
654
655impl Japanese {
656 fn adjusted_year_for(&self, date: &IsoDateInner) -> (i32, TinyStr16) {
660 let date: EraStartDate = date.into();
661 let (start, era) = self.japanese_era_for(date);
662 if date < start {
668 if date.year <= 0 {
669 (1 - date.year, tinystr!(16, "bce"))
670 } else {
671 (date.year, tinystr!(16, "ce"))
672 }
673 } else {
674 (date.year - start.year + 1, era)
675 }
676 }
677
678 fn japanese_era_for(&self, date: EraStartDate) -> (EraStartDate, TinyStr16) {
680 let era_data = self.eras.get();
681 if date >= MEIJI_START
685 && era_data.dates_to_eras.last().map(|x| x.1) == Some(tinystr!(16, "reiwa"))
686 {
687 return if date >= REIWA_START {
689 (REIWA_START, tinystr!(16, "reiwa"))
690 } else if date >= HEISEI_START {
691 (HEISEI_START, tinystr!(16, "heisei"))
692 } else if date >= SHOWA_START {
693 (SHOWA_START, tinystr!(16, "showa"))
694 } else if date >= TAISHO_START {
695 (TAISHO_START, tinystr!(16, "taisho"))
696 } else {
697 (MEIJI_START, tinystr!(16, "meiji"))
698 };
699 }
700 let data = &era_data.dates_to_eras;
701 match data.binary_search_by(|(d, _)| d.cmp(&date)) {
702 Ok(index) => data.get(index),
703 Err(index) if index == 0 => data.get(index),
704 Err(index) => data.get(index - 1).or_else(|| data.iter().next_back()),
705 }
706 .unwrap_or(FALLBACK_ERA)
707 }
708
709 fn japanese_era_range_for(
714 &self,
715 era: TinyStr16,
716 ) -> Result<(EraStartDate, Option<EraStartDate>), CalendarError> {
717 if era == tinystr!(16, "reiwa") {
719 if let Some(last) = self.eras.get().dates_to_eras.last() {
721 if last.1 == era {
722 return Ok((REIWA_START, None));
723 }
724 }
725 } else if era == tinystr!(16, "heisei") {
726 return Ok((HEISEI_START, Some(REIWA_START)));
727 } else if era == tinystr!(16, "showa") {
728 return Ok((SHOWA_START, Some(HEISEI_START)));
729 } else if era == tinystr!(16, "taisho") {
730 return Ok((TAISHO_START, Some(SHOWA_START)));
731 } else if era == tinystr!(16, "meiji") {
732 return Ok((MEIJI_START, Some(TAISHO_START)));
733 }
734
735 let era_data = self.eras.get();
736 let data = &era_data.dates_to_eras;
737 if let Some(year) = era.split('-').nth(1) {
739 if let Ok(ref int) = year.parse::<i32>() {
740 if let Ok(index) = data.binary_search_by(|(d, _)| d.year.cmp(int)) {
741 #[allow(clippy::expect_used)] let (era_start, code) = data
743 .get(index)
744 .expect("Indexing from successful binary search must succeed");
745 if code == era {
749 return Ok((era_start, data.get(index + 1).map(|e| e.0)));
750 }
751 }
752 }
753 }
754
755 if let Some((index, (start, _))) = data.iter().enumerate().rev().find(|d| d.1 .1 == era) {
757 return Ok((start, data.get(index + 1).map(|e| e.0)));
758 }
759
760 Err(CalendarError::UnknownEra(era, self.debug_name()))
761 }
762
763 fn new_japanese_date_inner(
764 &self,
765 era: types::Era,
766 year: i32,
767 month: u8,
768 day: u8,
769 ) -> Result<JapaneseDateInner, CalendarError> {
770 let cal = Ref(self);
771 if era.0 == tinystr!(16, "bce") {
772 if year <= 0 {
773 return Err(CalendarError::OutOfRange);
774 }
775 return Ok(Date::try_new_iso_date(1 - year, month, day)?
776 .to_calendar(cal)
777 .inner);
778 } else if era.0 == tinystr!(16, "ce") {
779 if year <= 0 {
780 return Err(CalendarError::OutOfRange);
781 }
782 return Ok(Date::try_new_iso_date(year, month, day)?
783 .to_calendar(cal)
784 .inner);
785 }
786
787 let (era_start, next_era_start) = self.japanese_era_range_for(era.0)?;
788
789 let date_in_iso = EraStartDate {
790 year: era_start.year + year - 1,
791 month,
792 day,
793 };
794
795 if date_in_iso < era_start {
796 return Err(CalendarError::OutOfRange);
797 } else if let Some(next_era_start) = next_era_start {
798 if date_in_iso >= next_era_start {
799 return Err(CalendarError::OutOfRange);
800 }
801 }
802
803 let iso = Date::try_new_iso_date(date_in_iso.year, date_in_iso.month, date_in_iso.day)?;
804 Ok(JapaneseDateInner {
805 inner: iso.inner,
806 adjusted_year: year,
807 era: era.0,
808 })
809 }
810}
811
812#[cfg(test)]
813mod tests {
814 use super::*;
815 use crate::Ref;
816
817 fn single_test_roundtrip(calendar: Ref<Japanese>, era: &str, year: i32, month: u8, day: u8) {
818 let era = types::Era(era.parse().expect("era must parse"));
819
820 let date =
821 Date::try_new_japanese_date(era, year, month, day, calendar).unwrap_or_else(|e| {
822 panic!("Failed to construct date with {era:?}, {year}, {month}, {day}: {e}")
823 });
824 let iso = date.to_iso();
825 let reconstructed = Date::new_from_iso(iso, calendar);
826 assert_eq!(
827 date, reconstructed,
828 "Failed to roundtrip with {era:?}, {year}, {month}, {day}"
829 );
830
831 assert_eq!(reconstructed.year().era, era);
833 assert_eq!(reconstructed.year().number, year);
834 }
835
836 fn single_test_roundtrip_ext(
837 calendar: Ref<JapaneseExtended>,
838 era: &str,
839 year: i32,
840 month: u8,
841 day: u8,
842 ) {
843 let era = types::Era(era.parse().expect("era must parse"));
844
845 let date = Date::try_new_japanese_extended_date(era, year, month, day, calendar)
846 .unwrap_or_else(|e| {
847 panic!("Failed to construct date with {era:?}, {year}, {month}, {day}: {e}")
848 });
849 let iso = date.to_iso();
850 let reconstructed = Date::new_from_iso(iso, calendar);
851 assert_eq!(
852 date, reconstructed,
853 "Failed to roundtrip with {era:?}, {year}, {month}, {day}"
854 )
855 }
856
857 fn single_test_gregorian_roundtrip_ext(
859 calendar: Ref<JapaneseExtended>,
860 era: &str,
861 year: i32,
862 month: u8,
863 day: u8,
864 era2: &str,
865 year2: i32,
866 ) {
867 let era = types::Era(era.parse().expect("era must parse"));
868 let era2 = types::Era(era2.parse().expect("era must parse"));
869
870 let expected = Date::try_new_japanese_extended_date(era2, year2, month, day, calendar)
871 .unwrap_or_else(|e| {
872 panic!(
873 "Failed to construct expectation date with {era2:?}, {year2}, {month}, {day}: {e}"
874 )
875 });
876
877 let date = Date::try_new_japanese_extended_date(era, year, month, day, calendar)
878 .unwrap_or_else(|e| {
879 panic!("Failed to construct date with {era:?}, {year}, {month}, {day}: {e}")
880 });
881 let iso = date.to_iso();
882 let reconstructed = Date::new_from_iso(iso, calendar);
883 assert_eq!(
884 expected, reconstructed,
885 "Failed to roundtrip with {era:?}, {year}, {month}, {day} == {era2:?}, {year}"
886 )
887 }
888
889 fn single_test_error(
890 calendar: Ref<Japanese>,
891 era: &str,
892 year: i32,
893 month: u8,
894 day: u8,
895 error: CalendarError,
896 ) {
897 let era = types::Era(era.parse().expect("era must parse"));
898
899 let date = Date::try_new_japanese_date(era, year, month, day, calendar);
900 assert_eq!(
901 date,
902 Err(error),
903 "Construction with {era:?}, {year}, {month}, {day} did not return {error:?}"
904 )
905 }
906
907 fn single_test_error_ext(
908 calendar: Ref<JapaneseExtended>,
909 era: &str,
910 year: i32,
911 month: u8,
912 day: u8,
913 error: CalendarError,
914 ) {
915 let era = types::Era(era.parse().expect("era must parse"));
916
917 let date = Date::try_new_japanese_extended_date(era, year, month, day, calendar);
918 assert_eq!(
919 date,
920 Err(error),
921 "Construction with {era:?}, {year}, {month}, {day} did not return {error:?}"
922 )
923 }
924
925 #[test]
926 fn test_japanese() {
927 let calendar = Japanese::new();
928 let calendar_ext = JapaneseExtended::new();
929 let calendar = Ref(&calendar);
930 let calendar_ext = Ref(&calendar_ext);
931
932 single_test_roundtrip(calendar, "heisei", 12, 3, 1);
933 single_test_roundtrip(calendar, "taisho", 3, 3, 1);
934 single_test_error(calendar, "heisei", 1, 1, 1, CalendarError::OutOfRange);
936
937 single_test_roundtrip_ext(calendar_ext, "heisei", 12, 3, 1);
938 single_test_roundtrip_ext(calendar_ext, "taisho", 3, 3, 1);
939 single_test_error_ext(calendar_ext, "heisei", 1, 1, 1, CalendarError::OutOfRange);
940
941 single_test_roundtrip_ext(calendar_ext, "hakuho-672", 4, 3, 1);
942 single_test_error(
943 calendar,
944 "hakuho-672",
945 4,
946 3,
947 1,
948 CalendarError::UnknownEra("hakuho-672".parse().unwrap(), "Japanese"),
949 );
950
951 single_test_roundtrip(calendar, "bce", 100, 3, 1);
953 single_test_roundtrip(calendar, "bce", 1, 3, 1);
954 single_test_roundtrip(calendar, "ce", 1, 3, 1);
955 single_test_roundtrip(calendar, "ce", 100, 3, 1);
956 single_test_roundtrip_ext(calendar_ext, "ce", 100, 3, 1);
957 single_test_roundtrip(calendar, "ce", 1000, 3, 1);
958 single_test_error(calendar, "ce", 0, 3, 1, CalendarError::OutOfRange);
959 single_test_error(calendar, "bce", -1, 3, 1, CalendarError::OutOfRange);
960
961 single_test_gregorian_roundtrip_ext(calendar_ext, "ce", 1000, 3, 1, "choho-999", 2);
964 single_test_gregorian_roundtrip_ext(calendar_ext, "ce", 749, 5, 10, "tenpyokampo-749", 1);
965 single_test_gregorian_roundtrip_ext(calendar_ext, "bce", 10, 3, 1, "bce", 10);
966
967 single_test_roundtrip_ext(calendar_ext, "tenpyokampo-749", 1, 4, 20);
970 single_test_roundtrip_ext(calendar_ext, "tenpyokampo-749", 1, 4, 14);
971 single_test_roundtrip_ext(calendar_ext, "tenpyokampo-749", 1, 7, 1);
972 single_test_error_ext(
973 calendar_ext,
974 "tenpyokampo-749",
975 1,
976 7,
977 5,
978 CalendarError::OutOfRange,
979 );
980 single_test_error_ext(
981 calendar_ext,
982 "tenpyokampo-749",
983 1,
984 4,
985 13,
986 CalendarError::OutOfRange,
987 );
988 }
989}