diff --git a/Cargo.lock b/Cargo.lock index 7669ee53dae..e72800c7e32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1340,6 +1340,7 @@ name = "icu_datetime" version = "2.0.0" dependencies = [ "bincode", + "calendrical_calculations", "criterion", "databake", "displaydoc", diff --git a/components/datetime/Cargo.toml b/components/datetime/Cargo.toml index 5dc59bc935a..228a7c0fbbb 100644 --- a/components/datetime/Cargo.toml +++ b/components/datetime/Cargo.toml @@ -46,6 +46,7 @@ icu_locale = { workspace = true, optional = true } [dev-dependencies] +calendrical_calculations = { workspace = true } icu = { path = "../../components/icu", default-features = false } icu_calendar = { path = "../calendar", features = ["ixdtf"] } icu_provider_adapters = { path = "../../provider/adapters" } diff --git a/components/datetime/src/scaffold/calendar.rs b/components/datetime/src/scaffold/calendar.rs index 7d8e33bdf00..5a6f5d10b0b 100644 --- a/components/datetime/src/scaffold/calendar.rs +++ b/components/datetime/src/scaffold/calendar.rs @@ -91,12 +91,72 @@ impl CldrCalendar for Indian { type SkeletaV1 = DatetimePatternsDateIndianV1; } -impl CldrCalendar for Hijri { +/// [`hijri::Rules`]-specific formatting options. +/// +/// See [`CldrCalendar`]. +/// +/// The simplest implementation of this uses the same names +/// as some provided [`hijri::Rules`]: +/// +/// ```rust +/// use icu::calendar::cal::hijri; +/// use icu::datetime::scaffold::FormattableHijriRules; +/// +/// #[derive(Clone, Debug)] +/// struct MyRules; +/// +/// impl icu::calendar::cal::scaffold::UnstableSealed for MyRules {} +/// impl icu::datetime::scaffold::UnstableSealed for MyRules {} +/// +/// impl hijri::Rules for MyRules { +/// fn year_data(&self, _year: i32) -> hijri::HijriYearData { todo!() } +/// } +/// +/// impl FormattableHijriRules for MyRules { +/// type YearNamesV1 = ::YearNamesV1; +/// type MonthNamesV1 = ::MonthNamesV1; +/// type SkeletaV1 = ::SkeletaV1; +/// } +/// ``` +// TODO: default associated types would be nice (https://github.com/rust-lang/rust/issues/29661) +pub trait FormattableHijriRules: hijri::Rules + UnstableSealed { + /// The data marker for loading year symbols for this calendar. + type YearNamesV1: DataMarker>; + + /// The data marker for loading month symbols for this calendar. + type MonthNamesV1: DataMarker>; + + /// The data marker for loading skeleton patterns for this calendar. + type SkeletaV1: DataMarker>; +} + +impl UnstableSealed for hijri::TabularAlgorithm {} +impl FormattableHijriRules for hijri::TabularAlgorithm { + type YearNamesV1 = DatetimeNamesYearHijriV1; + type MonthNamesV1 = DatetimeNamesMonthHijriV1; + type SkeletaV1 = DatetimePatternsDateHijriV1; +} + +impl UnstableSealed for hijri::UmmAlQura {} +impl FormattableHijriRules for hijri::UmmAlQura { type YearNamesV1 = DatetimeNamesYearHijriV1; type MonthNamesV1 = DatetimeNamesMonthHijriV1; type SkeletaV1 = DatetimePatternsDateHijriV1; } +impl UnstableSealed for hijri::AstronomicalSimulation {} +impl FormattableHijriRules for hijri::AstronomicalSimulation { + type YearNamesV1 = DatetimeNamesYearHijriV1; + type MonthNamesV1 = DatetimeNamesMonthHijriV1; + type SkeletaV1 = DatetimePatternsDateHijriV1; +} + +impl CldrCalendar for Hijri { + type YearNamesV1 = R::YearNamesV1; + type MonthNamesV1 = R::MonthNamesV1; + type SkeletaV1 = R::SkeletaV1; +} + impl CldrCalendar for Japanese { type YearNamesV1 = DatetimeNamesYearJapaneseV1; type MonthNamesV1 = DatetimeNamesMonthJapaneseV1; diff --git a/components/datetime/src/scaffold/mod.rs b/components/datetime/src/scaffold/mod.rs index 8744d3f82c8..d3045706ed7 100644 --- a/components/datetime/src/scaffold/mod.rs +++ b/components/datetime/src/scaffold/mod.rs @@ -19,6 +19,7 @@ pub use calendar::ConvertCalendar; pub(crate) use calendar::FormattableAnyCalendar; pub(crate) use calendar::FormattableAnyCalendarKind; pub(crate) use calendar::FormattableAnyCalendarNamesLoader; +pub use calendar::FormattableHijriRules; pub use calendar::FullDataCalMarkers; pub use calendar::InFixedCalendar; pub use calendar::InSameCalendar; diff --git a/components/calendar/tests/hijri_iran.rs b/components/datetime/tests/hijri_iran.rs similarity index 79% rename from components/calendar/tests/hijri_iran.rs rename to components/datetime/tests/hijri_iran.rs index 43c55d7e97b..432a32a7bfc 100644 --- a/components/calendar/tests/hijri_iran.rs +++ b/components/datetime/tests/hijri_iran.rs @@ -7,9 +7,13 @@ use icu_calendar::cal::hijri::Rules; use icu_calendar::cal::hijri::TabularAlgorithm; use icu_calendar::cal::hijri::TabularAlgorithmEpoch; use icu_calendar::cal::hijri::TabularAlgorithmLeapYears; +use icu_calendar::cal::hijri::UmmAlQura; use icu_calendar::cal::Hijri; use icu_calendar::types::RataDie; use icu_calendar::Date; +use icu_datetime::fieldsets; +use icu_datetime::scaffold::FormattableHijriRules; +use icu_datetime::FixedCalendarDateTimeFormatter; static TEST_RD: [i64; 4] = [727274, 728714, 744313, 764652]; @@ -102,6 +106,14 @@ impl Rules for IranTestSighting { } } +// Use the same display names as for UAQ +impl icu_datetime::scaffold::UnstableSealed for IranTestSighting {} +impl FormattableHijriRules for IranTestSighting { + type MonthNamesV1 = ::MonthNamesV1; + type YearNamesV1 = ::YearNamesV1; + type SkeletaV1 = ::SkeletaV1; +} + #[test] fn test_hijri_iran_from_rd() { let calendar = Hijri(IranTestSighting); @@ -123,3 +135,21 @@ fn test_rd_from_hijri_iran() { assert_eq!(date.to_rata_die(), RataDie::new(*f_date), "{case:?}"); } } + +#[test] +fn test_format() { + let formatter = + FixedCalendarDateTimeFormatter::try_new(Default::default(), fieldsets::YMD::long()) + .unwrap(); + + assert_eq!( + formatter + .format( + &Date::try_new_gregorian(2022, 10, 12) + .unwrap() + .to_calendar(Hijri(IranTestSighting)) + ) + .to_string(), + "AH 1444 RabiÊ» I 16" + ); +}