date.rs (17157B)
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 use ffi::IsoWeekOfYear; 6 7 #[diplomat::bridge] 8 #[diplomat::abi_rename = "icu4x_{0}_mv1"] 9 #[diplomat::attr(auto, namespace = "icu4x")] 10 pub mod ffi { 11 use alloc::boxed::Box; 12 use alloc::sync::Arc; 13 use core::fmt::Write; 14 use icu_calendar::Iso; 15 16 use crate::unstable::calendar::ffi::Calendar; 17 use crate::unstable::errors::ffi::{CalendarError, Rfc9557ParseError}; 18 19 use tinystr::TinyAsciiStr; 20 21 #[diplomat::enum_convert(icu_calendar::types::Weekday)] 22 pub enum Weekday { 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 IsoDate(pub icu_calendar::Date<icu_calendar::Iso>); 36 37 impl IsoDate { 38 /// Creates a new [`IsoDate`] from the specified date. 39 #[diplomat::rust_link(icu::calendar::Date::try_new_iso, FnInStruct)] 40 #[diplomat::attr(supports = fallible_constructors, constructor)] 41 pub fn create(year: i32, month: u8, day: u8) -> Result<Box<IsoDate>, CalendarError> { 42 Ok(Box::new(IsoDate(icu_calendar::Date::try_new_iso( 43 year, month, day, 44 )?))) 45 } 46 47 /// Creates a new [`IsoDate`] from the given Rata Die 48 #[diplomat::rust_link(icu::calendar::Date::from_rata_die, FnInStruct)] 49 #[diplomat::attr(all(supports = named_constructors), named_constructor)] 50 #[diplomat::demo(default_constructor)] 51 pub fn from_rata_die(rd: i64) -> Box<IsoDate> { 52 Box::new(IsoDate(icu_calendar::Date::from_rata_die( 53 icu_calendar::types::RataDie::new(rd), 54 Iso, 55 ))) 56 } 57 58 /// Creates a new [`IsoDate`] from an IXDTF string. 59 #[diplomat::rust_link(icu::calendar::Date::try_from_str, FnInStruct)] 60 #[diplomat::rust_link(icu::calendar::Date::try_from_utf8, FnInStruct, hidden)] 61 #[diplomat::rust_link(icu::calendar::Date::from_str, FnInStruct, hidden)] 62 #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)] 63 pub fn from_string(v: &DiplomatStr) -> Result<Box<IsoDate>, Rfc9557ParseError> { 64 Ok(Box::new(IsoDate(icu_calendar::Date::try_from_utf8( 65 v, Iso, 66 )?))) 67 } 68 69 /// Convert this date to one in a different calendar 70 #[diplomat::rust_link(icu::calendar::Date::to_calendar, FnInStruct)] 71 pub fn to_calendar(&self, calendar: &Calendar) -> Box<Date> { 72 Box::new(Date(self.0.to_calendar(calendar.0.clone()))) 73 } 74 75 #[diplomat::rust_link(icu::calendar::Date::to_any, FnInStruct)] 76 pub fn to_any(&self) -> Box<Date> { 77 Box::new(Date(self.0.to_any().into_atomic_ref_counted())) 78 } 79 80 /// Returns this date's Rata Die 81 #[diplomat::rust_link(icu::calendar::Date::to_rata_die, FnInStruct)] 82 #[diplomat::attr(auto, getter = "rata_die")] 83 pub fn to_rata_die(&self) -> i64 { 84 self.0.to_rata_die().to_i64_date() 85 } 86 87 /// Returns the 1-indexed day in the year for this date 88 #[diplomat::rust_link(icu::calendar::Date::day_of_year, FnInStruct)] 89 #[diplomat::attr(auto, getter)] 90 pub fn day_of_year(&self) -> u16 { 91 self.0.day_of_year().0 92 } 93 94 /// Returns the 1-indexed day in the month for this date 95 #[diplomat::rust_link(icu::calendar::Date::day_of_month, FnInStruct)] 96 #[diplomat::attr(auto, getter)] 97 pub fn day_of_month(&self) -> u8 { 98 self.0.day_of_month().0 99 } 100 101 /// Returns the day in the week for this day 102 #[diplomat::rust_link(icu::calendar::Date::day_of_week, FnInStruct)] 103 #[diplomat::attr(auto, getter)] 104 pub fn day_of_week(&self) -> Weekday { 105 self.0.day_of_week().into() 106 } 107 108 /// Returns the week number in this year, using week data 109 #[diplomat::rust_link(icu::calendar::Date::week_of_year, FnInStruct)] 110 #[cfg(feature = "calendar")] 111 pub fn week_of_year(&self) -> IsoWeekOfYear { 112 self.0.week_of_year().into() 113 } 114 115 /// Returns 1-indexed number of the month of this date in its year 116 #[diplomat::rust_link(icu::calendar::types::MonthInfo::ordinal, StructField)] 117 #[diplomat::rust_link(icu::calendar::Date::month, FnInStruct, compact)] 118 #[diplomat::attr(auto, getter)] 119 pub fn month(&self) -> u8 { 120 self.0.month().ordinal 121 } 122 123 /// Returns the year number in the current era for this date 124 /// 125 /// For calendars without an era, returns the extended year 126 #[diplomat::rust_link(icu::calendar::Date::year, FnInStruct)] 127 #[diplomat::attr(auto, getter)] 128 pub fn year(&self) -> i32 { 129 self.0.extended_year() 130 } 131 132 /// Returns if the year is a leap year for this date 133 #[diplomat::rust_link(icu::calendar::Date::is_in_leap_year, FnInStruct)] 134 #[diplomat::attr(auto, getter)] 135 pub fn is_in_leap_year(&self) -> bool { 136 self.0.is_in_leap_year() 137 } 138 139 /// Returns the number of months in the year represented by this date 140 #[diplomat::rust_link(icu::calendar::Date::months_in_year, FnInStruct)] 141 #[diplomat::attr(auto, getter)] 142 pub fn months_in_year(&self) -> u8 { 143 self.0.months_in_year() 144 } 145 146 /// Returns the number of days in the month represented by this date 147 #[diplomat::rust_link(icu::calendar::Date::days_in_month, FnInStruct)] 148 #[diplomat::attr(auto, getter)] 149 pub fn days_in_month(&self) -> u8 { 150 self.0.days_in_month() 151 } 152 153 /// Returns the number of days in the year represented by this date 154 #[diplomat::rust_link(icu::calendar::Date::days_in_year, FnInStruct)] 155 #[diplomat::attr(auto, getter)] 156 pub fn days_in_year(&self) -> u16 { 157 self.0.days_in_year() 158 } 159 } 160 161 #[diplomat::opaque] 162 #[diplomat::transparent_convert] 163 /// An ICU4X Date object capable of containing a date for any calendar. 164 #[diplomat::rust_link(icu::calendar::Date, Struct)] 165 pub struct Date(pub icu_calendar::Date<Arc<icu_calendar::AnyCalendar>>); 166 167 impl Date { 168 /// Creates a new [`Date`] representing the ISO date 169 /// given but in a given calendar 170 #[diplomat::rust_link(icu::calendar::Date::new_from_iso, FnInStruct)] 171 #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)] 172 #[diplomat::demo(default_constructor)] 173 pub fn from_iso_in_calendar( 174 year: i32, 175 month: u8, 176 day: u8, 177 calendar: &Calendar, 178 ) -> Result<Box<Date>, CalendarError> { 179 let cal = calendar.0.clone(); 180 Ok(Box::new(Date( 181 icu_calendar::Date::try_new_iso(year, month, day)?.to_calendar(cal), 182 ))) 183 } 184 185 /// Creates a new [`Date`] from the given codes, which are interpreted in the given calendar system 186 /// 187 /// An empty era code will treat the year as an extended year 188 #[diplomat::rust_link(icu::calendar::Date::try_new_from_codes, FnInStruct)] 189 #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)] 190 pub fn from_codes_in_calendar( 191 era_code: &DiplomatStr, 192 year: i32, 193 month_code: &DiplomatStr, 194 day: u8, 195 calendar: &Calendar, 196 ) -> Result<Box<Date>, CalendarError> { 197 let era = if !era_code.is_empty() { 198 Some(core::str::from_utf8(era_code).map_err(|_| CalendarError::UnknownEra)?) 199 } else { 200 None 201 }; 202 let month = icu_calendar::types::MonthCode( 203 TinyAsciiStr::try_from_utf8(month_code) 204 .map_err(|_| CalendarError::UnknownMonthCode)?, 205 ); 206 let cal = calendar.0.clone(); 207 Ok(Box::new(Date(icu_calendar::Date::try_new_from_codes( 208 era, year, month, day, cal, 209 )?))) 210 } 211 212 /// Creates a new [`Date`] from the given Rata Die 213 #[diplomat::rust_link(icu::calendar::Date::from_rata_die, FnInStruct)] 214 #[diplomat::attr(all(supports = named_constructors), named_constructor)] 215 #[diplomat::demo(default_constructor)] 216 pub fn from_rata_die(rd: i64, calendar: &Calendar) -> Result<Box<Date>, CalendarError> { 217 let cal = calendar.0.clone(); 218 Ok(Box::new(Date(icu_calendar::Date::from_rata_die( 219 icu_calendar::types::RataDie::new(rd), 220 cal, 221 )))) 222 } 223 224 /// Creates a new [`Date`] from an IXDTF string. 225 #[diplomat::rust_link(icu::calendar::Date::try_from_str, FnInStruct)] 226 #[diplomat::rust_link(icu::calendar::Date::try_from_utf8, FnInStruct, hidden)] 227 #[diplomat::rust_link(icu::calendar::Date::from_str, FnInStruct, hidden)] 228 #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)] 229 pub fn from_string( 230 v: &DiplomatStr, 231 calendar: &Calendar, 232 ) -> Result<Box<Date>, Rfc9557ParseError> { 233 Ok(Box::new(Date(icu_calendar::Date::try_from_utf8( 234 v, 235 calendar.0.clone(), 236 )?))) 237 } 238 239 /// Convert this date to one in a different calendar 240 #[diplomat::rust_link(icu::calendar::Date::to_calendar, FnInStruct)] 241 #[diplomat::rust_link(icu::calendar::Date::convert_any, FnInStruct, hidden)] 242 pub fn to_calendar(&self, calendar: &Calendar) -> Box<Date> { 243 Box::new(Date(self.0.to_calendar(calendar.0.clone()))) 244 } 245 246 /// Converts this date to ISO 247 #[diplomat::rust_link(icu::calendar::Date::to_iso, FnInStruct)] 248 pub fn to_iso(&self) -> Box<IsoDate> { 249 Box::new(IsoDate(self.0.to_iso())) 250 } 251 252 /// Returns this date's Rata Die 253 #[diplomat::rust_link(icu::calendar::Date::to_rata_die, FnInStruct)] 254 #[diplomat::attr(auto, getter = "rata_die")] 255 pub fn to_rata_die(&self) -> i64 { 256 self.0.to_rata_die().to_i64_date() 257 } 258 259 /// Returns the 1-indexed day in the year for this date 260 #[diplomat::rust_link(icu::calendar::Date::day_of_year, FnInStruct)] 261 #[diplomat::attr(auto, getter)] 262 pub fn day_of_year(&self) -> u16 { 263 self.0.day_of_year().0 264 } 265 266 /// Returns the 1-indexed day in the month for this date 267 #[diplomat::rust_link(icu::calendar::Date::day_of_month, FnInStruct)] 268 #[diplomat::attr(auto, getter)] 269 pub fn day_of_month(&self) -> u8 { 270 self.0.day_of_month().0 271 } 272 273 /// Returns the day in the week for this day 274 #[diplomat::rust_link(icu::calendar::Date::day_of_week, FnInStruct)] 275 #[diplomat::attr(auto, getter)] 276 pub fn day_of_week(&self) -> Weekday { 277 self.0.day_of_week().into() 278 } 279 280 /// Returns 1-indexed number of the month of this date in its year 281 /// 282 /// Note that for lunar calendars this may not lead to the same month 283 /// having the same ordinal month across years; use month_code if you care 284 /// about month identity. 285 #[diplomat::rust_link(icu::calendar::Date::month, FnInStruct)] 286 #[diplomat::rust_link(icu::calendar::types::MonthInfo::ordinal, StructField)] 287 #[diplomat::attr(auto, getter)] 288 pub fn ordinal_month(&self) -> u8 { 289 self.0.month().ordinal 290 } 291 292 /// Returns the month code for this date. Typically something 293 /// like "M01", "M02", but can be more complicated for lunar calendars. 294 #[diplomat::rust_link(icu::calendar::types::MonthInfo::standard_code, StructField)] 295 #[diplomat::rust_link(icu::calendar::Date::month, FnInStruct, compact)] 296 #[diplomat::rust_link(icu::calendar::types::MonthInfo, Struct, hidden)] 297 #[diplomat::rust_link( 298 icu::calendar::types::MonthInfo::formatting_code, 299 StructField, 300 hidden 301 )] 302 #[diplomat::rust_link(icu::calendar::types::MonthInfo, Struct, hidden)] 303 #[diplomat::attr(auto, getter)] 304 pub fn month_code(&self, write: &mut diplomat_runtime::DiplomatWrite) { 305 let code = self.0.month().standard_code; 306 let _infallible = write.write_str(&code.0); 307 } 308 309 /// Returns the month number of this month. 310 #[diplomat::rust_link(icu::calendar::types::MonthInfo::month_number, FnInStruct)] 311 #[diplomat::attr(auto, getter)] 312 pub fn month_number(&self) -> u8 { 313 self.0.month().month_number() 314 } 315 316 /// Returns whether the month is a leap month. 317 #[diplomat::rust_link(icu::calendar::types::MonthInfo::is_leap, FnInStruct)] 318 #[diplomat::attr(auto, getter)] 319 pub fn month_is_leap(&self) -> bool { 320 self.0.month().is_leap() 321 } 322 323 /// Returns the year number in the current era for this date 324 /// 325 /// For calendars without an era, returns the related ISO year. 326 #[diplomat::rust_link(icu::calendar::types::YearInfo::era_year_or_related_iso, FnInEnum)] 327 #[diplomat::rust_link(icu::calendar::types::EraYear::year, StructField, compact)] 328 #[diplomat::rust_link(icu::calendar::types::CyclicYear::related_iso, StructField, compact)] 329 #[diplomat::rust_link(icu::calendar::Date::year, FnInStruct, compact)] 330 #[diplomat::rust_link(icu::calendar::Date::era_year, FnInStruct, hidden)] 331 #[diplomat::rust_link(icu::calendar::Date::cyclic_year, FnInStruct, hidden)] 332 #[diplomat::rust_link(icu::calendar::types::YearInfo, Enum, hidden)] 333 #[diplomat::rust_link(icu::calendar::types::YearInfo::era, FnInEnum, hidden)] 334 #[diplomat::rust_link(icu::calendar::types::YearInfo::cyclic, FnInEnum, hidden)] 335 #[diplomat::rust_link(icu::calendar::types::EraYear, Struct, hidden)] 336 #[diplomat::rust_link(icu::calendar::types::CyclicYear, Struct, hidden)] 337 #[diplomat::attr(auto, getter)] 338 pub fn era_year_or_related_iso(&self) -> i32 { 339 self.0.year().era_year_or_related_iso() 340 } 341 342 /// Returns the extended year in the Date 343 #[diplomat::rust_link(icu::calendar::Date::extended_year, FnInStruct)] 344 #[diplomat::attr(auto, getter)] 345 pub fn extended_year(&self) -> i32 { 346 self.0.extended_year() 347 } 348 349 /// Returns the era for this date, or an empty string 350 #[diplomat::rust_link(icu::calendar::types::EraYear::era, StructField)] 351 #[diplomat::rust_link(icu::calendar::Date::year, FnInStruct, compact)] 352 #[diplomat::attr(auto, getter)] 353 pub fn era(&self, write: &mut diplomat_runtime::DiplomatWrite) { 354 if let Some(era) = self.0.year().era() { 355 let _infallible = write.write_str(&era.era); 356 } 357 } 358 359 /// Returns the number of months in the year represented by this date 360 #[diplomat::rust_link(icu::calendar::Date::months_in_year, FnInStruct)] 361 #[diplomat::attr(auto, getter)] 362 pub fn months_in_year(&self) -> u8 { 363 self.0.months_in_year() 364 } 365 366 /// Returns the number of days in the month represented by this date 367 #[diplomat::rust_link(icu::calendar::Date::days_in_month, FnInStruct)] 368 #[diplomat::attr(auto, getter)] 369 pub fn days_in_month(&self) -> u8 { 370 self.0.days_in_month() 371 } 372 373 /// Returns the number of days in the year represented by this date 374 #[diplomat::rust_link(icu::calendar::Date::days_in_year, FnInStruct)] 375 #[diplomat::attr(auto, getter)] 376 pub fn days_in_year(&self) -> u16 { 377 self.0.days_in_year() 378 } 379 380 /// Returns the [`Calendar`] object backing this date 381 #[diplomat::rust_link(icu::calendar::Date::calendar, FnInStruct)] 382 #[diplomat::rust_link(icu::calendar::Date::calendar_wrapper, FnInStruct, hidden)] 383 #[diplomat::attr(auto, getter)] 384 pub fn calendar(&self) -> Box<Calendar> { 385 Box::new(Calendar(self.0.calendar_wrapper().clone())) 386 } 387 } 388 389 pub struct IsoWeekOfYear { 390 pub week_number: u8, 391 pub iso_year: i32, 392 } 393 } 394 395 impl From<icu_calendar::types::IsoWeekOfYear> for IsoWeekOfYear { 396 fn from( 397 icu_calendar::types::IsoWeekOfYear { 398 week_number, 399 iso_year, 400 }: icu_calendar::types::IsoWeekOfYear, 401 ) -> Self { 402 Self { 403 week_number, 404 iso_year, 405 } 406 } 407 }