icu_capi/
datetime.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::convert::TryInto;
10    use core::fmt::Write;
11
12    use icu_calendar::{AnyCalendar, DateTime, Iso, Time};
13    use tinystr::TinyAsciiStr;
14
15    use crate::calendar::ffi::ICU4XCalendar;
16    use crate::date::ffi::{ICU4XDate, ICU4XIsoDate, ICU4XIsoWeekday};
17    use crate::errors::ffi::ICU4XError;
18    use crate::time::ffi::ICU4XTime;
19
20    #[cfg(feature = "icu_calendar")]
21    use crate::week::ffi::ICU4XWeekCalculator;
22
23    #[diplomat::opaque]
24    /// An ICU4X DateTime object capable of containing a ISO-8601 date and time.
25    #[diplomat::rust_link(icu::calendar::DateTime, Struct)]
26    pub struct ICU4XIsoDateTime(pub DateTime<Iso>);
27
28    impl ICU4XIsoDateTime {
29        /// Creates a new [`ICU4XIsoDateTime`] from the specified date and time.
30        #[diplomat::rust_link(icu::calendar::DateTime::try_new_iso_datetime, FnInStruct)]
31        #[diplomat::attr(all(supports = constructors, supports = fallible_constructors), constructor)]
32        pub fn create(
33            year: i32,
34            month: u8,
35            day: u8,
36            hour: u8,
37            minute: u8,
38            second: u8,
39            nanosecond: u32,
40        ) -> Result<Box<ICU4XIsoDateTime>, ICU4XError> {
41            let mut dt = DateTime::try_new_iso_datetime(year, month, day, hour, minute, second)?;
42            dt.time.nanosecond = nanosecond.try_into()?;
43            Ok(Box::new(ICU4XIsoDateTime(dt)))
44        }
45
46        /// Creates a new [`ICU4XIsoDateTime`] from an [`ICU4XIsoDate`] and [`ICU4XTime`] object
47        #[diplomat::rust_link(icu::calendar::DateTime::new, FnInStruct)]
48        #[diplomat::attr(all(supports = constructors, supports = fallible_constructors, supports = named_constructors), named_constructor = "from_date_and_time")]
49        pub fn crate_from_date_and_time(
50            date: &ICU4XIsoDate,
51            time: &ICU4XTime,
52        ) -> Box<ICU4XIsoDateTime> {
53            let dt = DateTime::new(date.0, time.0);
54            Box::new(ICU4XIsoDateTime(dt))
55        }
56
57        /// Creates a new [`ICU4XIsoDateTime`] of midnight on January 1, 1970
58        #[diplomat::rust_link(icu::calendar::DateTime::local_unix_epoch, FnInStruct)]
59        #[diplomat::attr(all(supports = constructors, supports = fallible_constructors, supports = named_constructors), named_constructor = "local_unix_epoch")]
60        pub fn local_unix_epoch() -> Box<ICU4XIsoDateTime> {
61            let dt = DateTime::local_unix_epoch();
62            Box::new(ICU4XIsoDateTime(dt))
63        }
64
65        /// Construct from the minutes since the local unix epoch for this date (Jan 1 1970, 00:00)
66        #[diplomat::rust_link(
67            icu::calendar::DateTime::from_minutes_since_local_unix_epoch,
68            FnInStruct
69        )]
70        #[diplomat::attr(all(supports = constructors, supports = fallible_constructors, supports = named_constructors), named_constructor = "from_minutes_since_local_unix_epoch")]
71        pub fn create_from_minutes_since_local_unix_epoch(minutes: i32) -> Box<ICU4XIsoDateTime> {
72            Box::new(ICU4XIsoDateTime(
73                DateTime::from_minutes_since_local_unix_epoch(minutes),
74            ))
75        }
76
77        /// Gets the date contained in this object
78        #[diplomat::rust_link(icu::calendar::DateTime::date, StructField)]
79        #[diplomat::attr(supports = accessors, getter)]
80        pub fn date(&self) -> Box<ICU4XIsoDate> {
81            Box::new(ICU4XIsoDate(self.0.date))
82        }
83
84        /// Gets the time contained in this object
85        #[diplomat::rust_link(icu::calendar::DateTime::time, StructField)]
86        #[diplomat::attr(supports = accessors, getter)]
87        pub fn time(&self) -> Box<ICU4XTime> {
88            Box::new(ICU4XTime(self.0.time))
89        }
90
91        /// Converts this to an [`ICU4XDateTime`] capable of being mixed with dates of
92        /// other calendars
93        #[diplomat::rust_link(icu::calendar::DateTime::to_any, FnInStruct)]
94        #[diplomat::rust_link(icu::calendar::DateTime::new_from_iso, FnInStruct, hidden)]
95        pub fn to_any(&self) -> Box<ICU4XDateTime> {
96            Box::new(ICU4XDateTime(self.0.to_any().wrap_calendar_in_arc()))
97        }
98
99        /// Gets the minutes since the local unix epoch for this date (Jan 1 1970, 00:00)
100        #[diplomat::rust_link(icu::calendar::DateTime::minutes_since_local_unix_epoch, FnInStruct)]
101        #[diplomat::attr(supports = accessors, getter)]
102        pub fn minutes_since_local_unix_epoch(&self) -> i32 {
103            self.0.minutes_since_local_unix_epoch()
104        }
105
106        /// Convert this datetime to one in a different calendar
107        #[diplomat::rust_link(icu::calendar::DateTime::to_calendar, FnInStruct)]
108        pub fn to_calendar(&self, calendar: &ICU4XCalendar) -> Box<ICU4XDateTime> {
109            Box::new(ICU4XDateTime(self.0.to_calendar(calendar.0.clone())))
110        }
111
112        /// Returns the hour in this time
113        #[diplomat::rust_link(icu::calendar::Time::hour, StructField)]
114        #[diplomat::attr(supports = accessors, getter)]
115        pub fn hour(&self) -> u8 {
116            self.0.time.hour.into()
117        }
118        /// Returns the minute in this time
119        #[diplomat::rust_link(icu::calendar::Time::minute, StructField)]
120        #[diplomat::attr(supports = accessors, getter)]
121        pub fn minute(&self) -> u8 {
122            self.0.time.minute.into()
123        }
124        /// Returns the second in this time
125        #[diplomat::rust_link(icu::calendar::Time::second, StructField)]
126        #[diplomat::attr(supports = accessors, getter)]
127        pub fn second(&self) -> u8 {
128            self.0.time.second.into()
129        }
130        /// Returns the nanosecond in this time
131        #[diplomat::rust_link(icu::calendar::Time::nanosecond, StructField)]
132        #[diplomat::attr(supports = accessors, getter)]
133        pub fn nanosecond(&self) -> u32 {
134            self.0.time.nanosecond.into()
135        }
136
137        /// Returns the 1-indexed day in the year for this date
138        #[diplomat::rust_link(icu::calendar::Date::day_of_year_info, FnInStruct)]
139        #[diplomat::attr(supports = accessors, getter)]
140        pub fn day_of_year(&self) -> u16 {
141            self.0.date.day_of_year_info().day_of_year
142        }
143
144        /// Returns the 1-indexed day in the month for this date
145        #[diplomat::rust_link(icu::calendar::Date::day_of_month, FnInStruct)]
146        #[diplomat::attr(supports = accessors, getter)]
147        pub fn day_of_month(&self) -> u32 {
148            self.0.date.day_of_month().0
149        }
150
151        /// Returns the day in the week for this day
152        #[diplomat::rust_link(icu::calendar::Date::day_of_week, FnInStruct)]
153        #[diplomat::attr(supports = accessors, getter)]
154        pub fn day_of_week(&self) -> ICU4XIsoWeekday {
155            self.0.date.day_of_week().into()
156        }
157
158        /// Returns the week number in this month, 1-indexed, based on what
159        /// is considered the first day of the week (often a locale preference).
160        ///
161        /// `first_weekday` can be obtained via `first_weekday()` on [`ICU4XWeekCalculator`]
162        #[diplomat::rust_link(icu::calendar::Date::week_of_month, FnInStruct)]
163        #[diplomat::rust_link(
164            icu::calendar::week::WeekCalculator::week_of_month,
165            FnInStruct,
166            hidden
167        )]
168        pub fn week_of_month(&self, first_weekday: ICU4XIsoWeekday) -> u32 {
169            self.0.date.week_of_month(first_weekday.into()).0
170        }
171
172        /// Returns the week number in this year, using week data
173        #[diplomat::rust_link(icu::calendar::Date::week_of_year, FnInStruct)]
174        #[diplomat::rust_link(
175            icu::calendar::week::WeekCalculator::week_of_year,
176            FnInStruct,
177            hidden
178        )]
179        #[cfg(feature = "icu_calendar")]
180        pub fn week_of_year(
181            &self,
182            calculator: &ICU4XWeekCalculator,
183        ) -> Result<crate::week::ffi::ICU4XWeekOf, ICU4XError> {
184            Ok(self.0.date.week_of_year(&calculator.0)?.into())
185        }
186
187        /// Returns 1-indexed number of the month of this date in its year
188        #[diplomat::rust_link(icu::calendar::Date::month, FnInStruct)]
189        #[diplomat::attr(supports = accessors, getter)]
190        pub fn month(&self) -> u32 {
191            self.0.date.month().ordinal
192        }
193
194        /// Returns the year number for this date
195        #[diplomat::rust_link(icu::calendar::Date::year, FnInStruct)]
196        #[diplomat::attr(supports = accessors, getter)]
197        pub fn year(&self) -> i32 {
198            self.0.date.year().number
199        }
200
201        /// Returns whether this date is in a leap year
202        #[diplomat::rust_link(icu::calendar::Date::is_in_leap_year, FnInStruct)]
203        #[diplomat::attr(supports = accessors, getter)]
204        pub fn is_in_leap_year(&self) -> bool {
205            self.0.date.is_in_leap_year()
206        }
207
208        /// Returns the number of months in the year represented by this date
209        #[diplomat::rust_link(icu::calendar::Date::months_in_year, FnInStruct)]
210        #[diplomat::attr(supports = accessors, getter)]
211        pub fn months_in_year(&self) -> u8 {
212            self.0.date.months_in_year()
213        }
214
215        /// Returns the number of days in the month represented by this date
216        #[diplomat::rust_link(icu::calendar::Date::days_in_month, FnInStruct)]
217        #[diplomat::attr(supports = accessors, getter)]
218        pub fn days_in_month(&self) -> u8 {
219            self.0.date.days_in_month()
220        }
221
222        /// Returns the number of days in the year represented by this date
223        #[diplomat::rust_link(icu::calendar::Date::days_in_year, FnInStruct)]
224        #[diplomat::attr(supports = accessors, getter)]
225        pub fn days_in_year(&self) -> u16 {
226            self.0.date.days_in_year()
227        }
228    }
229
230    #[diplomat::opaque]
231    /// An ICU4X DateTime object capable of containing a date and time for any calendar.
232    #[diplomat::rust_link(icu::calendar::DateTime, Struct)]
233    pub struct ICU4XDateTime(pub DateTime<Arc<AnyCalendar>>);
234
235    impl ICU4XDateTime {
236        /// Creates a new [`ICU4XDateTime`] representing the ISO date and time
237        /// given but in a given calendar
238        #[diplomat::rust_link(icu::DateTime::new_from_iso, FnInStruct)]
239        #[diplomat::attr(all(supports = constructors, supports = fallible_constructors, supports = named_constructors), named_constructor = "from_iso_in_calendar")]
240        #[allow(clippy::too_many_arguments)]
241        pub fn create_from_iso_in_calendar(
242            year: i32,
243            month: u8,
244            day: u8,
245            hour: u8,
246            minute: u8,
247            second: u8,
248            nanosecond: u32,
249            calendar: &ICU4XCalendar,
250        ) -> Result<Box<ICU4XDateTime>, ICU4XError> {
251            let cal = calendar.0.clone();
252            let mut dt = DateTime::try_new_iso_datetime(year, month, day, hour, minute, second)?;
253            dt.time.nanosecond = nanosecond.try_into()?;
254            Ok(Box::new(ICU4XDateTime(dt.to_calendar(cal))))
255        }
256        /// Creates a new [`ICU4XDateTime`] from the given codes, which are interpreted in the given calendar system
257        #[diplomat::rust_link(icu::calendar::DateTime::try_new_from_codes, FnInStruct)]
258        #[diplomat::attr(all(supports = constructors, supports = fallible_constructors, supports = named_constructors), named_constructor = "from_codes_in_calendar")]
259        #[allow(clippy::too_many_arguments)]
260        pub fn create_from_codes_in_calendar(
261            era_code: &DiplomatStr,
262            year: i32,
263            month_code: &DiplomatStr,
264            day: u8,
265            hour: u8,
266            minute: u8,
267            second: u8,
268            nanosecond: u32,
269            calendar: &ICU4XCalendar,
270        ) -> Result<Box<ICU4XDateTime>, ICU4XError> {
271            let era = TinyAsciiStr::from_bytes(era_code)
272                .map_err(|_| ICU4XError::CalendarUnknownEraError)?
273                .into();
274            let month = TinyAsciiStr::from_bytes(month_code)
275                .map_err(|_| ICU4XError::CalendarUnknownMonthCodeError)?
276                .into();
277            let cal = calendar.0.clone();
278            let hour = hour.try_into()?;
279            let minute = minute.try_into()?;
280            let second = second.try_into()?;
281            let nanosecond = nanosecond.try_into()?;
282            let time = Time {
283                hour,
284                minute,
285                second,
286                nanosecond,
287            };
288            Ok(Box::new(ICU4XDateTime(DateTime::try_new_from_codes(
289                era, year, month, day, time, cal,
290            )?)))
291        }
292        /// Creates a new [`ICU4XDateTime`] from an [`ICU4XDate`] and [`ICU4XTime`] object
293        #[diplomat::rust_link(icu::calendar::DateTime::new, FnInStruct)]
294        #[diplomat::attr(all(supports = constructors, supports = fallible_constructors, supports = named_constructors), named_constructor = "from_date_and_time")]
295        pub fn create_from_date_and_time(date: &ICU4XDate, time: &ICU4XTime) -> Box<ICU4XDateTime> {
296            let dt = DateTime::new(date.0.clone(), time.0);
297            Box::new(ICU4XDateTime(dt))
298        }
299
300        /// Gets a copy of the date contained in this object
301        #[diplomat::rust_link(icu::calendar::DateTime::date, StructField)]
302        #[diplomat::attr(supports = accessors, getter)]
303        pub fn date(&self) -> Box<ICU4XDate> {
304            Box::new(ICU4XDate(self.0.date.clone()))
305        }
306
307        /// Gets the time contained in this object
308        #[diplomat::rust_link(icu::calendar::DateTime::time, StructField)]
309        #[diplomat::attr(supports = accessors, getter)]
310        pub fn time(&self) -> Box<ICU4XTime> {
311            Box::new(ICU4XTime(self.0.time))
312        }
313
314        /// Converts this date to ISO
315        #[diplomat::rust_link(icu::calendar::DateTime::to_iso, FnInStruct)]
316        pub fn to_iso(&self) -> Box<ICU4XIsoDateTime> {
317            Box::new(ICU4XIsoDateTime(self.0.to_iso()))
318        }
319
320        /// Convert this datetime to one in a different calendar
321        #[diplomat::rust_link(icu::calendar::DateTime::to_calendar, FnInStruct)]
322        pub fn to_calendar(&self, calendar: &ICU4XCalendar) -> Box<ICU4XDateTime> {
323            Box::new(ICU4XDateTime(self.0.to_calendar(calendar.0.clone())))
324        }
325
326        /// Returns the hour in this time
327        #[diplomat::rust_link(icu::calendar::Time::hour, StructField)]
328        #[diplomat::attr(supports = accessors, getter)]
329        pub fn hour(&self) -> u8 {
330            self.0.time.hour.into()
331        }
332        /// Returns the minute in this time
333        #[diplomat::rust_link(icu::calendar::Time::minute, StructField)]
334        #[diplomat::attr(supports = accessors, getter)]
335        pub fn minute(&self) -> u8 {
336            self.0.time.minute.into()
337        }
338        /// Returns the second in this time
339        #[diplomat::rust_link(icu::calendar::Time::second, StructField)]
340        #[diplomat::attr(supports = accessors, getter)]
341        pub fn second(&self) -> u8 {
342            self.0.time.second.into()
343        }
344        /// Returns the nanosecond in this time
345        #[diplomat::rust_link(icu::calendar::Time::nanosecond, StructField)]
346        #[diplomat::attr(supports = accessors, getter)]
347        pub fn nanosecond(&self) -> u32 {
348            self.0.time.nanosecond.into()
349        }
350
351        /// Returns the 1-indexed day in the year for this date
352        #[diplomat::rust_link(icu::calendar::Date::day_of_year_info, FnInStruct)]
353        #[diplomat::attr(supports = accessors, getter)]
354        pub fn day_of_year(&self) -> u16 {
355            self.0.date.day_of_year_info().day_of_year
356        }
357
358        /// Returns the 1-indexed day in the month for this date
359        #[diplomat::rust_link(icu::calendar::Date::day_of_month, FnInStruct)]
360        #[diplomat::attr(supports = accessors, getter)]
361        pub fn day_of_month(&self) -> u32 {
362            self.0.date.day_of_month().0
363        }
364
365        /// Returns the day in the week for this day
366        #[diplomat::rust_link(icu::calendar::Date::day_of_week, FnInStruct)]
367        #[diplomat::attr(supports = accessors, getter)]
368        pub fn day_of_week(&self) -> ICU4XIsoWeekday {
369            self.0.date.day_of_week().into()
370        }
371
372        /// Returns the week number in this month, 1-indexed, based on what
373        /// is considered the first day of the week (often a locale preference).
374        ///
375        /// `first_weekday` can be obtained via `first_weekday()` on [`ICU4XWeekCalculator`]
376        #[diplomat::rust_link(icu::calendar::Date::week_of_month, FnInStruct)]
377        #[diplomat::rust_link(
378            icu::calendar::week::WeekCalculator::week_of_month,
379            FnInStruct,
380            hidden
381        )]
382        pub fn week_of_month(&self, first_weekday: ICU4XIsoWeekday) -> u32 {
383            self.0.date.week_of_month(first_weekday.into()).0
384        }
385
386        /// Returns the week number in this year, using week data
387        #[diplomat::rust_link(icu::calendar::Date::week_of_year, FnInStruct)]
388        #[diplomat::rust_link(
389            icu::calendar::week::WeekCalculator::week_of_year,
390            FnInStruct,
391            hidden
392        )]
393        #[cfg(feature = "icu_calendar")]
394        pub fn week_of_year(
395            &self,
396            calculator: &ICU4XWeekCalculator,
397        ) -> Result<crate::week::ffi::ICU4XWeekOf, ICU4XError> {
398            Ok(self.0.date.week_of_year(&calculator.0)?.into())
399        }
400
401        /// Returns 1-indexed number of the month of this date in its year
402        ///
403        /// Note that for lunar calendars this may not lead to the same month
404        /// having the same ordinal month across years; use month_code if you care
405        /// about month identity.
406        #[diplomat::rust_link(icu::calendar::Date::month, FnInStruct)]
407        #[diplomat::attr(supports = accessors, getter)]
408        pub fn ordinal_month(&self) -> u32 {
409            self.0.date.month().ordinal
410        }
411
412        /// Returns the month code for this date. Typically something
413        /// like "M01", "M02", but can be more complicated for lunar calendars.
414        #[diplomat::rust_link(icu::calendar::Date::month, FnInStruct)]
415        #[diplomat::attr(supports = accessors, getter)]
416        pub fn month_code(
417            &self,
418            write: &mut diplomat_runtime::DiplomatWriteable,
419        ) -> Result<(), ICU4XError> {
420            let code = self.0.date.month().code;
421            write.write_str(&code.0)?;
422            Ok(())
423        }
424
425        /// Returns the year number in the current era for this date
426        #[diplomat::rust_link(icu::calendar::Date::year, FnInStruct)]
427        #[diplomat::attr(supports = accessors, getter)]
428        pub fn year_in_era(&self) -> i32 {
429            self.0.date.year().number
430        }
431
432        /// Returns the era for this date,
433        #[diplomat::rust_link(icu::calendar::Date::year, FnInStruct)]
434        #[diplomat::attr(supports = accessors, getter)]
435        pub fn era(
436            &self,
437            write: &mut diplomat_runtime::DiplomatWriteable,
438        ) -> Result<(), ICU4XError> {
439            let era = self.0.date.year().era;
440            write.write_str(&era.0)?;
441            Ok(())
442        }
443
444        /// Returns the number of months in the year represented by this date
445        #[diplomat::rust_link(icu::calendar::Date::months_in_year, FnInStruct)]
446        #[diplomat::attr(supports = accessors, getter)]
447        pub fn months_in_year(&self) -> u8 {
448            self.0.date.months_in_year()
449        }
450
451        /// Returns the number of days in the month represented by this date
452        #[diplomat::rust_link(icu::calendar::Date::days_in_month, FnInStruct)]
453        #[diplomat::attr(supports = accessors, getter)]
454        pub fn days_in_month(&self) -> u8 {
455            self.0.date.days_in_month()
456        }
457
458        /// Returns the number of days in the year represented by this date
459        #[diplomat::rust_link(icu::calendar::Date::days_in_year, FnInStruct)]
460        #[diplomat::attr(supports = accessors, getter)]
461        pub fn days_in_year(&self) -> u16 {
462            self.0.date.days_in_year()
463        }
464
465        /// Returns the [`ICU4XCalendar`] object backing this date
466        #[diplomat::rust_link(icu::calendar::Date::calendar, FnInStruct)]
467        #[diplomat::rust_link(icu::calendar::Date::calendar_wrapper, FnInStruct, hidden)]
468        #[diplomat::attr(supports = accessors, getter)]
469        pub fn calendar(&self) -> Box<ICU4XCalendar> {
470            Box::new(ICU4XCalendar(self.0.date.calendar_wrapper().clone()))
471        }
472    }
473}