icu_calendar/
calendar.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5use calendrical_calculations::rata_die::RataDie;
6
7use crate::cal::iso::IsoDateInner;
8use crate::error::{DateError, DateFromFieldsError};
9use crate::options::DateFromFieldsOptions;
10use crate::options::{DateAddOptions, DateDifferenceOptions};
11use crate::{types, Iso};
12use core::fmt;
13
14/// A calendar implementation
15///
16/// Only implementors of [`Calendar`] should care about these methods, in general users of
17/// these calendars should use the methods on [`Date`](crate::Date) instead.
18///
19/// Individual [`Calendar`] implementations may have inherent utility methods
20/// allowing for direct construction, etc.
21///
22/// <div class="stab unstable">
23/// 🚫 This trait is sealed; it should not be implemented by user code. If an API requests an item that implements this
24/// trait, please consider using a type from the implementors listed below.
25///
26/// It is still possible to implement this trait in userland (since `UnstableSealed` is public),
27/// do not do so unless you are prepared for things to occasionally break.
28/// </div>
29pub trait Calendar: crate::cal::scaffold::UnstableSealed {
30    /// The internal type used to represent dates
31    ///
32    /// Equality and ordering should observe normal calendar semantics.
33    type DateInner: Eq + Copy + PartialOrd + fmt::Debug;
34    /// The type of YearInfo returned by the date
35    type Year: fmt::Debug + Into<types::YearInfo>;
36    /// The type of error returned by `until`
37    type DifferenceError;
38
39    /// Construct a date from era/month codes and fields
40    ///
41    /// The year is the [extended year](crate::Date::extended_year) if no era is provided
42    #[expect(clippy::wrong_self_convention)]
43    fn from_codes(
44        &self,
45        era: Option<&str>,
46        year: i32,
47        month_code: types::MonthCode,
48        day: u8,
49    ) -> Result<Self::DateInner, DateError>;
50
51    /// Construct a date from a bag of date fields.
52    ///
53    /// <div class="stab unstable">
54    /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways,
55    /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break.
56    ///
57    /// Graduation tracking issue: [issue #7161](https://github.com/unicode-org/icu4x/issues/7161).
58    /// </div>
59    ///
60    /// ✨ *Enabled with the `unstable` Cargo feature.*
61    #[expect(clippy::wrong_self_convention)]
62    #[cfg(feature = "unstable")]
63    fn from_fields(
64        &self,
65        fields: types::DateFields,
66        options: DateFromFieldsOptions,
67    ) -> Result<Self::DateInner, DateFromFieldsError>;
68
69    /// Whether `from_iso`/`to_iso` is more efficient
70    /// than `from_rata_die`/`to_rata_die`.
71    fn has_cheap_iso_conversion(&self) -> bool;
72
73    /// Construct the date from an ISO date.
74    ///
75    /// Only called if `HAS_CHEAP_ISO_CONVERSION` is set.
76    #[expect(clippy::wrong_self_convention)]
77    fn from_iso(&self, iso: IsoDateInner) -> Self::DateInner {
78        self.from_rata_die(Iso.to_rata_die(&iso))
79    }
80    /// Obtain an ISO date from this date.
81    ///
82    /// Only called if `HAS_CHEAP_ISO_CONVERSION` is set.
83    fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner {
84        Iso.from_rata_die(self.to_rata_die(date))
85    }
86
87    /// Construct the date from a [`RataDie`]
88    #[expect(clippy::wrong_self_convention)]
89    fn from_rata_die(&self, rd: RataDie) -> Self::DateInner;
90    /// Obtain a [`RataDie`] from this date
91    fn to_rata_die(&self, date: &Self::DateInner) -> RataDie;
92
93    /// Count the number of months in a given year, specified by providing a date
94    /// from that year
95    fn months_in_year(&self, date: &Self::DateInner) -> u8;
96    /// Count the number of days in a given year, specified by providing a date
97    /// from that year
98    fn days_in_year(&self, date: &Self::DateInner) -> u16;
99    /// Count the number of days in a given month, specified by providing a date
100    /// from that year/month
101    fn days_in_month(&self, date: &Self::DateInner) -> u8;
102    /// Calculate if a date is in a leap year
103    fn is_in_leap_year(&self, date: &Self::DateInner) -> bool;
104
105    /// Information about the year
106    fn year_info(&self, date: &Self::DateInner) -> Self::Year;
107
108    /// The [extended year](crate::Date::extended_year).
109    fn extended_year(&self, date: &Self::DateInner) -> i32 {
110        self.year_info(date).into().extended_year()
111    }
112    /// The calendar-specific month represented by `date`
113    fn month(&self, date: &Self::DateInner) -> types::MonthInfo;
114    /// The calendar-specific day-of-month represented by `date`
115    fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth;
116    /// Information of the day of the year
117    fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear;
118
119    /// Add `duration` to `date`
120    ///
121    /// <div class="stab unstable">
122    /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways,
123    /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break.
124    ///
125    /// Graduation tracking issue: [issue #3964](https://github.com/unicode-org/icu4x/issues/3964).
126    /// </div>
127    ///
128    /// ✨ *Enabled with the `unstable` Cargo feature.*
129    #[cfg(feature = "unstable")]
130    fn add(
131        &self,
132        date: &Self::DateInner,
133        duration: types::DateDuration,
134        options: DateAddOptions,
135    ) -> Result<Self::DateInner, DateError>;
136
137    /// Calculate `date2 - date` as a duration
138    ///
139    /// `calendar2` is the calendar object associated with `date2`. In case the specific calendar objects
140    /// differ on data, the data for the first calendar is used, and `date2` may be converted if necessary.
141    ///
142    /// <div class="stab unstable">
143    /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways,
144    /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break.
145    ///
146    /// Graduation tracking issue: [issue #3964](https://github.com/unicode-org/icu4x/issues/3964).
147    /// </div>
148    ///
149    /// ✨ *Enabled with the `unstable` Cargo feature.*
150    #[cfg(feature = "unstable")]
151    fn until(
152        &self,
153        date1: &Self::DateInner,
154        date2: &Self::DateInner,
155        options: DateDifferenceOptions,
156    ) -> Result<types::DateDuration, Self::DifferenceError>;
157
158    /// Returns the [`CalendarAlgorithm`](crate::preferences::CalendarAlgorithm) that is required to match
159    /// when parsing into this calendar.
160    ///
161    /// If left empty, any algorithm will parse successfully.
162    fn calendar_algorithm(&self) -> Option<crate::preferences::CalendarAlgorithm>;
163
164    /// Obtain a name for the calendar for debug printing
165    fn debug_name(&self) -> &'static str;
166}