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 ).
9 use core::convert::TryInto;
12 use icu_calendar::{AnyCalendar, DateTime, Iso, Time};
13 use tinystr::TinyAsciiStr;
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;
20 #[cfg(feature = "icu_calendar")]
21 use crate::week::ffi::ICU4XWeekCalculator;
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>);
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)]
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)))
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(
52 ) -> Box<ICU4XIsoDateTime> {
53 let dt = DateTime::new(date.0, time.0);
54 Box::new(ICU4XIsoDateTime(dt))
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))
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,
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),
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))
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))
91 /// Converts this to an [`ICU4XDateTime`] capable of being mixed with dates of
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()))
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()
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())))
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()
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()
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()
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()
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
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
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()
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).
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,
168 pub fn week_of_month(&self, first_weekday: ICU4XIsoWeekday) -> u32 {
169 self.0.date.week_of_month(first_weekday.into()).0
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,
179 #[cfg(feature = "icu_calendar")]
182 calculator: &ICU4XWeekCalculator,
183 ) -> Result<crate::week::ffi::ICU4XWeekOf, ICU4XError> {
184 Ok(self.0.date.week_of_year(&calculator.0)?.into())
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
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
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()
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()
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()
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()
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>>);
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(
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))))
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,
263 month_code: &DiplomatStr,
269 calendar: &ICU4XCalendar,
270 ) -> Result<Box<ICU4XDateTime>, ICU4XError> {
271 let era = TinyAsciiStr::from_bytes(era_code)
272 .map_err(|_| ICU4XError::CalendarUnknownEraError)?
274 let month = TinyAsciiStr::from_bytes(month_code)
275 .map_err(|_| ICU4XError::CalendarUnknownMonthCodeError)?
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()?;
288 Ok(Box::new(ICU4XDateTime(DateTime::try_new_from_codes(
289 era, year, month, day, time, cal,
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))
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()))
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))
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()))
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())))
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()
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()
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()
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()
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
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
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()
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).
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,
382 pub fn week_of_month(&self, first_weekday: ICU4XIsoWeekday) -> u32 {
383 self.0.date.week_of_month(first_weekday.into()).0
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,
393 #[cfg(feature = "icu_calendar")]
396 calculator: &ICU4XWeekCalculator,
397 ) -> Result<crate::week::ffi::ICU4XWeekOf, ICU4XError> {
398 Ok(self.0.date.week_of_year(&calculator.0)?.into())
401 /// Returns 1-indexed number of the month of this date in its year
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
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)]
418 write: &mut diplomat_runtime::DiplomatWriteable,
419 ) -> Result<(), ICU4XError> {
420 let code = self.0.date.month().code;
421 write.write_str(&code.0)?;
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
432 /// Returns the era for this date,
433 #[diplomat::rust_link(icu::calendar::Date::year, FnInStruct)]
434 #[diplomat::attr(supports = accessors, getter)]
437 write: &mut diplomat_runtime::DiplomatWriteable,
438 ) -> Result<(), ICU4XError> {
439 let era = self.0.date.year().era;
440 write.write_str(&era.0)?;
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()
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()
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()
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()))