// This file is part of ICU4X. For terms of use, please see the file // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use calendrical_calculations::rata_die::RataDie; use crate::Iso; use crate::cal::iso::IsoDateInner; use crate::error::{DateAddError, DateError, DateFromFieldsError, DateNewError}; use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::types::{self, Month, YearInput}; use core::fmt; #[cfg(doc)] use crate::Date; /// A calendar implementation /// /// Only implementors of [`Calendar`] should care about these methods, in general users of /// these calendars should use the methods on [`Date`](crate::Date) instead. /// /// Individual [`Calendar`] implementations may have inherent utility methods /// allowing for direct construction, etc. /// ///
/// 🚫 This trait is sealed; it should not be implemented by user code. If an API requests an item that implements this /// trait, please consider using a type from the implementors listed below. /// /// It is still possible to implement this trait in userland (since `UnstableSealed` is public), /// do not do so unless you are prepared for things to occasionally break. ///
pub trait Calendar: crate::cal::scaffold::UnstableSealed { /// The internal type used to represent dates /// /// Using the [`Eq`] or [`PartialOrd`] implementations requires /// the associated calendars to have passed [`Self::check_date_compatibility`]. type DateInner: Eq + Copy + PartialOrd + fmt::Debug; /// The type of year info returned by the date type Year: fmt::Debug + Into; /// The error that is returned by [`Self::check_date_compatibility`]. /// /// Set this to [`core::convert::Infallible`] if the type is a singleton or /// the parameterization does not affect date semantics. type DateCompatibilityError: fmt::Debug; /// Construct a date from era/month codes and fields /// /// The year is the [extended year](crate::Date::extended_year) if no era is provided /// /// This is used by the deprecated [`Date::try_new_from_codes()`]. Implementors /// should rely on the default impl which adapts this to using [`Self::new_date()`]. #[expect(clippy::wrong_self_convention)] #[deprecated(since = "2.2.0", note = "use `new_date`")] fn from_codes( &self, era: Option<&str>, year: i32, month_code: types::MonthCode, day: u8, ) -> Result { let input_year = match era { Some(e) => YearInput::EraYear(e, year), None => year.into(), }; let month = match Month::try_from_utf8(month_code.0.as_bytes()) { Ok(m) => m, Err(_) => return Err(DateError::UnknownMonthCode(month_code)), }; let result = self.new_date(input_year, month, day); match result { Ok(date) => Ok(date), Err(codes_error) => Err(match codes_error { DateNewError::InvalidDay { max } => DateError::Range { field: "day", value: day as i32, min: 1, max: max as i32, }, DateNewError::MonthNotInCalendar | DateNewError::MonthNotInYear => { DateError::UnknownMonthCode(month_code) } DateNewError::InvalidEra => DateError::UnknownEra, DateNewError::InvalidYear => DateError::Range { field: "year", value: year, min: -9999, max: 9999, }, }), } } /// Construct a date from a [`YearInput`], [`Month`], and a day. /// /// This is used by [`Date::try_new()`]. fn new_date( &self, year: YearInput, month: Month, day: u8, ) -> Result; /// Construct a date from a bag of date fields. #[expect(clippy::wrong_self_convention)] fn from_fields( &self, fields: types::DateFields, options: DateFromFieldsOptions, ) -> Result; /// Whether `from_iso`/`to_iso` is more efficient /// than `from_rata_die`/`to_rata_die`. fn has_cheap_iso_conversion(&self) -> bool; /// Construct the date from an ISO date. /// /// Only called if `HAS_CHEAP_ISO_CONVERSION` is set. #[expect(clippy::wrong_self_convention)] fn from_iso(&self, iso: IsoDateInner) -> Self::DateInner { // `from_rata_die` precondition is satified by `to_rata_die` self.from_rata_die(Iso.to_rata_die(&iso)) } /// Obtain an ISO date from this date. /// /// Only called if `HAS_CHEAP_ISO_CONVERSION` is set. fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { // `from_rata_die` precondition is satified by `to_rata_die` Iso.from_rata_die(self.to_rata_die(date)) } /// Construct the date from a [`RataDie`] /// /// Precondition: `rd` needs to be in the `VALID_RD_RANGE` #[expect(clippy::wrong_self_convention)] fn from_rata_die(&self, rd: RataDie) -> Self::DateInner; /// Obtain a [`RataDie`] from this date /// /// The result is guaranteed to be in `VALID_RD_RANGE` fn to_rata_die(&self, date: &Self::DateInner) -> RataDie; /// Count the number of months in a given year, specified by providing a date /// from that year fn months_in_year(&self, date: &Self::DateInner) -> u8; /// Count the number of days in a given year, specified by providing a date /// from that year fn days_in_year(&self, date: &Self::DateInner) -> u16; /// Count the number of days in a given month, specified by providing a date /// from that year/month fn days_in_month(&self, date: &Self::DateInner) -> u8; /// Calculate if a date is in a leap year fn is_in_leap_year(&self, date: &Self::DateInner) -> bool; /// Information about the year fn year_info(&self, date: &Self::DateInner) -> Self::Year; /// The [extended year](crate::Date::extended_year). fn extended_year(&self, date: &Self::DateInner) -> i32 { self.year_info(date).into().extended_year() } /// The calendar-specific month represented by `date` fn month(&self, date: &Self::DateInner) -> types::MonthInfo; /// The calendar-specific day-of-month represented by `date` fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth; /// Information of the day of the year fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear; /// Add `duration` to `date` fn add( &self, date: &Self::DateInner, duration: types::DateDuration, options: DateAddOptions, ) -> Result; /// Calculate `date2 - date` as a duration. /// /// This requires the associated calendars to have passed [`Self::check_date_compatibility`]. fn until( &self, date1: &Self::DateInner, date2: &Self::DateInner, options: DateDifferenceOptions, ) -> types::DateDuration; /// Returns whether [`Self::DateInner`] represents the same date in both calendars. /// /// This is checked by [`Date::try_until_with_options`](crate::Date::try_until_with_options), /// `impl PartialEq for Date`, `impl PartialOrd for Date`, and `impl Ord for Date`. fn check_date_compatibility(&self, other: &Self) -> Result<(), Self::DateCompatibilityError>; /// Returns the [`CalendarAlgorithm`](crate::preferences::CalendarAlgorithm) that is required to match /// when parsing into this calendar. /// /// If left empty, any algorithm will parse successfully. fn calendar_algorithm(&self) -> Option; /// Obtain a name for the calendar for debug printing fn debug_name(&self) -> &'static str; }