diff --git a/components/calendar/src/any_calendar.rs b/components/calendar/src/any_calendar.rs index a04d14f1a22..ff76853aee2 100644 --- a/components/calendar/src/any_calendar.rs +++ b/components/calendar/src/any_calendar.rs @@ -508,11 +508,12 @@ impl Calendar for AnyCalendar { } } - /// The calendar-specific year represented by `date` - fn year(&self, date: &Self::DateInner) -> types::FormattableYear { + fn year(&self, date: &Self::DateInner) -> types::YearInfo { match_cal_and_date!(match (self, date): (c, d) => c.year(d)) } - + fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear { + match_cal_and_date!(match (self, date): (c, d) => c.formattable_year(d)) + } /// The calendar-specific check if `date` is in a leap year fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { match_cal_and_date!(match (self, date): (c, d) => c.is_in_leap_year(d)) diff --git a/components/calendar/src/buddhist.rs b/components/calendar/src/buddhist.rs index 1b86bdcd714..a0eafad7f4b 100644 --- a/components/calendar/src/buddhist.rs +++ b/components/calendar/src/buddhist.rs @@ -119,10 +119,15 @@ impl Calendar for Buddhist { } /// The calendar-specific year represented by `date` - fn year(&self, date: &Self::DateInner) -> types::FormattableYear { + fn year(&self, date: &Self::DateInner) -> types::YearInfo { iso_year_as_buddhist(date.0.year) } + /// The calendar-specific year represented by `date` + fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear { + iso_year_as_buddhist(date.0.year).into() + } + fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { Iso.is_in_leap_year(date) } @@ -144,9 +149,9 @@ impl Calendar for Buddhist { types::DayOfYearInfo { day_of_year: Iso::day_of_year(*date), days_in_year: Iso::days_in_year_direct(date.0.year), - prev_year: iso_year_as_buddhist(prev_year), + prev_year: iso_year_as_buddhist(prev_year).into(), days_in_prev_year: Iso::days_in_year_direct(prev_year), - next_year: iso_year_as_buddhist(next_year), + next_year: iso_year_as_buddhist(next_year).into(), } } @@ -218,14 +223,9 @@ impl DateTime { } } -fn iso_year_as_buddhist(year: i32) -> types::FormattableYear { +fn iso_year_as_buddhist(year: i32) -> types::YearInfo { let buddhist_year = year + BUDDHIST_ERA_OFFSET; - types::FormattableYear { - era: types::Era(tinystr!(16, "be")), - number: buddhist_year, - cyclic: None, - related_iso: None, - } + types::YearInfo::new(buddhist_year, tinystr!(16, "be"), buddhist_year) } #[cfg(test)] diff --git a/components/calendar/src/calendar.rs b/components/calendar/src/calendar.rs index 487f3e9f4bb..4c182cdb866 100644 --- a/components/calendar/src/calendar.rs +++ b/components/calendar/src/calendar.rs @@ -73,8 +73,11 @@ pub trait Calendar { fn debug_name(&self) -> &'static str; // fn since(&self, from: &Date, to: &Date) -> Duration, Error; - /// The calendar-specific year represented by `date` - fn year(&self, date: &Self::DateInner) -> types::FormattableYear; + /// Information about the year + fn year(&self, date: &Self::DateInner) -> types::YearInfo; + + /// Information about the calendar-specific year as needed for formatting + fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear; /// Calculate if a date is in a leap year fn is_in_leap_year(&self, date: &Self::DateInner) -> bool; diff --git a/components/calendar/src/chinese.rs b/components/calendar/src/chinese.rs index 1f34c9a0417..82d8ee02a23 100644 --- a/components/calendar/src/chinese.rs +++ b/components/calendar/src/chinese.rs @@ -23,15 +23,13 @@ //! //! // `Date` checks //! assert_eq!(chinese_date.year().number, 4660); -//! assert_eq!(chinese_date.year().related_iso, Some(2023)); -//! assert_eq!(chinese_date.year().cyclic.unwrap().get(), 40); +//! assert_eq!(chinese_date.formattable_year().cyclic().unwrap().get(), 40); //! assert_eq!(chinese_date.month().ordinal, 6); //! assert_eq!(chinese_date.day_of_month().0, 6); //! //! // `DateTime` checks //! assert_eq!(chinese_datetime.date.year().number, 4660); -//! assert_eq!(chinese_datetime.date.year().related_iso, Some(2023)); -//! assert_eq!(chinese_datetime.date.year().cyclic.unwrap().get(), 40); +//! assert_eq!(chinese_datetime.date.formattable_year().cyclic().unwrap().get(), 40); //! assert_eq!(chinese_datetime.date.month().ordinal, 6); //! assert_eq!(chinese_datetime.date.day_of_month().0, 6); //! assert_eq!(chinese_datetime.time.hour.number(), 13); @@ -48,7 +46,7 @@ use crate::chinese_based::{ use crate::error::DateError; use crate::iso::Iso; use crate::provider::chinese_based::ChineseCacheV1Marker; -use crate::types::{Era, FormattableYear}; +use crate::types::FormattableYear; use crate::AsCalendar; use crate::{types, Calendar, Date, DateDuration, DateDurationUnit, DateTime, Time}; use core::cmp::Ordering; @@ -268,8 +266,11 @@ impl Calendar for Chinese { Self::DEBUG_NAME } - /// The calendar-specific year represented by `date` - fn year(&self, date: &Self::DateInner) -> types::FormattableYear { + fn year(&self, date: &Self::DateInner) -> types::YearInfo { + types::YearInfo::new(date.0 .0.year, tinystr!(16, "chinese"), date.0 .0.year) + } + + fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear { Self::format_chinese_year(date.0 .0.year, Some(date.0 .0.year_info)) } @@ -331,8 +332,8 @@ impl> Date { /// .expect("Failed to initialize Chinese Date instance."); /// /// assert_eq!(date_chinese.year().number, 4660); - /// assert_eq!(date_chinese.year().cyclic.unwrap().get(), 40); - /// assert_eq!(date_chinese.year().related_iso, Some(2023)); + /// assert_eq!(date_chinese.formattable_year().cyclic().unwrap().get(), 40); + /// assert_eq!(date_chinese.formattable_year().related_iso(), Some(2023)); /// assert_eq!(date_chinese.month().ordinal, 6); /// assert_eq!(date_chinese.day_of_month().0, 11); /// ``` @@ -372,8 +373,7 @@ impl> DateTime { /// .expect("Failed to initialize Chinese DateTime instance."); /// /// assert_eq!(chinese_datetime.date.year().number, 4660); - /// assert_eq!(chinese_datetime.date.year().related_iso, Some(2023)); - /// assert_eq!(chinese_datetime.date.year().cyclic.unwrap().get(), 40); + /// assert_eq!(chinese_datetime.date.formattable_year().cyclic().unwrap().get(), 40); /// assert_eq!(chinese_datetime.date.month().ordinal, 6); /// assert_eq!(chinese_datetime.date.day_of_month().0, 11); /// assert_eq!(chinese_datetime.time.hour.number(), 13); @@ -407,32 +407,20 @@ impl ChineseBasedWithDataLoading for Chinese { impl Chinese { /// Get a FormattableYear from an integer Chinese year; optionally, a `ChineseBasedYearInfo` /// can be passed in for faster results. - /// - /// `era` is always `Era(tinystr!(16, "chinese"))` - /// `number` is the year since the inception of the Chinese calendar (see [`Chinese`]) - /// `cyclic` is an option with the current year in the sexagesimal cycle (see [`Chinese`]) - /// `related_iso` is the ISO year in which the given Chinese year begins (see [`Chinese`]) fn format_chinese_year( year: i32, year_info_option: Option, ) -> FormattableYear { - let era = Era(tinystr!(16, "chinese")); - let number = year; - let cyclic = (number - 1).rem_euclid(60) as u8; - let cyclic = NonZeroU8::new(cyclic + 1); // 1-indexed + let cyclic = (year - 1).rem_euclid(60) as u8; + let cyclic = NonZeroU8::new(cyclic + 1).unwrap_or(NonZeroU8::MIN); // 1-indexed let rata_die_in_year = if let Some(info) = year_info_option { info.new_year::(year) } else { - Inner::fixed_mid_year_from_year(number) + Inner::fixed_mid_year_from_year(year) }; let iso_formattable_year = Iso::iso_from_fixed(rata_die_in_year).year(); - let related_iso = Some(iso_formattable_year.number); - types::FormattableYear { - era, - number, - cyclic, - related_iso, - } + let related_iso = iso_formattable_year.number; + types::FormattableYear::new_cyclic(year, cyclic, related_iso) } } @@ -666,8 +654,8 @@ mod test { assert_eq!(chinese.month().ordinal, 1); assert_eq!(chinese.month().code.0, "M01"); assert_eq!(chinese.day_of_month().0, 1); - assert_eq!(chinese.year().cyclic.unwrap().get(), 1); - assert_eq!(chinese.year().related_iso, Some(-2636)); + assert_eq!(chinese.formattable_year().cyclic().unwrap().get(), 1); + assert_eq!(chinese.formattable_year().related_iso(), Some(-2636)); }, ) } @@ -1113,8 +1101,8 @@ mod test { &chinese_cached, |chinese, calendar_type| { let chinese = iso.to_calendar(chinese); - let chinese_rel_iso = chinese.year().related_iso; - let chinese_cyclic = chinese.year().cyclic; + let chinese_rel_iso = chinese.formattable_year().related_iso(); + let chinese_cyclic = chinese.formattable_year().cyclic(); let chinese_month = chinese.month().ordinal; let chinese_day = chinese.day_of_month().0; diff --git a/components/calendar/src/chinese_based.rs b/components/calendar/src/chinese_based.rs index 815170de72c..1c5f6cf0968 100644 --- a/components/calendar/src/chinese_based.rs +++ b/components/calendar/src/chinese_based.rs @@ -12,8 +12,7 @@ //! let chinese_date = Date::new_from_iso(iso_date, Chinese::new()); //! //! assert_eq!(chinese_date.year().number, 4660); -//! assert_eq!(chinese_date.year().related_iso, Some(2023)); -//! assert_eq!(chinese_date.year().cyclic.unwrap().get(), 40); +//! assert_eq!(chinese_date.formattable_year().cyclic().unwrap().get(), 40); //! assert_eq!(chinese_date.month().ordinal, 6); //! assert_eq!(chinese_date.day_of_month().0, 6); //! ``` diff --git a/components/calendar/src/coptic.rs b/components/calendar/src/coptic.rs index 66ab35a4553..ef0c671dfbc 100644 --- a/components/calendar/src/coptic.rs +++ b/components/calendar/src/coptic.rs @@ -184,10 +184,14 @@ impl Calendar for Coptic { date1.0.until(date2.0, _largest_unit, _smallest_unit) } - fn year(&self, date: &Self::DateInner) -> types::FormattableYear { + fn year(&self, date: &Self::DateInner) -> types::YearInfo { year_as_coptic(date.0.year) } + fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear { + year_as_coptic(date.0.year).into() + } + fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { Self::is_leap_year(date.0.year, ()) } @@ -206,9 +210,9 @@ impl Calendar for Coptic { types::DayOfYearInfo { day_of_year: date.0.day_of_year(), days_in_year: date.0.days_in_year(), - prev_year: year_as_coptic(prev_year), + prev_year: year_as_coptic(prev_year).into(), days_in_prev_year: Coptic::days_in_year_direct(prev_year), - next_year: year_as_coptic(next_year), + next_year: year_as_coptic(next_year).into(), } } @@ -301,24 +305,13 @@ impl DateTime { } } -fn year_as_coptic(year: i32) -> types::FormattableYear { +fn year_as_coptic(year: i32) -> types::YearInfo { if year > 0 { - types::FormattableYear { - era: types::Era(tinystr!(16, "ad")), - number: year, - cyclic: None, - related_iso: None, - } + types::YearInfo::new(year, tinystr!(16, "ad"), year) } else { - types::FormattableYear { - era: types::Era(tinystr!(16, "bd")), - number: 1 - year, - cyclic: None, - related_iso: None, - } + types::YearInfo::new(year, tinystr!(16, "bd"), 1 - year) } } - #[cfg(test)] mod tests { use super::*; diff --git a/components/calendar/src/dangi.rs b/components/calendar/src/dangi.rs index 97c8f3c1b69..c26081054ca 100644 --- a/components/calendar/src/dangi.rs +++ b/components/calendar/src/dangi.rs @@ -23,15 +23,13 @@ //! //! // `Date` checks //! assert_eq!(dangi_date.year().number, 4356); -//! assert_eq!(dangi_date.year().related_iso, Some(2023)); -//! assert_eq!(dangi_date.year().cyclic.unwrap().get(), 40); +//! assert_eq!(dangi_date.formattable_year().cyclic().unwrap().get(), 40); //! assert_eq!(dangi_date.month().ordinal, 6); //! assert_eq!(dangi_date.day_of_month().0, 6); //! //! // `DateTime` checks //! assert_eq!(dangi_datetime.date.year().number, 4356); -//! assert_eq!(dangi_datetime.date.year().related_iso, Some(2023)); -//! assert_eq!(dangi_datetime.date.year().cyclic.unwrap().get(), 40); +//! assert_eq!(dangi_datetime.date.formattable_year().cyclic().unwrap().get(), 40); //! assert_eq!(dangi_datetime.date.month().ordinal, 6); //! assert_eq!(dangi_datetime.date.day_of_month().0, 6); //! assert_eq!(dangi_datetime.time.hour.number(), 13); @@ -50,7 +48,7 @@ use crate::provider::chinese_based::DangiCacheV1Marker; use crate::AsCalendar; use crate::{ chinese_based::ChineseBasedDateInner, - types::{self, Era, FormattableYear}, + types::{self, FormattableYear}, Calendar, Date, DateTime, Iso, Time, }; use core::cmp::Ordering; @@ -252,7 +250,10 @@ impl Calendar for Dangi { Self::DEBUG_NAME } - fn year(&self, date: &Self::DateInner) -> crate::types::FormattableYear { + fn year(&self, date: &Self::DateInner) -> crate::types::YearInfo { + types::YearInfo::new(date.0 .0.year, tinystr!(16, "dangi"), date.0 .0.year) + } + fn formattable_year(&self, date: &Self::DateInner) -> crate::types::FormattableYear { Self::format_dangi_year(date.0 .0.year, Some(date.0 .0.year_info)) } @@ -308,8 +309,7 @@ impl> Date { /// .expect("Failed to initialize Dangi Date instance."); /// /// assert_eq!(date_dangi.year().number, 4356); - /// assert_eq!(date_dangi.year().cyclic.unwrap().get(), 40); - /// assert_eq!(date_dangi.year().related_iso, Some(2023)); + /// assert_eq!(date_dangi.formattable_year().cyclic().unwrap().get(), 40); /// assert_eq!(date_dangi.month().ordinal, 6); /// assert_eq!(date_dangi.day_of_month().0, 18); /// ``` @@ -349,8 +349,7 @@ impl> DateTime { /// .expect("Failed to initialize Dangi DateTime instance."); /// /// assert_eq!(dangi_datetime.date.year().number, 4356); - /// assert_eq!(dangi_datetime.date.year().related_iso, Some(2023)); - /// assert_eq!(dangi_datetime.date.year().cyclic.unwrap().get(), 40); + /// assert_eq!(dangi_datetime.date.formattable_year().cyclic().unwrap().get(), 40); /// assert_eq!(dangi_datetime.date.month().ordinal, 6); /// assert_eq!(dangi_datetime.date.day_of_month().0, 6); /// assert_eq!(dangi_datetime.time.hour.number(), 13); @@ -388,24 +387,17 @@ impl Dangi { year: i32, year_info_option: Option, ) -> FormattableYear { - let era = Era(tinystr!(16, "dangi")); - let number = year; // constant 364 from https://github.com/EdReingold/calendar-code2/blob/main/calendar.l#L5704 - let cyclic = (number as i64 - 1 + 364).rem_euclid(60) as u8; - let cyclic = NonZeroU8::new(cyclic + 1); // 1-indexed + let cyclic = (year as i64 - 1 + 364).rem_euclid(60) as u8; + let cyclic = NonZeroU8::new(cyclic + 1).unwrap_or(NonZeroU8::MIN); // 1-indexed let rata_die_in_year = if let Some(info) = year_info_option { info.new_year::(year) } else { - Inner::fixed_mid_year_from_year(number) + Inner::fixed_mid_year_from_year(year) }; let iso_formattable_year = Iso::iso_from_fixed(rata_die_in_year).year(); - let related_iso = Some(iso_formattable_year.number); - types::FormattableYear { - era, - number, - cyclic, - related_iso, - } + let related_iso = iso_formattable_year.number; + types::FormattableYear::new_cyclic(year, cyclic, related_iso) } } @@ -430,14 +422,14 @@ mod test { let iso = Date::try_new_iso_date(year, 6, 6).unwrap(); let chinese = iso.to_calendar(Chinese::new_always_calculating()); let dangi = iso.to_calendar(Dangi::new_always_calculating()); - let chinese_year = chinese.year().cyclic; - let korean_year = dangi.year().cyclic; + let chinese_year = chinese.formattable_year().cyclic(); + let korean_year = dangi.formattable_year().cyclic(); assert_eq!( chinese_year, korean_year, "Cyclic year failed for year: {year}" ); - let chinese_rel_iso = chinese.year().related_iso; - let korean_rel_iso = dangi.year().related_iso; + let chinese_rel_iso = chinese.formattable_year().related_iso(); + let korean_rel_iso = dangi.formattable_year().related_iso(); assert_eq!( chinese_rel_iso, korean_rel_iso, "Rel. ISO year equality failed for year: {year}" @@ -998,8 +990,8 @@ mod test { let iso = Date::try_new_iso_date(case.iso_year, case.iso_month, case.iso_day).unwrap(); do_twice(&dangi_calculating, &dangi_cached, |dangi, calendar_type| { let dangi = iso.to_calendar(dangi); - let dangi_rel_iso = dangi.year().related_iso; - let dangi_cyclic = dangi.year().cyclic; + let dangi_rel_iso = dangi.formattable_year().related_iso(); + let dangi_cyclic = dangi.formattable_year().cyclic(); let dangi_month = dangi.month().ordinal; let dangi_day = dangi.day_of_month().0; diff --git a/components/calendar/src/date.rs b/components/calendar/src/date.rs index 51d8a2a7d31..6e3acc110b1 100644 --- a/components/calendar/src/date.rs +++ b/components/calendar/src/date.rs @@ -205,10 +205,17 @@ impl Date { /// The calendar-specific year represented by `self` #[inline] - pub fn year(&self) -> types::FormattableYear { + pub fn year(&self) -> types::YearInfo { self.calendar.as_calendar().year(&self.inner) } + /// The calendar-specific year represented by `self`, with information needed + /// for formatting + #[inline] + pub fn formattable_year(&self) -> types::FormattableYear { + self.calendar.as_calendar().formattable_year(&self.inner) + } + /// Returns whether `self` is in a calendar-specific leap year #[inline] pub fn is_in_leap_year(&self) -> bool { diff --git a/components/calendar/src/ethiopian.rs b/components/calendar/src/ethiopian.rs index 7aeaffa84c7..1ac2c9b6e87 100644 --- a/components/calendar/src/ethiopian.rs +++ b/components/calendar/src/ethiopian.rs @@ -206,9 +206,12 @@ impl Calendar for Ethiopian { date1.0.until(date2.0, _largest_unit, _smallest_unit) } - fn year(&self, date: &Self::DateInner) -> types::FormattableYear { + fn year(&self, date: &Self::DateInner) -> types::YearInfo { Self::year_as_ethiopian(date.0.year, self.0) } + fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear { + Self::year_as_ethiopian(date.0.year, self.0).into() + } fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { Self::is_leap_year(date.0.year, ()) @@ -228,9 +231,9 @@ impl Calendar for Ethiopian { types::DayOfYearInfo { day_of_year: date.0.day_of_year(), days_in_year: date.0.days_in_year(), - prev_year: Self::year_as_ethiopian(prev_year, self.0), + prev_year: Self::year_as_ethiopian(prev_year, self.0).into(), days_in_prev_year: Ethiopian::days_in_year_direct(prev_year), - next_year: Self::year_as_ethiopian(next_year, self.0), + next_year: Self::year_as_ethiopian(next_year, self.0).into(), } } @@ -291,29 +294,13 @@ impl Ethiopian { 365 } } - - fn year_as_ethiopian(year: i32, amete_alem: bool) -> types::FormattableYear { + fn year_as_ethiopian(year: i32, amete_alem: bool) -> types::YearInfo { if amete_alem { - types::FormattableYear { - era: types::Era(tinystr!(16, "mundi")), - number: year + AMETE_ALEM_OFFSET, - cyclic: None, - related_iso: None, - } + types::YearInfo::new(year, tinystr!(16, "mundi"), year + AMETE_ALEM_OFFSET) } else if year > 0 { - types::FormattableYear { - era: types::Era(tinystr!(16, "incar")), - number: year, - cyclic: None, - related_iso: None, - } + types::YearInfo::new(year, tinystr!(16, "incar"), year) } else { - types::FormattableYear { - era: types::Era(tinystr!(16, "pre-incar")), - number: 1 - year, - cyclic: None, - related_iso: None, - } + types::YearInfo::new(year, tinystr!(16, "pre-incar"), 1 - year) } } } diff --git a/components/calendar/src/gregorian.rs b/components/calendar/src/gregorian.rs index ed11979d95f..1ddede08fae 100644 --- a/components/calendar/src/gregorian.rs +++ b/components/calendar/src/gregorian.rs @@ -130,12 +130,16 @@ impl Calendar for Gregorian { Iso.until(&date1.0, &date2.0, &Iso, largest_unit, smallest_unit) .cast_unit() } - /// The calendar-specific year represented by `date` - fn year(&self, date: &Self::DateInner) -> types::FormattableYear { + fn year(&self, date: &Self::DateInner) -> types::YearInfo { year_as_gregorian(date.0 .0.year) } + /// The calendar-specific year represented by `date` + fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear { + year_as_gregorian(date.0 .0.year).into() + } + fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { Iso.is_in_leap_year(&date.0) } @@ -157,9 +161,9 @@ impl Calendar for Gregorian { types::DayOfYearInfo { day_of_year: Iso::day_of_year(date.0), days_in_year: Iso::days_in_year_direct(date.0 .0.year), - prev_year: year_as_gregorian(prev_year), + prev_year: year_as_gregorian(prev_year).into(), days_in_prev_year: Iso::days_in_year_direct(prev_year), - next_year: year_as_gregorian(next_year), + next_year: year_as_gregorian(next_year).into(), } } @@ -231,21 +235,11 @@ impl DateTime { } } -pub(crate) fn year_as_gregorian(year: i32) -> types::FormattableYear { +pub(crate) fn year_as_gregorian(year: i32) -> types::YearInfo { if year > 0 { - types::FormattableYear { - era: types::Era(tinystr!(16, "ce")), - number: year, - cyclic: None, - related_iso: None, - } + types::YearInfo::new(year, tinystr!(16, "ce"), year) } else { - types::FormattableYear { - era: types::Era(tinystr!(16, "bce")), - number: 1_i32.saturating_sub(year), - cyclic: None, - related_iso: None, - } + types::YearInfo::new(year, tinystr!(16, "bce"), 1_i32.saturating_sub(year)) } } @@ -345,14 +339,14 @@ mod test { assert_eq!( Calendar::day_of_year_info(&Gregorian, &date.inner) .next_year - .number, + .era_year_or_extended(), case.next_era_year, "{case:?}", ); assert_eq!( Calendar::day_of_year_info(&Gregorian, &date.inner) .next_year - .era + .era_or_unknown() .0, case.era, "{case:?}", @@ -553,14 +547,14 @@ mod test { assert_eq!( Calendar::day_of_year_info(&Gregorian, &date.inner) .prev_year - .number, + .era_year_or_extended(), case.prev_era_year, "{case:?}", ); assert_eq!( Calendar::day_of_year_info(&Gregorian, &date.inner) .prev_year - .era + .era_or_unknown() .0, case.era, "{case:?}", diff --git a/components/calendar/src/hebrew.rs b/components/calendar/src/hebrew.rs index be21a745386..84905454ecc 100644 --- a/components/calendar/src/hebrew.rs +++ b/components/calendar/src/hebrew.rs @@ -259,10 +259,14 @@ impl Calendar for Hebrew { "Hebrew" } - fn year(&self, date: &Self::DateInner) -> types::FormattableYear { + fn year(&self, date: &Self::DateInner) -> types::YearInfo { Self::year_as_hebrew(date.0.year) } + fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear { + Self::year_as_hebrew(date.0.year).into() + } + fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { Self::is_leap_year(date.0.year, date.0.year_info) } @@ -321,9 +325,9 @@ impl Calendar for Hebrew { types::DayOfYearInfo { day_of_year: date.0.day_of_year(), days_in_year: date.0.days_in_year(), - prev_year: Self::year_as_hebrew(prev_year), + prev_year: Self::year_as_hebrew(prev_year).into(), days_in_prev_year: date.0.year_info.prev_keviyah.year_length(), - next_year: Self::year_as_hebrew(next_year), + next_year: Self::year_as_hebrew(next_year).into(), } } @@ -333,13 +337,8 @@ impl Calendar for Hebrew { } impl Hebrew { - fn year_as_hebrew(civil_year: i32) -> types::FormattableYear { - types::FormattableYear { - era: types::Era(tinystr!(16, "hebrew")), - number: civil_year, - cyclic: None, - related_iso: None, - } + fn year_as_hebrew(civil_year: i32) -> types::YearInfo { + types::YearInfo::new(civil_year, tinystr!(16, "hebrew"), civil_year) } } diff --git a/components/calendar/src/indian.rs b/components/calendar/src/indian.rs index 7c24fb92008..f16a543bef6 100644 --- a/components/calendar/src/indian.rs +++ b/components/calendar/src/indian.rs @@ -193,13 +193,12 @@ impl Calendar for Indian { date1.0.until(date2.0, _largest_unit, _smallest_unit) } - fn year(&self, date: &Self::DateInner) -> types::FormattableYear { - types::FormattableYear { - era: types::Era(tinystr!(16, "saka")), - number: date.0.year, - cyclic: None, - related_iso: None, - } + fn year(&self, date: &Self::DateInner) -> types::YearInfo { + types::YearInfo::new(date.0.year, tinystr!(16, "saka"), date.0.year) + } + + fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear { + self.year(date).into() } fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { @@ -215,18 +214,11 @@ impl Calendar for Indian { } fn day_of_year_info(&self, date: &Self::DateInner) -> types::DayOfYearInfo { - let prev_year = types::FormattableYear { - era: types::Era(tinystr!(16, "saka")), - number: date.0.year - 1, - cyclic: None, - related_iso: None, - }; - let next_year = types::FormattableYear { - era: types::Era(tinystr!(16, "saka")), - number: date.0.year + 1, - cyclic: None, - related_iso: None, - }; + let prev_year = + types::FormattableYear::new_era(date.0.year - 1, tinystr!(16, "saka"), date.0.year - 1); + let next_year = + types::FormattableYear::new_era(date.0.year + 1, tinystr!(16, "saka"), date.0.year + 1); + types::DayOfYearInfo { day_of_year: date.0.day_of_year(), days_in_year: date.0.days_in_year(), diff --git a/components/calendar/src/islamic.rs b/components/calendar/src/islamic.rs index 620e23fe96e..04a472ad753 100644 --- a/components/calendar/src/islamic.rs +++ b/components/calendar/src/islamic.rs @@ -54,6 +54,10 @@ use core::marker::PhantomData; use icu_provider::prelude::*; use tinystr::tinystr; +fn year_as_islamic(year: i32) -> types::YearInfo { + types::YearInfo::new(year, tinystr!(16, "islamic"), year) +} + /// Islamic Observational Calendar (Default) /// /// # Era codes @@ -505,8 +509,11 @@ impl Calendar for IslamicObservational { Self::DEBUG_NAME } - fn year(&self, date: &Self::DateInner) -> types::FormattableYear { - Self::year_as_islamic(date.0.year) + fn year(&self, date: &Self::DateInner) -> types::YearInfo { + year_as_islamic(date.0.year) + } + fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear { + year_as_islamic(date.0.year).into() } fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { @@ -527,9 +534,9 @@ impl Calendar for IslamicObservational { types::DayOfYearInfo { day_of_year: date.0.day_of_year(), days_in_year: date.0.days_in_year(), - prev_year: Self::year_as_islamic(prev_year), + prev_year: year_as_islamic(prev_year).into(), days_in_prev_year: date.0.year_info.days_in_prev_year(), - next_year: Self::year_as_islamic(next_year), + next_year: year_as_islamic(next_year).into(), } } @@ -543,14 +550,6 @@ impl IslamicObservational { IslamicPrecomputedData::new(self.data.as_ref().map(|x| x.get())) } - fn year_as_islamic(year: i32) -> types::FormattableYear { - types::FormattableYear { - era: types::Era(tinystr!(16, "islamic")), - number: year, - cyclic: None, - related_iso: None, - } - } pub(crate) const DEBUG_NAME: &'static str = "Islamic (observational)"; } @@ -738,8 +737,11 @@ impl Calendar for IslamicUmmAlQura { Self::DEBUG_NAME } - fn year(&self, date: &Self::DateInner) -> types::FormattableYear { - Self::year_as_islamic(date.0.year) + fn year(&self, date: &Self::DateInner) -> types::YearInfo { + year_as_islamic(date.0.year) + } + fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear { + year_as_islamic(date.0.year).into() } fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { @@ -760,9 +762,9 @@ impl Calendar for IslamicUmmAlQura { types::DayOfYearInfo { day_of_year: date.0.day_of_year(), days_in_year: date.0.days_in_year(), - prev_year: Self::year_as_islamic(prev_year), + prev_year: year_as_islamic(prev_year).into(), days_in_prev_year: date.0.year_info.days_in_prev_year(), - next_year: Self::year_as_islamic(next_year), + next_year: year_as_islamic(next_year).into(), } } @@ -776,14 +778,6 @@ impl IslamicUmmAlQura { IslamicPrecomputedData::new(self.data.as_ref().map(|x| x.get())) } - fn year_as_islamic(year: i32) -> types::FormattableYear { - types::FormattableYear { - era: types::Era(tinystr!(16, "islamic")), - number: year, - cyclic: None, - related_iso: None, - } - } pub(crate) const DEBUG_NAME: &'static str = "Islamic (Umm al-Qura)"; } @@ -972,8 +966,11 @@ impl Calendar for IslamicCivil { "Islamic (civil)" } - fn year(&self, date: &Self::DateInner) -> types::FormattableYear { - Self::year_as_islamic(date.0.year) + fn year(&self, date: &Self::DateInner) -> types::YearInfo { + year_as_islamic(date.0.year) + } + fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear { + year_as_islamic(date.0.year).into() } fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { @@ -994,9 +991,9 @@ impl Calendar for IslamicCivil { types::DayOfYearInfo { day_of_year: date.0.day_of_year(), days_in_year: date.0.days_in_year(), - prev_year: Self::year_as_islamic(prev_year), + prev_year: year_as_islamic(prev_year).into(), days_in_prev_year: Self::days_in_provided_year(prev_year, ()), - next_year: Self::year_as_islamic(next_year), + next_year: year_as_islamic(next_year).into(), } } @@ -1025,15 +1022,6 @@ impl IslamicCivil { IslamicCivil, ) } - - fn year_as_islamic(year: i32) -> types::FormattableYear { - types::FormattableYear { - era: types::Era(tinystr!(16, "islamic")), - number: year, - cyclic: None, - related_iso: None, - } - } } impl> Date { @@ -1215,8 +1203,11 @@ impl Calendar for IslamicTabular { "Islamic (tabular)" } - fn year(&self, date: &Self::DateInner) -> types::FormattableYear { - Self::year_as_islamic(date.0.year) + fn year(&self, date: &Self::DateInner) -> types::YearInfo { + year_as_islamic(date.0.year) + } + fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear { + year_as_islamic(date.0.year).into() } fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { @@ -1237,9 +1228,9 @@ impl Calendar for IslamicTabular { types::DayOfYearInfo { day_of_year: date.0.day_of_year(), days_in_year: date.0.days_in_year(), - prev_year: Self::year_as_islamic(prev_year), + prev_year: year_as_islamic(prev_year).into(), days_in_prev_year: Self::days_in_provided_year(prev_year, ()), - next_year: Self::year_as_islamic(next_year), + next_year: year_as_islamic(next_year).into(), } } @@ -1268,15 +1259,6 @@ impl IslamicTabular { IslamicTabular, ) } - - fn year_as_islamic(year: i32) -> types::FormattableYear { - types::FormattableYear { - era: types::Era(tinystr!(16, "islamic")), - number: year, - cyclic: None, - related_iso: None, - } - } } impl> Date { diff --git a/components/calendar/src/iso.rs b/components/calendar/src/iso.rs index 384b2af0b89..bf5e9479a72 100644 --- a/components/calendar/src/iso.rs +++ b/components/calendar/src/iso.rs @@ -193,11 +193,13 @@ impl Calendar for Iso { date1.0.until(date2.0, _largest_unit, _smallest_unit) } - /// The calendar-specific year represented by `date` - fn year(&self, date: &Self::DateInner) -> types::FormattableYear { + fn year(&self, date: &Self::DateInner) -> types::YearInfo { Self::year_as_iso(date.0.year) } - + /// The calendar-specific year represented by `date` + fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear { + Self::year_as_iso(date.0.year).into() + } fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { Self::is_leap_year(date.0.year, ()) } @@ -218,9 +220,9 @@ impl Calendar for Iso { types::DayOfYearInfo { day_of_year: date.0.day_of_year(), days_in_year: date.0.days_in_year(), - prev_year: Self::year_as_iso(prev_year), + prev_year: Self::year_as_iso(prev_year).into(), days_in_prev_year: Iso::days_in_year_direct(prev_year), - next_year: Self::year_as_iso(next_year), + next_year: Self::year_as_iso(next_year).into(), } } @@ -444,13 +446,8 @@ impl Iso { } /// Wrap the year in the appropriate era code - fn year_as_iso(year: i32) -> types::FormattableYear { - types::FormattableYear { - era: types::Era(tinystr!(16, "default")), - number: year, - cyclic: None, - related_iso: None, - } + fn year_as_iso(year: i32) -> types::YearInfo { + types::YearInfo::new(year, tinystr!(16, "default"), year) } } diff --git a/components/calendar/src/japanese.rs b/components/calendar/src/japanese.rs index ec976978b3f..fa914e41f1b 100644 --- a/components/calendar/src/japanese.rs +++ b/components/calendar/src/japanese.rs @@ -270,14 +270,12 @@ impl Calendar for Japanese { .cast_unit() } - /// The calendar-specific year represented by `date` - fn year(&self, date: &Self::DateInner) -> types::FormattableYear { - types::FormattableYear { - era: types::Era(date.era), - number: date.adjusted_year, - cyclic: None, - related_iso: None, - } + fn year(&self, date: &Self::DateInner) -> types::YearInfo { + types::YearInfo::new(date.inner.0.year, date.era, date.adjusted_year) + } + + fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear { + self.year(date).into() } fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { @@ -304,9 +302,9 @@ impl Calendar for Japanese { types::DayOfYearInfo { day_of_year: Iso::days_in_year_direct(date.inner.0.year), days_in_year: Iso::days_in_year_direct(date.inner.0.year), - prev_year: self.year(&prev_dec_31), + prev_year: self.formattable_year(&prev_dec_31), days_in_prev_year: Iso::days_in_year_direct(prev_dec_31.inner.0.year), - next_year: self.year(&next_jan_1), + next_year: self.formattable_year(&next_jan_1), } } @@ -375,11 +373,14 @@ impl Calendar for JapaneseExtended { .cast_unit() } - /// The calendar-specific year represented by `date` - fn year(&self, date: &Self::DateInner) -> types::FormattableYear { + fn year(&self, date: &Self::DateInner) -> types::YearInfo { Japanese::year(&self.0, date) } + fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear { + Japanese::formattable_year(&self.0, date) + } + fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { Japanese::is_in_leap_year(&self.0, date) } diff --git a/components/calendar/src/julian.rs b/components/calendar/src/julian.rs index 46055b49a74..6ae2764b88b 100644 --- a/components/calendar/src/julian.rs +++ b/components/calendar/src/julian.rs @@ -178,10 +178,16 @@ impl Calendar for Julian { /// The calendar-specific year represented by `date` /// Julian has the same era scheme as Gregorian - fn year(&self, date: &Self::DateInner) -> types::FormattableYear { + fn year(&self, date: &Self::DateInner) -> types::YearInfo { year_as_gregorian(date.0.year) } + /// The calendar-specific year represented by `date` + /// Julian has the same era scheme as Gregorian + fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear { + year_as_gregorian(date.0.year).into() + } + fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { Self::is_leap_year(date.0.year, ()) } @@ -202,9 +208,9 @@ impl Calendar for Julian { types::DayOfYearInfo { day_of_year: date.0.day_of_year(), days_in_year: date.0.days_in_year(), - prev_year: crate::gregorian::year_as_gregorian(prev_year), + prev_year: crate::gregorian::year_as_gregorian(prev_year).into(), days_in_prev_year: Julian::days_in_year_direct(prev_year), - next_year: crate::gregorian::year_as_gregorian(next_year), + next_year: crate::gregorian::year_as_gregorian(next_year).into(), } } diff --git a/components/calendar/src/persian.rs b/components/calendar/src/persian.rs index 502646d0db9..6efce941d42 100644 --- a/components/calendar/src/persian.rs +++ b/components/calendar/src/persian.rs @@ -161,10 +161,12 @@ impl Calendar for Persian { date1.0.until(date2.0, _largest_unit, _smallest_unit) } - fn year(&self, date: &Self::DateInner) -> types::FormattableYear { + fn year(&self, date: &Self::DateInner) -> types::YearInfo { Self::year_as_persian(date.0.year) } - + fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear { + Self::year_as_persian(date.0.year).into() + } fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { Self::is_leap_year(date.0.year, ()) } @@ -183,9 +185,9 @@ impl Calendar for Persian { types::DayOfYearInfo { day_of_year: date.0.day_of_year(), days_in_year: date.0.days_in_year(), - prev_year: Persian::year_as_persian(prev_year), + prev_year: Persian::year_as_persian(prev_year).into(), days_in_prev_year: Persian::days_in_provided_year(prev_year, ()), - next_year: Persian::year_as_persian(next_year), + next_year: Persian::year_as_persian(next_year).into(), } } @@ -222,13 +224,8 @@ impl Persian { PersianDateInner(ArithmeticDate::new_unchecked(year, month, day)) } - fn year_as_persian(year: i32) -> types::FormattableYear { - types::FormattableYear { - era: types::Era(tinystr!(16, "ah")), - number: year, - cyclic: None, - related_iso: None, - } + fn year_as_persian(year: i32) -> types::YearInfo { + types::YearInfo::new(year, tinystr!(16, "ah"), year) } } @@ -520,8 +517,18 @@ mod tests { let date = Date::try_new_persian_date(case.input, 1, 1).unwrap(); let info = Persian::day_of_year_info(&Persian, date.inner()); - assert_eq!(info.prev_year.number, case.expected_prev, "{:?}", case); - assert_eq!(info.next_year.number, case.expected_next, "{:?}", case); + assert_eq!( + info.prev_year.era_year_or_extended(), + case.expected_prev, + "{:?}", + case + ); + assert_eq!( + info.next_year.era_year_or_extended(), + case.expected_next, + "{:?}", + case + ); } } diff --git a/components/calendar/src/roc.rs b/components/calendar/src/roc.rs index ccdf7324089..c08c7a474f9 100644 --- a/components/calendar/src/roc.rs +++ b/components/calendar/src/roc.rs @@ -152,10 +152,12 @@ impl Calendar for Roc { "ROC" } - fn year(&self, date: &Self::DateInner) -> crate::types::FormattableYear { + fn year(&self, date: &Self::DateInner) -> crate::types::YearInfo { year_as_roc(date.0 .0.year as i64) } - + fn formattable_year(&self, date: &Self::DateInner) -> crate::types::FormattableYear { + year_as_roc(date.0 .0.year as i64).into() + } fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { Iso.is_in_leap_year(&date.0) } @@ -174,9 +176,9 @@ impl Calendar for Roc { types::DayOfYearInfo { day_of_year: Iso::day_of_year(date.0), days_in_year: Iso::days_in_year_direct(date.0 .0.year), - prev_year: year_as_roc(prev_year as i64), + prev_year: year_as_roc(prev_year as i64).into(), days_in_prev_year: Iso::days_in_year_direct(prev_year), - next_year: year_as_roc(next_year as i64), + next_year: year_as_roc(next_year as i64).into(), } } @@ -262,23 +264,21 @@ impl DateTime { } } -pub(crate) fn year_as_roc(year: i64) -> types::FormattableYear { +pub(crate) fn year_as_roc(year: i64) -> types::YearInfo { let year_i32 = i64_to_saturated_i32(year); let offset_i64 = ROC_ERA_OFFSET as i64; if year > offset_i64 { - types::FormattableYear { - era: types::Era(tinystr!(16, "roc")), - number: year_i32.saturating_sub(ROC_ERA_OFFSET), - cyclic: None, - related_iso: Some(year_i32), - } + types::YearInfo::new( + year_i32, + tinystr!(16, "roc"), + year_i32.saturating_sub(ROC_ERA_OFFSET), + ) } else { - types::FormattableYear { - era: types::Era(tinystr!(16, "roc-inverse")), - number: (ROC_ERA_OFFSET + 1).saturating_sub(year_i32), - cyclic: None, - related_iso: Some(year_i32), - } + types::YearInfo::new( + year_i32, + tinystr!(16, "roc-inverse"), + (ROC_ERA_OFFSET + 1).saturating_sub(year_i32), + ) } } diff --git a/components/calendar/src/types.rs b/components/calendar/src/types.rs index 8292b7dbf23..bef143f9013 100644 --- a/components/calendar/src/types.rs +++ b/components/calendar/src/types.rs @@ -26,12 +26,22 @@ use zerovec::ule::AsULE; #[allow(clippy::exhaustive_structs)] // this is a newtype pub struct Era(pub TinyStr16); -/// Representation of a formattable year. +impl Era { + /// Construct an unknown era for GIGO behavior during + pub const fn unknown() -> Self { + Era(tinystr::tinystr!(16, "unknown")) + } +} + +/// General information about a year, needed by Temporal. /// /// More fields may be added in the future for things like extended year #[derive(Copy, Clone, Debug, PartialEq)] #[non_exhaustive] -pub struct FormattableYear { +pub struct YearInfo { + /// The "extended year", typically anchored with year 1 as the year 1 of either the most modern or + /// otherwise some "major" era for the calendar + pub extended_year: i32, /// The era containing the year. /// /// This may not always be the canonical era for the calendar and could be an alias, @@ -41,37 +51,99 @@ pub struct FormattableYear { /// The year number in the current era (usually 1-based). pub number: i32, +} - /// The year in the current cycle for cyclic calendars (1-indexed) - /// can be set to `None` for non-cyclic calendars - /// - /// For chinese and dangi it will be - /// a number between 1 and 60, for hypothetical other calendars it may be something else. - pub cyclic: Option, +/// Representation of a year as needed for formatting +#[derive(Copy, Clone, Debug, PartialEq)] +#[non_exhaustive] +pub struct FormattableYear { + /// The "extended year", typically anchored with year 1 as the year 1 of either the most modern or + /// otherwise some "major" era for the calendar + pub extended_year: i32, + /// The rest of the details about the year. + pub kind: FormattableYearKind, +} - /// The related ISO year. This is normally the ISO (proleptic Gregorian) year having the greatest - /// overlap with the calendar year. It is used in certain date formatting patterns. +/// The type of year: Calendars like Chinese don't have an era and instead format with cyclic years. +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(clippy::exhaustive_enums)] // Only two kinds of years +pub enum FormattableYearKind { + /// An Era and a numeric year in that era. + EraYear(Era, i32), + /// A cyclic year, and the related ISO year /// - /// Can be `None` if the calendar does not typically use `related_iso` (and CLDR does not contain patterns - /// using it) - pub related_iso: Option, + /// Knowing the cyclic year is typically not enough to pinpoint a date, however cyclic calendars + /// don't typically use eras, so disambiguation can be done by saying things like "Year 甲辰 (2024)" + Cyclic(NonZeroU8, i32), } -impl FormattableYear { +impl YearInfo { /// Construct a new Year given an era and number - /// - /// Other fields can be set mutably after construction - /// as needed - pub fn new(era: Era, number: i32, cyclic: Option) -> Self { + pub fn new(extended_year: i32, era: TinyStr16, number: i32) -> Self { Self { - era, + extended_year, + era: Era(era), number, - cyclic, - related_iso: None, } } } +impl FormattableYear { + /// Construct a new Year given an era and number + pub fn new_era(extended_year: i32, era: TinyStr16, number: i32) -> Self { + Self { + extended_year, + kind: FormattableYearKind::EraYear(Era(era), number), + } + } + /// Construct a new cyclic Year given a cycle and a related_iso + pub fn new_cyclic(extended_year: i32, cycle: NonZeroU8, related_iso: i32) -> Self { + Self { + extended_year, + kind: FormattableYearKind::Cyclic(cycle, related_iso), + } + } + + /// Get *some* year number that can be displayed + /// + /// Gets the eraYear for era dates, otherwise falls back to Extended Year + pub fn era_year_or_extended(self) -> i32 { + match self.kind { + FormattableYearKind::EraYear(_, y) => y, + FormattableYearKind::Cyclic(..) => self.extended_year, + } + } + + /// Return the cyclic year, if any + pub fn cyclic(self) -> Option { + match self.kind { + FormattableYearKind::EraYear(..) => None, + FormattableYearKind::Cyclic(cy, _) => Some(cy), + } + } + /// Return the Related ISO year, if any + pub fn related_iso(self) -> Option { + match self.kind { + FormattableYearKind::EraYear(..) => None, + FormattableYearKind::Cyclic(_, i) => Some(i), + } + } + /// Return the era, or "unknown" for cyclic years + pub fn era_or_unknown(self) -> Era { + match self.kind { + FormattableYearKind::EraYear(e, _) => e, + FormattableYearKind::Cyclic(..) => Era::unknown(), + } + } +} + +impl From for FormattableYear { + #[inline] + fn from(x: YearInfo) -> FormattableYear { + FormattableYear::new_era(x.extended_year, x.era.0, x.number) + } +} + /// Representation of a month in a year /// /// Month codes typically look like `M01`, `M02`, etc, but can handle leap months diff --git a/components/datetime/src/format/datetime.rs b/components/datetime/src/format/datetime.rs index 3d3154adc16..e44275fd79e 100644 --- a/components/datetime/src/format/datetime.rs +++ b/components/datetime/src/format/datetime.rs @@ -377,18 +377,19 @@ where Some(year) => match date_symbols .ok_or(DateTimeWriteError::MissingDateSymbols) .and_then(|ds| { - ds.get_symbol_for_era(l, &year.era).map_err(|e| match e { - GetSymbolForEraError::Missing => { - DateTimeWriteError::MissingEraSymbol(year.era) - } - #[cfg(feature = "experimental")] - GetSymbolForEraError::MissingNames(f) => { - DateTimeWriteError::MissingNames(f) - } - }) + ds.get_symbol_for_era(l, year.era_or_unknown()) + .map_err(|e| match e { + GetSymbolForEraError::Missing => { + DateTimeWriteError::MissingEraSymbol(year.era_or_unknown()) + } + #[cfg(feature = "experimental")] + GetSymbolForEraError::MissingNames(f) => { + DateTimeWriteError::MissingNames(f) + } + }) }) { Err(e) => { - w.with_part(Part::ERROR, |w| w.write_str(&year.era.0))?; + w.with_part(Part::ERROR, |w| w.write_str(&year.era_or_unknown().0))?; Err(e) } Ok(era) => Ok(w.write_str(era)?), @@ -399,7 +400,7 @@ where write_value_missing(w, field)?; Err(DateTimeWriteError::MissingInputField("year")) } - Some(year) => try_write_number(w, fdf, year.number.into(), l)?, + Some(year) => try_write_number(w, fdf, year.era_year_or_extended().into(), l)?, }, (FieldSymbol::Year(Year::WeekOf), l) => match week_data .ok_or(DateTimeWriteError::MissingWeekCalculator) @@ -412,7 +413,7 @@ where write_value_missing(w, field)?; Err(e) } - Ok((year, _)) => try_write_number(w, fdf, year.number.into(), l)?, + Ok((year, _)) => try_write_number(w, fdf, year.era_year_or_extended().into(), l)?, }, (FieldSymbol::Year(Year::Cyclic), l) => match datetime.year() { None => { @@ -421,7 +422,7 @@ where } Some(year) => { let r = year - .cyclic + .cyclic() .ok_or(DateTimeWriteError::MissingInputField("cyclic")) .and_then(|cyclic| { // TODO(#3761): This is a hack, we should use actual data for cyclic years @@ -459,7 +460,8 @@ where match r { Err(e) => { w.with_part(Part::ERROR, |w| { - try_write_number(w, fdf, year.number.into(), l).map(|_| ()) + try_write_number(w, fdf, year.era_year_or_extended().into(), l) + .map(|_| ()) })?; Err(e) } @@ -472,7 +474,7 @@ where .year() .ok_or(DateTimeWriteError::MissingInputField("year")) .and_then(|year| { - year.related_iso + year.related_iso() .ok_or(DateTimeWriteError::MissingInputField("related_iso")) }) { Err(e) => { diff --git a/components/datetime/src/format/neo.rs b/components/datetime/src/format/neo.rs index 8803d0f03bc..21133e5f198 100644 --- a/components/datetime/src/format/neo.rs +++ b/components/datetime/src/format/neo.rs @@ -2394,7 +2394,7 @@ impl<'data> DateSymbols<'data> for RawDateTimeNamesBorrowed<'data> { fn get_symbol_for_era<'a>( &'a self, field_length: FieldLength, - era_code: &'a Era, + era_code: Era, ) -> Result<&str, GetSymbolForEraError> { let field = fields::Field { symbol: FieldSymbol::Era, diff --git a/components/datetime/src/input.rs b/components/datetime/src/input.rs index 1704d7f498e..4d7bb8d568c 100644 --- a/components/datetime/src/input.rs +++ b/components/datetime/src/input.rs @@ -232,8 +232,8 @@ impl ExtractedDateTimeInput { | Some(AnyCalendarKind::Iso) => false, Some(AnyCalendarKind::Gregorian) => match self.year() { None => true, - Some(year) if year.number < 1000 => true, - Some(year) if year.era.0 != tinystr::tinystr!(16, "ce") => true, + Some(year) if year.era_year_or_extended() < 1000 => true, + Some(year) if year.era_or_unknown().0 != tinystr::tinystr!(16, "ce") => true, Some(_) => false, }, Some(_) => { @@ -363,7 +363,7 @@ impl> DateInput for Date { type Calendar = C; /// Gets the era and year input. fn year(&self) -> Option { - Some(self.year()) + Some(self.formattable_year()) } /// Gets the month input. @@ -399,7 +399,7 @@ impl> DateInput for DateTime { type Calendar = C; /// Gets the era and year input. fn year(&self) -> Option { - Some(self.date.year()) + Some(self.date.formattable_year()) } /// Gets the month input. diff --git a/components/datetime/src/neo_marker.rs b/components/datetime/src/neo_marker.rs index fc6d5c4b22d..b44924173ea 100644 --- a/components/datetime/src/neo_marker.rs +++ b/components/datetime/src/neo_marker.rs @@ -474,7 +474,7 @@ where impl> NeoGetField for Date { #[inline] fn get_field(&self) -> FormattableYear { - self.year() + self.formattable_year() } } @@ -544,7 +544,7 @@ impl NeoGetField for Time { impl> NeoGetField for DateTime { #[inline] fn get_field(&self) -> FormattableYear { - self.date.year() + self.date.formattable_year() } } @@ -616,7 +616,7 @@ impl> NeoGetField { #[inline] fn get_field(&self) -> FormattableYear { - self.date.year() + self.date.formattable_year() } } diff --git a/components/datetime/src/provider/date_time.rs b/components/datetime/src/provider/date_time.rs index f7db6861bff..0b3738c7dea 100644 --- a/components/datetime/src/provider/date_time.rs +++ b/components/datetime/src/provider/date_time.rs @@ -404,7 +404,7 @@ pub(crate) trait DateSymbols<'data> { fn get_symbol_for_era<'a>( &'a self, length: fields::FieldLength, - era_code: &'a Era, + era_code: Era, ) -> Result<&str, GetSymbolForEraError>; } @@ -518,7 +518,7 @@ impl<'data> DateSymbols<'data> for provider::calendar::DateSymbolsV1<'data> { fn get_symbol_for_era<'a>( &'a self, length: fields::FieldLength, - era_code: &'a Era, + era_code: Era, ) -> Result<&str, GetSymbolForEraError> { let symbols = match length { fields::FieldLength::Wide => &self.eras.names,