icu_capi/
date.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
5#[diplomat::bridge]
6pub mod ffi {
7    use alloc::boxed::Box;
8    use alloc::sync::Arc;
9    use core::fmt::Write;
10    use icu_calendar::types::IsoWeekday;
11    use icu_calendar::AnyCalendar;
12    use icu_calendar::{Date, Iso};
13    use tinystr::TinyAsciiStr;
14
15    use crate::calendar::ffi::ICU4XCalendar;
16    use crate::errors::ffi::ICU4XError;
17
18    #[cfg(feature = "icu_calendar")]
19    use crate::week::ffi::ICU4XWeekCalculator;
20
21    #[diplomat::enum_convert(IsoWeekday)]
22    pub enum ICU4XIsoWeekday {
23        Monday = 1,
24        Tuesday,
25        Wednesday,
26        Thursday,
27        Friday,
28        Saturday,
29        Sunday,
30    }
31    #[diplomat::opaque]
32    #[diplomat::transparent_convert]
33    /// An ICU4X Date object capable of containing a ISO-8601 date
34    #[diplomat::rust_link(icu::calendar::Date, Struct)]
35    pub struct ICU4XIsoDate(pub Date<Iso>);
36
37    impl ICU4XIsoDate {
38        /// Creates a new [`ICU4XIsoDate`] from the specified date and time.
39        #[diplomat::rust_link(icu::calendar::Date::try_new_iso_date, FnInStruct)]
40        #[diplomat::attr(all(supports = constructors, supports = fallible_constructors), constructor)]
41        pub fn create(year: i32, month: u8, day: u8) -> Result<Box<ICU4XIsoDate>, ICU4XError> {
42            Ok(Box::new(ICU4XIsoDate(Date::try_new_iso_date(
43                year, month, day,
44            )?)))
45        }
46
47        /// Creates a new [`ICU4XIsoDate`] representing January 1, 1970.
48        #[diplomat::rust_link(icu::calendar::Date::unix_epoch, FnInStruct)]
49        #[diplomat::attr(all(supports = constructors, supports = fallible_constructors, supports = named_constructors), named_constructor = "for_unix_epoch")]
50        pub fn create_for_unix_epoch() -> Box<ICU4XIsoDate> {
51            Box::new(ICU4XIsoDate(Date::unix_epoch()))
52        }
53
54        /// Convert this date to one in a different calendar
55        #[diplomat::rust_link(icu::calendar::Date::to_calendar, FnInStruct)]
56        pub fn to_calendar(&self, calendar: &ICU4XCalendar) -> Box<ICU4XDate> {
57            Box::new(ICU4XDate(self.0.to_calendar(calendar.0.clone())))
58        }
59
60        #[diplomat::rust_link(icu::calendar::Date::to_any, FnInStruct)]
61        pub fn to_any(&self) -> Box<ICU4XDate> {
62            Box::new(ICU4XDate(self.0.to_any().wrap_calendar_in_arc()))
63        }
64
65        /// Returns the 1-indexed day in the year for this date
66        #[diplomat::rust_link(icu::calendar::Date::day_of_year_info, FnInStruct)]
67        #[diplomat::attr(supports = accessors, getter)]
68        pub fn day_of_year(&self) -> u16 {
69            self.0.day_of_year_info().day_of_year
70        }
71
72        /// Returns the 1-indexed day in the month for this date
73        #[diplomat::rust_link(icu::calendar::Date::day_of_month, FnInStruct)]
74        #[diplomat::attr(supports = accessors, getter)]
75        pub fn day_of_month(&self) -> u32 {
76            self.0.day_of_month().0
77        }
78
79        /// Returns the day in the week for this day
80        #[diplomat::rust_link(icu::calendar::Date::day_of_week, FnInStruct)]
81        #[diplomat::attr(supports = accessors, getter)]
82        pub fn day_of_week(&self) -> ICU4XIsoWeekday {
83            self.0.day_of_week().into()
84        }
85
86        /// Returns the week number in this month, 1-indexed, based on what
87        /// is considered the first day of the week (often a locale preference).
88        ///
89        /// `first_weekday` can be obtained via `first_weekday()` on [`ICU4XWeekCalculator`]
90        #[diplomat::rust_link(icu::calendar::Date::week_of_month, FnInStruct)]
91        #[diplomat::rust_link(
92            icu::calendar::week::WeekCalculator::week_of_month,
93            FnInStruct,
94            hidden
95        )]
96        pub fn week_of_month(&self, first_weekday: ICU4XIsoWeekday) -> u32 {
97            self.0.week_of_month(first_weekday.into()).0
98        }
99
100        /// Returns the week number in this year, using week data
101        #[diplomat::rust_link(icu::calendar::Date::week_of_year, FnInStruct)]
102        #[diplomat::rust_link(
103            icu::calendar::week::WeekCalculator::week_of_year,
104            FnInStruct,
105            hidden
106        )]
107        #[cfg(feature = "icu_calendar")]
108        pub fn week_of_year(
109            &self,
110            calculator: &ICU4XWeekCalculator,
111        ) -> Result<crate::week::ffi::ICU4XWeekOf, ICU4XError> {
112            Ok(self.0.week_of_year(&calculator.0)?.into())
113        }
114
115        /// Returns 1-indexed number of the month of this date in its year
116        #[diplomat::rust_link(icu::calendar::Date::month, FnInStruct)]
117        #[diplomat::attr(supports = accessors, getter)]
118        pub fn month(&self) -> u32 {
119            self.0.month().ordinal
120        }
121
122        /// Returns the year number for this date
123        #[diplomat::rust_link(icu::calendar::Date::year, FnInStruct)]
124        #[diplomat::attr(supports = accessors, getter)]
125        pub fn year(&self) -> i32 {
126            self.0.year().number
127        }
128
129        /// Returns if the year is a leap year for this date
130        #[diplomat::rust_link(icu::calendar::Date::is_in_leap_year, FnInStruct)]
131        #[diplomat::attr(supports = accessors, getter)]
132        pub fn is_in_leap_year(&self) -> bool {
133            self.0.is_in_leap_year()
134        }
135
136        /// Returns the number of months in the year represented by this date
137        #[diplomat::rust_link(icu::calendar::Date::months_in_year, FnInStruct)]
138        #[diplomat::attr(supports = accessors, getter)]
139        pub fn months_in_year(&self) -> u8 {
140            self.0.months_in_year()
141        }
142
143        /// Returns the number of days in the month represented by this date
144        #[diplomat::rust_link(icu::calendar::Date::days_in_month, FnInStruct)]
145        #[diplomat::attr(supports = accessors, getter)]
146        pub fn days_in_month(&self) -> u8 {
147            self.0.days_in_month()
148        }
149
150        /// Returns the number of days in the year represented by this date
151        #[diplomat::rust_link(icu::calendar::Date::days_in_year, FnInStruct)]
152        #[diplomat::attr(supports = accessors, getter)]
153        pub fn days_in_year(&self) -> u16 {
154            self.0.days_in_year()
155        }
156    }
157
158    #[diplomat::opaque]
159    #[diplomat::transparent_convert]
160    /// An ICU4X Date object capable of containing a date and time for any calendar.
161    #[diplomat::rust_link(icu::calendar::Date, Struct)]
162    pub struct ICU4XDate(pub Date<Arc<AnyCalendar>>);
163
164    impl ICU4XDate {
165        /// Creates a new [`ICU4XDate`] representing the ISO date and time
166        /// given but in a given calendar
167        #[diplomat::rust_link(icu::calendar::Date::new_from_iso, FnInStruct)]
168        #[diplomat::attr(all(supports = constructors, supports = fallible_constructors, supports = named_constructors), named_constructor = "from_iso_in_calendar")]
169        pub fn create_from_iso_in_calendar(
170            year: i32,
171            month: u8,
172            day: u8,
173            calendar: &ICU4XCalendar,
174        ) -> Result<Box<ICU4XDate>, ICU4XError> {
175            let cal = calendar.0.clone();
176            Ok(Box::new(ICU4XDate(
177                Date::try_new_iso_date(year, month, day)?.to_calendar(cal),
178            )))
179        }
180
181        /// Creates a new [`ICU4XDate`] from the given codes, which are interpreted in the given calendar system
182        #[diplomat::rust_link(icu::calendar::Date::try_new_from_codes, FnInStruct)]
183        #[diplomat::attr(all(supports = constructors, supports = fallible_constructors, supports = named_constructors), named_constructor = "from_codes_in_calendar")]
184        pub fn create_from_codes_in_calendar(
185            era_code: &DiplomatStr,
186            year: i32,
187            month_code: &DiplomatStr,
188            day: u8,
189            calendar: &ICU4XCalendar,
190        ) -> Result<Box<ICU4XDate>, ICU4XError> {
191            let era = TinyAsciiStr::from_bytes(era_code)
192                .map_err(|_| ICU4XError::CalendarUnknownEraError)?
193                .into();
194            let month = TinyAsciiStr::from_bytes(month_code)
195                .map_err(|_| ICU4XError::CalendarUnknownMonthCodeError)?
196                .into();
197            let cal = calendar.0.clone();
198            Ok(Box::new(ICU4XDate(Date::try_new_from_codes(
199                era, year, month, day, cal,
200            )?)))
201        }
202
203        /// Convert this date to one in a different calendar
204        #[diplomat::rust_link(icu::calendar::Date::to_calendar, FnInStruct)]
205        pub fn to_calendar(&self, calendar: &ICU4XCalendar) -> Box<ICU4XDate> {
206            Box::new(ICU4XDate(self.0.to_calendar(calendar.0.clone())))
207        }
208
209        /// Converts this date to ISO
210        #[diplomat::rust_link(icu::calendar::Date::to_iso, FnInStruct)]
211        pub fn to_iso(&self) -> Box<ICU4XIsoDate> {
212            Box::new(ICU4XIsoDate(self.0.to_iso()))
213        }
214
215        /// Returns the 1-indexed day in the year for this date
216        #[diplomat::rust_link(icu::calendar::Date::day_of_year_info, FnInStruct)]
217        #[diplomat::attr(supports = accessors, getter)]
218        pub fn day_of_year(&self) -> u16 {
219            self.0.day_of_year_info().day_of_year
220        }
221
222        /// Returns the 1-indexed day in the month for this date
223        #[diplomat::rust_link(icu::calendar::Date::day_of_month, FnInStruct)]
224        #[diplomat::attr(supports = accessors, getter)]
225        pub fn day_of_month(&self) -> u32 {
226            self.0.day_of_month().0
227        }
228
229        /// Returns the day in the week for this day
230        #[diplomat::rust_link(icu::calendar::Date::day_of_week, FnInStruct)]
231        #[diplomat::attr(supports = accessors, getter)]
232        pub fn day_of_week(&self) -> ICU4XIsoWeekday {
233            self.0.day_of_week().into()
234        }
235
236        /// Returns the week number in this month, 1-indexed, based on what
237        /// is considered the first day of the week (often a locale preference).
238        ///
239        /// `first_weekday` can be obtained via `first_weekday()` on [`ICU4XWeekCalculator`]
240        #[diplomat::rust_link(icu::calendar::Date::week_of_month, FnInStruct)]
241        #[diplomat::rust_link(
242            icu::calendar::week::WeekCalculator::week_of_month,
243            FnInStruct,
244            hidden
245        )]
246        pub fn week_of_month(&self, first_weekday: ICU4XIsoWeekday) -> u32 {
247            self.0.week_of_month(first_weekday.into()).0
248        }
249
250        /// Returns the week number in this year, using week data
251        #[diplomat::rust_link(icu::calendar::Date::week_of_year, FnInStruct)]
252        #[diplomat::rust_link(
253            icu::calendar::week::WeekCalculator::week_of_year,
254            FnInStruct,
255            hidden
256        )]
257        #[cfg(feature = "icu_calendar")]
258        pub fn week_of_year(
259            &self,
260            calculator: &ICU4XWeekCalculator,
261        ) -> Result<crate::week::ffi::ICU4XWeekOf, ICU4XError> {
262            Ok(self.0.week_of_year(&calculator.0)?.into())
263        }
264
265        /// Returns 1-indexed number of the month of this date in its year
266        ///
267        /// Note that for lunar calendars this may not lead to the same month
268        /// having the same ordinal month across years; use month_code if you care
269        /// about month identity.
270        #[diplomat::rust_link(icu::calendar::Date::month, FnInStruct)]
271        #[diplomat::attr(supports = accessors, getter)]
272        pub fn ordinal_month(&self) -> u32 {
273            self.0.month().ordinal
274        }
275
276        /// Returns the month code for this date. Typically something
277        /// like "M01", "M02", but can be more complicated for lunar calendars.
278        #[diplomat::rust_link(icu::calendar::Date::month, FnInStruct)]
279        #[diplomat::attr(supports = accessors, getter)]
280        pub fn month_code(
281            &self,
282            write: &mut diplomat_runtime::DiplomatWriteable,
283        ) -> Result<(), ICU4XError> {
284            let code = self.0.month().code;
285            write.write_str(&code.0)?;
286            Ok(())
287        }
288
289        /// Returns the year number in the current era for this date
290        #[diplomat::rust_link(icu::calendar::Date::year, FnInStruct)]
291        #[diplomat::attr(supports = accessors, getter)]
292        pub fn year_in_era(&self) -> i32 {
293            self.0.year().number
294        }
295
296        /// Returns the era for this date,
297        #[diplomat::rust_link(icu::Date::year, FnInStruct)]
298        #[diplomat::rust_link(icu::types::Era, Struct, compact)]
299        #[diplomat::attr(supports = accessors, getter)]
300        pub fn era(
301            &self,
302            write: &mut diplomat_runtime::DiplomatWriteable,
303        ) -> Result<(), ICU4XError> {
304            let era = self.0.year().era;
305            write.write_str(&era.0)?;
306            Ok(())
307        }
308
309        /// Returns the number of months in the year represented by this date
310        #[diplomat::rust_link(icu::calendar::Date::months_in_year, FnInStruct)]
311        #[diplomat::attr(supports = accessors, getter)]
312        pub fn months_in_year(&self) -> u8 {
313            self.0.months_in_year()
314        }
315
316        /// Returns the number of days in the month represented by this date
317        #[diplomat::rust_link(icu::calendar::Date::days_in_month, FnInStruct)]
318        #[diplomat::attr(supports = accessors, getter)]
319        pub fn days_in_month(&self) -> u8 {
320            self.0.days_in_month()
321        }
322
323        /// Returns the number of days in the year represented by this date
324        #[diplomat::rust_link(icu::calendar::Date::days_in_year, FnInStruct)]
325        #[diplomat::attr(supports = accessors, getter)]
326        pub fn days_in_year(&self) -> u16 {
327            self.0.days_in_year()
328        }
329
330        /// Returns the [`ICU4XCalendar`] object backing this date
331        #[diplomat::rust_link(icu::calendar::Date::calendar, FnInStruct)]
332        #[diplomat::rust_link(icu::calendar::Date::calendar_wrapper, FnInStruct, hidden)]
333        #[diplomat::attr(supports = accessors, getter)]
334        pub fn calendar(&self) -> Box<ICU4XCalendar> {
335            Box::new(ICU4XCalendar(self.0.calendar_wrapper().clone()))
336        }
337    }
338}