diff --git a/components/calendar/src/cal/abstract_gregorian.rs b/components/calendar/src/cal/abstract_gregorian.rs index 72183638481..bbfd9d0bb1b 100644 --- a/components/calendar/src/cal/abstract_gregorian.rs +++ b/components/calendar/src/cal/abstract_gregorian.rs @@ -22,7 +22,13 @@ pub(crate) trait GregorianYears: Clone + core::fmt::Debug { fn extended_from_era_year(&self, era: Option<&[u8]>, year: i32) -> Result; - fn era_year_from_extended(&self, extended_year: i32, month: u8, day: u8) -> EraYear; + fn era_year_from_extended( + &self, + extended_year: i32, + related_gregorian: i32, + month: u8, + day: u8, + ) -> EraYear; fn calendar_algorithm(&self) -> Option { None @@ -164,6 +170,7 @@ impl Calendar for AbstractGregorian { fn year_info(&self, date: &Self::DateInner) -> Self::Year { self.0.era_year_from_extended( date.year() - Y::EXTENDED_YEAR_OFFSET, + date.year(), date.month(), date.day(), ) diff --git a/components/calendar/src/cal/buddhist.rs b/components/calendar/src/cal/buddhist.rs index 73569c90a64..1fb14b1dd6d 100644 --- a/components/calendar/src/cal/buddhist.rs +++ b/components/calendar/src/cal/buddhist.rs @@ -55,11 +55,18 @@ impl GregorianYears for BuddhistEra { } } - fn era_year_from_extended(&self, extended_year: i32, _month: u8, _day: u8) -> types::EraYear { + fn era_year_from_extended( + &self, + extended_year: i32, + related_gregorian: i32, + _month: u8, + _day: u8, + ) -> types::EraYear { types::EraYear { era: tinystr!(16, "be"), era_index: Some(0), year: extended_year, + related_gregorian, extended_year, ambiguity: types::YearAmbiguity::CenturyRequired, } diff --git a/components/calendar/src/cal/coptic.rs b/components/calendar/src/cal/coptic.rs index 8c1a58e9eb9..b7be0b2b0ac 100644 --- a/components/calendar/src/cal/coptic.rs +++ b/components/calendar/src/cal/coptic.rs @@ -200,10 +200,15 @@ impl Calendar for Coptic { fn year_info(&self, date: &Self::DateInner) -> Self::Year { let year = date.0.year(); + let related_gregorian = calendrical_calculations::gregorian::year_from_fixed( + calendrical_calculations::coptic::fixed_from_coptic(year, 1, 1), + ) + .unwrap_or_else(|e| e.saturate()); types::EraYear { era: tinystr!(16, "am"), era_index: Some(0), year, + related_gregorian, extended_year: year, ambiguity: types::YearAmbiguity::CenturyRequired, } @@ -289,4 +294,41 @@ mod tests { let date = Date::try_from_fields(fields, options, Coptic).unwrap(); assert_eq!(date.day_of_month().0, 6, "Day was successfully constrained"); } + + #[test] + fn related_gregorian() { + assert_eq!( + Date::try_new_gregorian(2025, 8, 18) + .unwrap() + .to_calendar(Coptic) + .era_year() + .related_gregorian, + 2024 + ); + assert_eq!( + Date::try_new_gregorian(2025, 9, 18) + .unwrap() + .to_calendar(Coptic) + .era_year() + .related_gregorian, + 2025 + ); + + // By 16702 the Coptic calendar is a full year ahead + // of the Gregorian calendar + assert_eq!( + Date::try_new_coptic(16419, 1, 1) + .unwrap() + .era_year() + .related_gregorian, + 16702 + ); + assert_eq!( + Date::try_new_coptic(16420, 1, 1) + .unwrap() + .era_year() + .related_gregorian, + 16704 + ); + } } diff --git a/components/calendar/src/cal/ethiopian.rs b/components/calendar/src/cal/ethiopian.rs index e4995b1017c..6f713c0dcdf 100644 --- a/components/calendar/src/cal/ethiopian.rs +++ b/components/calendar/src/cal/ethiopian.rs @@ -207,18 +207,19 @@ impl Calendar for Ethiopian { } fn year_info(&self, date: &Self::DateInner) -> Self::Year { - let coptic_year = date.0 .0.year(); + let coptic_year = Coptic.year_info(&date.0); let extended_year = if self.0 == EthiopianEraStyle::AmeteAlem { - coptic_year - AMETE_ALEM_OFFSET + coptic_year.extended_year - AMETE_ALEM_OFFSET } else { - coptic_year - AMETE_MIHRET_OFFSET + coptic_year.extended_year - AMETE_MIHRET_OFFSET }; if self.0 == EthiopianEraStyle::AmeteAlem || extended_year <= 0 { types::EraYear { era: tinystr!(16, "aa"), era_index: Some(0), - year: coptic_year - AMETE_ALEM_OFFSET, + year: coptic_year.year - AMETE_ALEM_OFFSET, + related_gregorian: coptic_year.related_gregorian, extended_year, ambiguity: types::YearAmbiguity::CenturyRequired, } @@ -226,7 +227,8 @@ impl Calendar for Ethiopian { types::EraYear { era: tinystr!(16, "am"), era_index: Some(1), - year: coptic_year - AMETE_MIHRET_OFFSET, + year: coptic_year.year - AMETE_MIHRET_OFFSET, + related_gregorian: coptic_year.related_gregorian, extended_year, ambiguity: types::YearAmbiguity::CenturyRequired, } @@ -390,4 +392,41 @@ mod test { 1 ); } + + #[test] + fn related_gregorian() { + assert_eq!( + Date::try_new_gregorian(2025, 8, 18) + .unwrap() + .to_calendar(Ethiopian::new()) + .era_year() + .related_gregorian, + 2024 + ); + assert_eq!( + Date::try_new_gregorian(2025, 9, 18) + .unwrap() + .to_calendar(Ethiopian::new()) + .era_year() + .related_gregorian, + 2025 + ); + + // By 16702 the Ethiopian calendar is a full year ahead + // of the Gregorian calendar + assert_eq!( + Date::try_new_ethiopian(EthiopianEraStyle::AmeteMihret, 16695, 1, 1) + .unwrap() + .era_year() + .related_gregorian, + 16702 + ); + assert_eq!( + Date::try_new_ethiopian(EthiopianEraStyle::AmeteMihret, 16696, 1, 1) + .unwrap() + .era_year() + .related_gregorian, + 16704 + ); + } } diff --git a/components/calendar/src/cal/gregorian.rs b/components/calendar/src/cal/gregorian.rs index b18a5ae13d8..1e144f6f345 100644 --- a/components/calendar/src/cal/gregorian.rs +++ b/components/calendar/src/cal/gregorian.rs @@ -30,12 +30,19 @@ impl GregorianYears for CeBce { } } - fn era_year_from_extended(&self, extended_year: i32, _month: u8, _day: u8) -> types::EraYear { + fn era_year_from_extended( + &self, + extended_year: i32, + related_gregorian: i32, + _month: u8, + _day: u8, + ) -> types::EraYear { if extended_year > 0 { types::EraYear { era: tinystr!(16, "ce"), era_index: Some(1), year: extended_year, + related_gregorian, extended_year, ambiguity: match extended_year { ..=999 => types::YearAmbiguity::EraAndCenturyRequired, @@ -49,6 +56,7 @@ impl GregorianYears for CeBce { era: tinystr!(16, "bce"), era_index: Some(0), year: 1 - extended_year, + related_gregorian, extended_year, ambiguity: types::YearAmbiguity::EraAndCenturyRequired, } diff --git a/components/calendar/src/cal/hebrew.rs b/components/calendar/src/cal/hebrew.rs index e1922a55dd6..15e78c0f67f 100644 --- a/components/calendar/src/cal/hebrew.rs +++ b/components/calendar/src/cal/hebrew.rs @@ -316,10 +316,14 @@ impl Calendar for Hebrew { fn year_info(&self, date: &Self::DateInner) -> Self::Year { let extended_year = date.0.year().value; + let related_gregorian = + calendrical_calculations::gregorian::year_from_fixed(date.0.year().new_year()) + .unwrap_or_else(|e| e.saturate()); types::EraYear { era_index: Some(0), era: tinystr!(16, "am"), year: extended_year, + related_gregorian, extended_year, ambiguity: types::YearAmbiguity::CenturyRequired, } @@ -524,4 +528,41 @@ mod tests { // https://www.hebcal.com/converter?hd=1&hm=Tishrei&hy=3760&h2g=1 assert_eq!(dt.weekday(), Weekday::Saturday); } + + #[test] + fn related_gregorian() { + assert_eq!( + Date::try_new_gregorian(2025, 9, 18) + .unwrap() + .to_calendar(Hebrew) + .era_year() + .related_gregorian, + 2024 + ); + assert_eq!( + Date::try_new_gregorian(2025, 10, 18) + .unwrap() + .to_calendar(Hebrew) + .era_year() + .related_gregorian, + 2025 + ); + + // By 22203 the Hebrew calendar is a full year ahead + // of the Gregorian calendar + assert_eq!( + Date::try_new_from_codes(None, 25962, TISHREI.code(), 1, Hebrew) + .unwrap() + .era_year() + .related_gregorian, + 22201 + ); + assert_eq!( + Date::try_new_from_codes(None, 25963, TISHREI.code(), 1, Hebrew) + .unwrap() + .era_year() + .related_gregorian, + 22203 + ); + } } diff --git a/components/calendar/src/cal/hijri.rs b/components/calendar/src/cal/hijri.rs index 032e7b73b79..e44c8efec42 100644 --- a/components/calendar/src/cal/hijri.rs +++ b/components/calendar/src/cal/hijri.rs @@ -911,11 +911,15 @@ impl Calendar for Hijri { fn year_info(&self, date: &Self::DateInner) -> Self::Year { let extended_year = date.0.year().extended_year; + let related_gregorian = + calendrical_calculations::gregorian::year_from_fixed(date.0.year().new_year()) + .unwrap_or_else(|e| e.saturate()); if extended_year > 0 { types::EraYear { era: tinystr!(16, "ah"), era_index: Some(0), year: extended_year, + related_gregorian, extended_year, ambiguity: types::YearAmbiguity::CenturyRequired, } @@ -925,6 +929,7 @@ impl Calendar for Hijri { era_index: Some(1), year: 1 - extended_year, extended_year, + related_gregorian, ambiguity: types::YearAmbiguity::CenturyRequired, } } @@ -1951,4 +1956,24 @@ mod test { single_roundtrip(mixed2, start_1600 - 1).unwrap(); single_roundtrip(mixed2, start_1600 - 4).unwrap(); } + + #[test] + fn related_gregorian() { + assert_eq!( + Date::try_new_gregorian(2025, 6, 18) + .unwrap() + .to_calendar(Hijri::new_umm_al_qura()) + .era_year() + .related_gregorian, + 2024 + ); + assert_eq!( + Date::try_new_gregorian(2025, 7, 18) + .unwrap() + .to_calendar(Hijri::new_umm_al_qura()) + .era_year() + .related_gregorian, + 2025 + ); + } } diff --git a/components/calendar/src/cal/indian.rs b/components/calendar/src/cal/indian.rs index d16e7f6490c..9aff80af964 100644 --- a/components/calendar/src/cal/indian.rs +++ b/components/calendar/src/cal/indian.rs @@ -244,6 +244,7 @@ impl Calendar for Indian { era: tinystr!(16, "shaka"), year: extended_year, extended_year, + related_gregorian: extended_year + YEAR_OFFSET + 1, ambiguity: types::YearAmbiguity::CenturyRequired, } } @@ -544,4 +545,24 @@ mod tests { } } } + + #[test] + fn related_gregorian() { + assert_eq!( + Date::try_new_gregorian(2025, 3, 18) + .unwrap() + .to_calendar(Indian) + .era_year() + .related_gregorian, + 2025 + ); + assert_eq!( + Date::try_new_gregorian(2025, 4, 18) + .unwrap() + .to_calendar(Indian) + .era_year() + .related_gregorian, + 2026 + ); + } } diff --git a/components/calendar/src/cal/iso.rs b/components/calendar/src/cal/iso.rs index 387cc0d273a..b7207eed507 100644 --- a/components/calendar/src/cal/iso.rs +++ b/components/calendar/src/cal/iso.rs @@ -41,11 +41,18 @@ impl GregorianYears for IsoEra { } } - fn era_year_from_extended(&self, extended_year: i32, _month: u8, _day: u8) -> types::EraYear { + fn era_year_from_extended( + &self, + extended_year: i32, + related_gregorian: i32, + _month: u8, + _day: u8, + ) -> types::EraYear { types::EraYear { era_index: Some(0), era: tinystr!(16, "default"), year: extended_year, + related_gregorian, extended_year, ambiguity: types::YearAmbiguity::Unambiguous, } diff --git a/components/calendar/src/cal/japanese.rs b/components/calendar/src/cal/japanese.rs index 7bf82229d86..b7127611f9f 100644 --- a/components/calendar/src/cal/japanese.rs +++ b/components/calendar/src/cal/japanese.rs @@ -222,7 +222,13 @@ impl GregorianYears for &'_ Japanese { Ok(era_start.year + year - 1) } - fn era_year_from_extended(&self, year: i32, month: u8, day: u8) -> types::EraYear { + fn era_year_from_extended( + &self, + year: i32, + related_gregorian: i32, + month: u8, + day: u8, + ) -> types::EraYear { let date: EraStartDate = EraStartDate { year, month, day }; let (start, era) = if date >= MEIJI_START @@ -255,7 +261,7 @@ impl GregorianYears for &'_ Japanese { return types::EraYear { // TODO: return era indices? era_index: None, - ..CeBce.era_year_from_extended(year, month, day) + ..CeBce.era_year_from_extended(year, related_gregorian, month, day) }; } Ok(index) => data.get(index).unwrap(), @@ -267,6 +273,7 @@ impl GregorianYears for &'_ Japanese { era, era_index: None, year: year - start.year + 1, + related_gregorian, extended_year: year, ambiguity: types::YearAmbiguity::CenturyRequired, } diff --git a/components/calendar/src/cal/julian.rs b/components/calendar/src/cal/julian.rs index 8c7f09aa77c..e2e52cb55a2 100644 --- a/components/calendar/src/cal/julian.rs +++ b/components/calendar/src/cal/julian.rs @@ -211,11 +211,16 @@ impl Calendar for Julian { /// Julian has the same era scheme as Gregorian fn year_info(&self, date: &Self::DateInner) -> Self::Year { let extended_year = date.0.year(); + let related_gregorian = calendrical_calculations::gregorian::year_from_fixed( + calendrical_calculations::julian::day_before_year(extended_year) + 1, + ) + .unwrap_or_else(|e| e.saturate()); if extended_year > 0 { types::EraYear { era: tinystr!(16, "ce"), era_index: Some(1), year: extended_year, + related_gregorian, extended_year, ambiguity: types::YearAmbiguity::CenturyRequired, } @@ -224,6 +229,7 @@ impl Calendar for Julian { era: tinystr!(16, "bce"), era_index: Some(0), year: 1 - extended_year, + related_gregorian, extended_year, ambiguity: types::YearAmbiguity::EraAndCenturyRequired, } @@ -500,4 +506,24 @@ mod test { Date::try_new_julian(-4, 2, 29).unwrap(); Date::try_new_julian(2020, 2, 29).unwrap(); } + + #[test] + fn related_gregorian() { + // By 48901 the Julian calendar is a full year ahead + // of the Gregorian calendar + assert_eq!( + Date::try_new_julian(48900, 1, 1) + .unwrap() + .era_year() + .related_gregorian, + 48900 + ); + assert_eq!( + Date::try_new_julian(48901, 1, 1) + .unwrap() + .era_year() + .related_gregorian, + 48902 + ); + } } diff --git a/components/calendar/src/cal/persian.rs b/components/calendar/src/cal/persian.rs index a3afb919c0f..98fa400b8e8 100644 --- a/components/calendar/src/cal/persian.rs +++ b/components/calendar/src/cal/persian.rs @@ -188,6 +188,7 @@ impl Calendar for Persian { era: tinystr!(16, "ap"), era_index: Some(0), year: extended_year, + related_gregorian: extended_year + 622, extended_year, ambiguity: types::YearAmbiguity::CenturyRequired, } @@ -745,4 +746,24 @@ mod tests { assert_eq!(iso_date.to_calendar(Persian), persian_date); } } + + #[test] + fn related_gregorian() { + assert_eq!( + Date::try_new_gregorian(2025, 3, 18) + .unwrap() + .to_calendar(Persian) + .era_year() + .related_gregorian, + 2025 + ); + assert_eq!( + Date::try_new_gregorian(2025, 4, 18) + .unwrap() + .to_calendar(Persian) + .era_year() + .related_gregorian, + 2026 + ); + } } diff --git a/components/calendar/src/cal/roc.rs b/components/calendar/src/cal/roc.rs index dc8ee844d1c..ac2666db693 100644 --- a/components/calendar/src/cal/roc.rs +++ b/components/calendar/src/cal/roc.rs @@ -54,12 +54,19 @@ impl GregorianYears for RocEra { } } - fn era_year_from_extended(&self, extended_year: i32, _month: u8, _day: u8) -> types::EraYear { + fn era_year_from_extended( + &self, + extended_year: i32, + related_iso: i32, + _month: u8, + _day: u8, + ) -> types::EraYear { if extended_year > 0 { types::EraYear { era: tinystr!(16, "roc"), era_index: Some(1), year: extended_year, + related_gregorian: related_iso, extended_year, ambiguity: types::YearAmbiguity::CenturyRequired, } @@ -68,6 +75,7 @@ impl GregorianYears for RocEra { era: tinystr!(16, "broc"), era_index: Some(0), year: 1 - extended_year, + related_gregorian: related_iso, extended_year, ambiguity: types::YearAmbiguity::EraAndCenturyRequired, } diff --git a/components/calendar/src/types.rs b/components/calendar/src/types.rs index 3bceb8fbe16..a0c3709143c 100644 --- a/components/calendar/src/types.rs +++ b/components/calendar/src/types.rs @@ -268,6 +268,27 @@ impl YearInfo { } } + /// The Gregorian year in which this year started. + /// + /// For Gregorian-based calendars ([`Buddhist`](crate::cal::Buddhist), [`Gregorian`](crate::cal::Gregorian), + /// [`Indian`](crate::cal::Indian), [`Iso`](crate::cal::Iso), [`Japanese`](crate::cal::Japanese), + /// [`JapaneseExtended`](crate::cal::JapaneseExtended), as well as the simple long-term implementations of + /// [`ChineseTraditional`](crate::cal::ChineseTraditional) and [`KoreanTraditional`](crate::cal::KoreanTraditional)), + /// this is just a fixed offset. + /// + /// Other solar and lunisolar calendars ([`Coptic`](crate::cal::Coptic), [`Ethiopian`](crate::cal::Ethiopian), + /// [`Hebrew`](crate::cal::Hebrew), [`Julian`](crate::cal::Julian), [`Persian`](crate::cal::Persian)) drift from the + /// Gregorian calendar and skip/repeat a related Gregorian year eventually. The earliest this happens is 16,703 CE. + /// + /// Lunar calendars, like [`Hijri`](crate::cal::Hijri), drift quickly through the Gregorian year, so related Gregorian + /// years are frequently repeated. + pub fn related_gregorian(self) -> i32 { + match self { + YearInfo::Era(e) => e.related_gregorian, + YearInfo::Cyclic(c) => c.related_iso, + } + } + /// Get the era year information, if available pub fn era(self) -> Option { match self { @@ -310,6 +331,8 @@ pub struct EraYear { pub year: i32, /// See [`YearInfo::extended_year()`] pub extended_year: i32, + /// See [`YearInfo::related_gregorian()`] + pub related_gregorian: i32, /// The era code as defined by CLDR, expect for cases where CLDR does not define a code. pub era: TinyAsciiStr<16>, /// An era index, for calendars with a small set of eras. @@ -329,7 +352,7 @@ pub struct EraYear { pub struct CyclicYear { /// The year in the cycle, 1-based pub year: u8, - /// The ISO year corresponding to this year + /// The Gregorian year corresponding to this year pub related_iso: i32, } diff --git a/components/datetime/src/format/datetime.rs b/components/datetime/src/format/datetime.rs index 7ea60e32c6a..edac90efba3 100644 --- a/components/datetime/src/format/datetime.rs +++ b/components/datetime/src/format/datetime.rs @@ -208,14 +208,13 @@ where } } } - (FieldSymbol::Year(Year::RelatedIso), l) => { + (FieldSymbol::Year(Year::RelatedGregorian), l) => { const PART: Part = parts::RELATED_YEAR; input!(PART, Year, year = input.year); - input!(PART, YearCyclic, cyclic = year.cyclic()); // Always in latin digits according to spec w.with_part(PART, |w| { - let mut num = Decimal::from(cyclic.related_iso); + let mut num = Decimal::from(year.related_gregorian()); num.pad_start(l.to_len() as i16); num.write_to(w) })?; diff --git a/components/datetime/src/pattern/names.rs b/components/datetime/src/pattern/names.rs index 5a0e2060391..541c48e07d4 100644 --- a/components/datetime/src/pattern/names.rs +++ b/components/datetime/src/pattern/names.rs @@ -3617,7 +3617,7 @@ impl RawDateTimeNames { // u+ (FS::Year(Year::Extended), _) => numeric_field = Some(field), // r+ - (FS::Year(Year::RelatedIso), _) => { + (FS::Year(Year::RelatedGregorian), _) => { // always formats as ASCII } diff --git a/components/datetime/src/provider/fields/symbols.rs b/components/datetime/src/provider/fields/symbols.rs index 837a2d81635..33f7e88af1a 100644 --- a/components/datetime/src/provider/fields/symbols.rs +++ b/components/datetime/src/provider/fields/symbols.rs @@ -279,7 +279,7 @@ impl FieldSymbol { // Self::Year(Year::WeekOf) => 2, Self::Year(Year::Extended) => 2, Self::Year(Year::Cyclic) => 3, - Self::Year(Year::RelatedIso) => 4, + Self::Year(Year::RelatedGregorian) => 4, Self::Month(Month::Format) => 5, Self::Month(Month::StandAlone) => 6, // TODO(#5643): Add week fields back @@ -506,8 +506,8 @@ field_type! ( 'y' => Calendar = 0, /// Field symbol for cyclic year; used in calendars where years are tracked in cycles, such as the Chinese or Dangi calendars. 'U' => Cyclic = 1, - /// Field symbol for related ISO; some calendars which use different year numbering than ISO, or no year numbering, may express years in an ISO year corresponding to a calendar year. - 'r' => RelatedIso = 2, + /// Field symbol for related Gregorian year. This corresponds to the extended Gregorian year in which the calendar’s year begins. + 'r' => RelatedGregorian = 2, /// Field symbol for extended year 'u' => Extended = 3, // /// Field symbol for year in "week of year". diff --git a/ffi/capi/bindings/c/Date.h b/ffi/capi/bindings/c/Date.h index f21db280d68..507a7df6d94 100644 --- a/ffi/capi/bindings/c/Date.h +++ b/ffi/capi/bindings/c/Date.h @@ -64,6 +64,8 @@ int32_t icu4x_Date_era_year_or_related_iso_mv1(const Date* self); int32_t icu4x_Date_extended_year_mv1(const Date* self); +int32_t icu4x_Date_related_gregorian_mv1(const Date* self); + void icu4x_Date_era_mv1(const Date* self, DiplomatWrite* write); uint8_t icu4x_Date_months_in_year_mv1(const Date* self); diff --git a/ffi/capi/bindings/cpp/icu4x/Date.d.hpp b/ffi/capi/bindings/cpp/icu4x/Date.d.hpp index c2a8e525584..451d73bb3fa 100644 --- a/ffi/capi/bindings/cpp/icu4x/Date.d.hpp +++ b/ffi/capi/bindings/cpp/icu4x/Date.d.hpp @@ -202,6 +202,11 @@ class Date { */ inline int32_t extended_year() const; + /** + * See the [Rust documentation for `related_gregorian`](https://docs.rs/icu/2.1.1/icu/calendar/types/enum.YearInfo.html#method.related_gregorian) for more information. + */ + inline int32_t related_gregorian() const; + /** * Returns the era for this date, or an empty string * diff --git a/ffi/capi/bindings/cpp/icu4x/Date.hpp b/ffi/capi/bindings/cpp/icu4x/Date.hpp index 7f5bf818734..b7303c6bec8 100644 --- a/ffi/capi/bindings/cpp/icu4x/Date.hpp +++ b/ffi/capi/bindings/cpp/icu4x/Date.hpp @@ -67,6 +67,8 @@ namespace capi { int32_t icu4x_Date_extended_year_mv1(const icu4x::capi::Date* self); + int32_t icu4x_Date_related_gregorian_mv1(const icu4x::capi::Date* self); + void icu4x_Date_era_mv1(const icu4x::capi::Date* self, icu4x::diplomat::capi::DiplomatWrite* write); uint8_t icu4x_Date_months_in_year_mv1(const icu4x::capi::Date* self); @@ -194,6 +196,11 @@ inline int32_t icu4x::Date::extended_year() const { return result; } +inline int32_t icu4x::Date::related_gregorian() const { + auto result = icu4x::capi::icu4x_Date_related_gregorian_mv1(this->AsFFI()); + return result; +} + inline std::string icu4x::Date::era() const { std::string output; icu4x::diplomat::capi::DiplomatWrite write = icu4x::diplomat::WriteFromString(output); diff --git a/ffi/capi/src/date.rs b/ffi/capi/src/date.rs index 630da9377cb..857b5b51b16 100644 --- a/ffi/capi/src/date.rs +++ b/ffi/capi/src/date.rs @@ -463,7 +463,13 @@ pub mod ffi { #[diplomat::rust_link(icu::calendar::types::YearInfo::extended_year, FnInEnum, hidden)] #[diplomat::attr(auto, getter)] pub fn extended_year(&self) -> i32 { - self.0.extended_year() + self.0.year().extended_year() + } + + #[diplomat::rust_link(icu::calendar::types::YearInfo::related_gregorian, FnInEnum)] + #[diplomat::attr(auto, getter)] + pub fn related_gregorian(&self) -> i32 { + self.0.year().related_gregorian() } /// Returns the era for this date, or an empty string diff --git a/ffi/dart/lib/src/bindings/Date.g.dart b/ffi/dart/lib/src/bindings/Date.g.dart index d443335be7a..b0b854cd6e0 100644 --- a/ffi/dart/lib/src/bindings/Date.g.dart +++ b/ffi/dart/lib/src/bindings/Date.g.dart @@ -229,6 +229,12 @@ final class Date implements ffi.Finalizable { return result; } + /// See the [Rust documentation for `related_gregorian`](https://docs.rs/icu/2.1.1/icu/calendar/types/enum.YearInfo.html#method.related_gregorian) for more information. + int get relatedGregorian { + final result = _icu4x_Date_related_gregorian_mv1(_ffi); + return result; + } + /// Returns the era for this date, or an empty string /// /// See the [Rust documentation for `era`](https://docs.rs/icu/2.1.1/icu/calendar/types/struct.EraYear.html#structfield.era) for more information. @@ -369,6 +375,11 @@ external int _icu4x_Date_era_year_or_related_iso_mv1(ffi.Pointer sel // ignore: non_constant_identifier_names external int _icu4x_Date_extended_year_mv1(ffi.Pointer self); +@_DiplomatFfiUse('icu4x_Date_related_gregorian_mv1') +@ffi.Native)>(isLeaf: true, symbol: 'icu4x_Date_related_gregorian_mv1') +// ignore: non_constant_identifier_names +external int _icu4x_Date_related_gregorian_mv1(ffi.Pointer self); + @_DiplomatFfiUse('icu4x_Date_era_mv1') @ffi.Native, ffi.Pointer)>(isLeaf: true, symbol: 'icu4x_Date_era_mv1') // ignore: non_constant_identifier_names diff --git a/ffi/mvn/src/main/kotlin/src/main/kotlin/org/unicode/icu4x/Date.kt b/ffi/mvn/src/main/kotlin/src/main/kotlin/org/unicode/icu4x/Date.kt index 526f4c1958f..4d8e252d3f9 100644 --- a/ffi/mvn/src/main/kotlin/src/main/kotlin/org/unicode/icu4x/Date.kt +++ b/ffi/mvn/src/main/kotlin/src/main/kotlin/org/unicode/icu4x/Date.kt @@ -24,6 +24,7 @@ internal interface DateLib: Library { fun icu4x_Date_month_is_leap_mv1(handle: Pointer): Byte fun icu4x_Date_era_year_or_related_iso_mv1(handle: Pointer): Int fun icu4x_Date_extended_year_mv1(handle: Pointer): Int + fun icu4x_Date_related_gregorian_mv1(handle: Pointer): Int fun icu4x_Date_era_mv1(handle: Pointer, write: Pointer): Unit fun icu4x_Date_months_in_year_mv1(handle: Pointer): FFIUint8 fun icu4x_Date_days_in_month_mv1(handle: Pointer): FFIUint8 @@ -301,6 +302,14 @@ class Date internal constructor ( return (returnVal) } + /** See the [Rust documentation for `related_gregorian`](https://docs.rs/icu/2.1.1/icu/calendar/types/enum.YearInfo.html#method.related_gregorian) for more information. + */ + fun relatedGregorian(): Int { + + val returnVal = lib.icu4x_Date_related_gregorian_mv1(handle); + return (returnVal) + } + /** Returns the era for this date, or an empty string * *See the [Rust documentation for `era`](https://docs.rs/icu/2.1.1/icu/calendar/types/struct.EraYear.html#structfield.era) for more information. diff --git a/ffi/mvn/src/main/kotlin/src/main/kotlin/org/unicode/icu4x/PropertyValueNameToEnumMapper.kt b/ffi/mvn/src/main/kotlin/src/main/kotlin/org/unicode/icu4x/PropertyValueNameToEnumMapper.kt index d5e9f9fe059..5c3b497e13e 100644 --- a/ffi/mvn/src/main/kotlin/src/main/kotlin/org/unicode/icu4x/PropertyValueNameToEnumMapper.kt +++ b/ffi/mvn/src/main/kotlin/src/main/kotlin/org/unicode/icu4x/PropertyValueNameToEnumMapper.kt @@ -35,6 +35,8 @@ internal interface PropertyValueNameToEnumMapperLib: Library { fun icu4x_PropertyValueNameToEnumMapper_create_vertical_orientation_with_provider_mv1(provider: Pointer): ResultPointerInt fun icu4x_PropertyValueNameToEnumMapper_create_joining_group_mv1(): Pointer fun icu4x_PropertyValueNameToEnumMapper_create_joining_group_with_provider_mv1(provider: Pointer): ResultPointerInt + fun icu4x_PropertyValueNameToEnumMapper_create_joining_type_mv1(): Pointer + fun icu4x_PropertyValueNameToEnumMapper_create_joining_type_with_provider_mv1(provider: Pointer): ResultPointerInt } /** A type capable of looking up a property value from a string name. * @@ -502,6 +504,40 @@ class PropertyValueNameToEnumMapper internal constructor ( return DataErrorError(DataError.fromNative(returnVal.union.err)).err() } } + @JvmStatic + + /** Create a name-to-enum mapper for the `JoiningType` property, using compiled data. + * + *See the [Rust documentation for `JoiningType`](https://docs.rs/icu/2.1.1/icu/properties/props/struct.JoiningType.html) for more information. + */ + fun createJoiningType(): PropertyValueNameToEnumMapper { + + val returnVal = lib.icu4x_PropertyValueNameToEnumMapper_create_joining_type_mv1(); + val selfEdges: List = listOf() + val handle = returnVal + val returnOpaque = PropertyValueNameToEnumMapper(handle, selfEdges) + CLEANER.register(returnOpaque, PropertyValueNameToEnumMapper.PropertyValueNameToEnumMapperCleaner(handle, PropertyValueNameToEnumMapper.lib)); + return returnOpaque + } + @JvmStatic + + /** Create a name-to-enum mapper for the `JoiningType` property, using a particular data source. + * + *See the [Rust documentation for `JoiningType`](https://docs.rs/icu/2.1.1/icu/properties/props/struct.JoiningType.html) for more information. + */ + fun createJoiningTypeWithProvider(provider: DataProvider): Result { + + val returnVal = lib.icu4x_PropertyValueNameToEnumMapper_create_joining_type_with_provider_mv1(provider.handle); + if (returnVal.isOk == 1.toByte()) { + val selfEdges: List = listOf() + val handle = returnVal.union.ok + val returnOpaque = PropertyValueNameToEnumMapper(handle, selfEdges) + CLEANER.register(returnOpaque, PropertyValueNameToEnumMapper.PropertyValueNameToEnumMapperCleaner(handle, PropertyValueNameToEnumMapper.lib)); + return returnOpaque.ok() + } else { + return DataErrorError(DataError.fromNative(returnVal.union.err)).err() + } + } } /** Get the property value matching the given name, using strict matching diff --git a/ffi/npm/lib/Date.d.ts b/ffi/npm/lib/Date.d.ts index c9a1efd6a0f..0a3ad35e5d4 100644 --- a/ffi/npm/lib/Date.d.ts +++ b/ffi/npm/lib/Date.d.ts @@ -182,6 +182,11 @@ export class Date { */ get extendedYear(): number; + /** + * See the [Rust documentation for `related_gregorian`](https://docs.rs/icu/2.1.1/icu/calendar/types/enum.YearInfo.html#method.related_gregorian) for more information. + */ + get relatedGregorian(): number; + /** * Returns the era for this date, or an empty string * diff --git a/ffi/npm/lib/Date.mjs b/ffi/npm/lib/Date.mjs index 97f4833127a..7178405054f 100644 --- a/ffi/npm/lib/Date.mjs +++ b/ffi/npm/lib/Date.mjs @@ -437,6 +437,21 @@ export class Date { } } + /** + * See the [Rust documentation for `related_gregorian`](https://docs.rs/icu/2.1.1/icu/calendar/types/enum.YearInfo.html#method.related_gregorian) for more information. + */ + get relatedGregorian() { + + const result = wasm.icu4x_Date_related_gregorian_mv1(this.ffiValue); + + try { + return result; + } + + finally { + } + } + /** * Returns the era for this date, or an empty string * diff --git a/tools/web-demo/gen/index.mjs b/tools/web-demo/gen/index.mjs index 8452b38fa16..984b7b5fc65 100644 --- a/tools/web-demo/gen/index.mjs +++ b/tools/web-demo/gen/index.mjs @@ -653,6 +653,41 @@ let termini = Object.assign({ ] }, + "Date.relatedGregorian": { + func: (selfIsoYear, selfIsoMonth, selfIsoDay, selfCalendarKind) => icu.Date.fromIsoInCalendar(selfIsoYear, selfIsoMonth, selfIsoDay, new icu.Calendar(selfCalendarKind)).relatedGregorian, + // For avoiding webpacking minifying issues: + funcName: "Date.relatedGregorian", + expr: (selfIsoYear, selfIsoMonth, selfIsoDay, selfCalendarKind) => "icu.Date.fromIsoInCalendar(selfIsoYear, selfIsoMonth, selfIsoDay, new icu.Calendar(selfCalendarKind)).relatedGregorian".replace(/([\( ])selfIsoYear([,\) \n])/, '$1' + selfIsoYear + '$2').replace(/([\( ])selfIsoMonth([,\) \n])/, '$1' + selfIsoMonth + '$2').replace(/([\( ])selfIsoDay([,\) \n])/, '$1' + selfIsoDay + '$2').replace(/([\( ])selfCalendarKind([,\) \n])/, '$1' + selfCalendarKind + '$2'), + parameters: [ + + { + name: "self_isoYear", + type: "number", + typeUse: "number" + }, + + { + name: "self_isoMonth", + type: "number", + typeUse: "number" + }, + + { + name: "self_isoDay", + type: "number", + typeUse: "number" + }, + + { + name: "self_calendar_kind", + type: "CalendarKind", + typeUse: "enumerator", + values: ["Iso", "Gregorian", "Buddhist", "Japanese", "JapaneseExtended", "Ethiopian", "EthiopianAmeteAlem", "Indian", "Coptic", "Dangi", "Chinese", "Hebrew", "HijriTabularTypeIIFriday", "HijriSimulatedMecca", "HijriTabularTypeIIThursday", "HijriUmmAlQura", "Persian", "Roc"] + } + + ] + }, + "Date.era": { func: (selfIsoYear, selfIsoMonth, selfIsoDay, selfCalendarKind) => icu.Date.fromIsoInCalendar(selfIsoYear, selfIsoMonth, selfIsoDay, new icu.Calendar(selfCalendarKind)).era, // For avoiding webpacking minifying issues: