use icu_locid::extensions::unicode::{key, value, Value}; use icu_locid::subtags::language; use icu_locid::Locale; use icu_provider::prelude::*;
use core::fmt;
/// This is a calendar that encompasses all formattable calendars supported by this crate /// /// This allows for the construction of [`Date`] objects that have their calendar known at runtime. /// /// This can be constructed by calling `.into()` on a concrete calendar type if the calendar type is known at /// compile time. When the type is known at runtime, the [`AnyCalendar::new()`] and sibling methods may be used. /// /// [`Date`] can also be converted to [`AnyCalendar`]-compatible ones /// via [`Date::to_any()`](crate::Date::to_any()). /// /// There are many ways of constructing an AnyCalendar'd date: /// ``` /// use icu::calendar::{AnyCalendar, DateTime, japanese::Japanese, Time}; /// use icu::locid::locale; /// # use std::rc::Rc; /// /// let locale = locale!("en-u-ca-japanese"); // English with the Japanese calendar /// /// let calendar = AnyCalendar::new_for_locale(&locale.into()); /// let calendar = Rc::new(calendar); // Avoid cloning it each time /// // If everything is a local reference, you may use icu::calendar::Ref instead. /// /// // manually construct a datetime in this calendar /// let manual_time = Time::try_new(12, 33, 12, 0).expect("failed to construct Time"); /// // construct from era code, year, month code, day, time, and a calendar /// // This is March 28, 15 Heisei /// let manual_datetime = DateTime::try_new_from_codes("heisei".parse().unwrap(), 15, "M03".parse().unwrap(), 28, /// manual_time, calendar.clone()) /// .expect("Failed to construct DateTime manually"); /// /// /// // construct another datetime by converting from ISO /// let iso_datetime = DateTime::try_new_iso_datetime(2020, 9, 1, 12, 34, 28) /// .expect("Failed to construct ISO DateTime."); /// let iso_converted = iso_datetime.to_calendar(calendar); /// /// // Construct a datetime in the appropriate typed calendar and convert /// let japanese_calendar = Japanese::new(); /// let japanese_datetime = DateTime::try_new_japanese_datetime("heisei".parse().unwrap(), 15, 3, 28, /// 12, 33, 12, japanese_calendar).unwrap(); /// // This is a DateTime<AnyCalendar> /// let any_japanese_datetime = japanese_datetime.to_any(); /// ``` #[derive(Debug)] #[non_exhaustive] pubenum AnyCalendar { /// A [`Buddhist`] calendar
Buddhist(Buddhist), /// A [`Chinese`] calendar
Chinese(Chinese), /// A [`Coptic`] calendar
Coptic(Coptic), /// A [`Dangi`] calendar
Dangi(Dangi), /// An [`Ethiopian`] calendar
Ethiopian(Ethiopian), /// A [`Gregorian`] calendar
Gregorian(Gregorian), /// A [`Hebrew`] calendar
Hebrew(Hebrew), /// An [`Indian`] calendar
Indian(Indian), /// An [`IslamicCivil`] calendar
IslamicCivil(IslamicCivil), /// An [`IslamicObservational`] calendar
IslamicObservational(IslamicObservational), /// An [`IslamicTabular`] calendar
IslamicTabular(IslamicTabular), /// An [`IslamicUmmAlQura`] calendar
IslamicUmmAlQura(IslamicUmmAlQura), /// An [`Iso`] calendar
Iso(Iso), /// A [`Japanese`] calendar
Japanese(Japanese), /// A [`JapaneseExtended`] calendar
JapaneseExtended(JapaneseExtended), /// A [`Persian`] calendar
Persian(Persian), /// A [`Roc`] calendar
Roc(Roc),
}
// TODO(#3469): Decide on the best way to implement Ord. /// The inner date type for [`AnyCalendar`] #[derive(Clone, PartialEq, Eq, Debug)] #[non_exhaustive] pubenum AnyDateInner { /// A date for a [`Buddhist`] calendar
Buddhist(<Buddhist as Calendar>::DateInner), /// A date for a [`Chinese`] calendar
Chinese(<Chinese as Calendar>::DateInner), /// A date for a [`Coptic`] calendar
Coptic(<Coptic as Calendar>::DateInner), /// A date for a [`Dangi`] calendar
Dangi(<Dangi as Calendar>::DateInner), /// A date for an [`Ethiopian`] calendar
Ethiopian(<Ethiopian as Calendar>::DateInner), /// A date for a [`Gregorian`] calendar
Gregorian(<Gregorian as Calendar>::DateInner), /// A date for a [`Hebrew`] calendar
Hebrew(<Hebrew as Calendar>::DateInner), /// A date for an [`Indian`] calendar
Indian(<Indian as Calendar>::DateInner), /// A date for an [`IslamicCivil`] calendar
IslamicCivil(<IslamicCivil as Calendar>::DateInner), /// A date for an [`IslamicObservational`] calendar
IslamicObservational(<IslamicObservational as Calendar>::DateInner), /// A date for an [`IslamicTabular`] calendar
IslamicTabular(<IslamicTabular as Calendar>::DateInner), /// A date for an [`IslamicUmmAlQura`] calendar
IslamicUmmAlQura(<IslamicUmmAlQura as Calendar>::DateInner), /// A date for an [`Iso`] calendar
Iso(<Iso as Calendar>::DateInner), /// A date for a [`Japanese`] calendar
Japanese(<Japanese as Calendar>::DateInner), /// A date for a [`JapaneseExtended`] calendar
JapaneseExtended(<JapaneseExtended as Calendar>::DateInner), /// A date for a [`Persian`] calendar
Persian(<Persian as Calendar>::DateInner), /// A date for a [`Roc`] calendar
Roc(<Roc as Calendar>::DateInner),
}
match_cal_and_date!(match (self, date1):
(c1, d1) => { let d2 = c1.date_from_iso(iso); let until = c1.until(d1, &d2, c1, largest_unit, smallest_unit);
until.cast_unit::<AnyCalendar>()
}
)
}
}
}
/// The calendar-specific year represented by `date` fn year(&self, date: &Self::DateInner) -> types::FormattableYear {
match_cal_and_date!(match (self, date): (c, d) => c.year(d))
}
/// The calendar-specific check if `date` is in a leap year fn is_in_leap_year(&self, date: &Self::DateInner) -> bool {
match_cal_and_date!(match (self, date): (c, d) => c.is_in_leap_year(d))
}
/// Information of the day of the year fn day_of_year_info(&self, date: &Self::DateInner) -> types::DayOfYearInfo {
match_cal_and_date!(match (self, date): (c, d) => c.day_of_year_info(d))
}
/// Constructs an AnyCalendar for a given calendar kind from compiled data. /// /// In case the locale's calendar is unknown or unspecified, it will attempt to load the default /// calendar for the locale, falling back to gregorian. /// /// ✨ *Enabled with the `compiled_data` Cargo feature.* /// /// [ Help choosing a constructor](icu_provider::constructors) #[cfg(feature = "compiled_data")] pubfn new_for_locale(locale: &DataLocale) -> Self { let kind = AnyCalendarKind::from_data_locale_with_fallback(locale); Self::new(kind)
}
/// The [`AnyCalendarKind`] corresponding to the calendar this contains pubfn kind(&self) -> AnyCalendarKind { match *self { Self::Buddhist(_) => AnyCalendarKind::Buddhist, Self::Chinese(_) => AnyCalendarKind::Chinese, Self::Coptic(_) => AnyCalendarKind::Coptic, Self::Dangi(_) => AnyCalendarKind::Dangi, #[allow(clippy::expect_used)] // Invariant known at compile time Self::Ethiopian(ref e) => e
.any_calendar_kind()
.expect("Ethiopian calendar known to have an AnyCalendarKind"), Self::Gregorian(_) => AnyCalendarKind::Gregorian, Self::Hebrew(_) => AnyCalendarKind::Hebrew, Self::Indian(_) => AnyCalendarKind::Indian, Self::IslamicCivil(_) => AnyCalendarKind::IslamicCivil, Self::IslamicObservational(_) => AnyCalendarKind::IslamicObservational, Self::IslamicTabular(_) => AnyCalendarKind::IslamicTabular, Self::IslamicUmmAlQura(_) => AnyCalendarKind::IslamicUmmAlQura, Self::Iso(_) => AnyCalendarKind::Iso, Self::Japanese(_) => AnyCalendarKind::Japanese, Self::JapaneseExtended(_) => AnyCalendarKind::JapaneseExtended, Self::Persian(_) => AnyCalendarKind::Persian, Self::Roc(_) => AnyCalendarKind::Roc,
}
}
/// Given an AnyCalendar date, convert that date to another AnyCalendar date in this calendar, /// if conversion is needed pubfn convert_any_date<'a>(
&'a self,
date: &Date<impl AsCalendar<Calendar = AnyCalendar>>,
) -> Date<Ref<'a, AnyCalendar>> { ifself.kind() != date.calendar.as_calendar().kind() {
Date::new_from_iso(date.to_iso(), Ref(self))
} else {
Date {
inner: date.inner.clone(),
calendar: Ref(self),
}
}
}
/// Given an AnyCalendar datetime, convert that date to another AnyCalendar datetime in this calendar, /// if conversion is needed pubfn convert_any_datetime<'a>(
&'a self,
date: &DateTime<impl AsCalendar<Calendar = AnyCalendar>>,
) -> DateTime<Ref<'a, AnyCalendar>> {
DateTime {
time: date.time,
date: self.convert_any_date(&date.date),
}
}
}
/// Convenient type for selecting the kind of AnyCalendar to construct #[non_exhaustive] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pubenum AnyCalendarKind { /// The kind of a [`Buddhist`] calendar
Buddhist, /// The kind of a [`Chinese`] calendar
Chinese, /// The kind of a [`Coptic`] calendar
Coptic, /// The kind of a [`Dangi`] calendar
Dangi, /// The kind of an [`Ethiopian`] calendar, with Amete Mihret era
Ethiopian, /// The kind of an [`Ethiopian`] calendar, with Amete Alem era
EthiopianAmeteAlem, /// The kind of a [`Gregorian`] calendar
Gregorian, /// The kind of a [`Hebrew`] calendar
Hebrew, /// The kind of a [`Indian`] calendar
Indian, /// The kind of an [`IslamicCivil`] calendar
IslamicCivil, /// The kind of an [`IslamicObservational`] calendar
IslamicObservational, /// The kind of an [`IslamicTabular`] calendar
IslamicTabular, /// The kind of an [`IslamicUmmAlQura`] calendar
IslamicUmmAlQura, /// The kind of an [`Iso`] calendar
Iso, /// The kind of a [`Japanese`] calendar
Japanese, /// The kind of a [`JapaneseExtended`] calendar
JapaneseExtended, /// The kind of a [`Persian`] calendar
Persian, /// The kind of a [`Roc`] calendar
Roc,
}
impl AnyCalendarKind { /// Construct from a BCP-47 string /// /// Returns `None` if the calendar is unknown. If you prefer an error, use /// [`CalendarError::unknown_any_calendar_kind`]. pubfn get_for_bcp47_string(x: &str) -> Option<Self> { Self::get_for_bcp47_bytes(x.as_bytes())
} /// Construct from a BCP-47 byte string /// /// Returns `None` if the calendar is unknown. If you prefer an error, use /// [`CalendarError::unknown_any_calendar_kind`]. pubfn get_for_bcp47_bytes(x: &[u8]) -> Option<Self> {
Some(match x {
b"buddhist" => AnyCalendarKind::Buddhist,
b"chinese" => AnyCalendarKind::Chinese,
b"coptic" => AnyCalendarKind::Coptic,
b"dangi" => AnyCalendarKind::Dangi,
b"ethioaa" => AnyCalendarKind::EthiopianAmeteAlem,
b"ethiopic" => AnyCalendarKind::Ethiopian,
b"gregory" => AnyCalendarKind::Gregorian,
b"hebrew" => AnyCalendarKind::Hebrew,
b"indian" => AnyCalendarKind::Indian,
b"islamic-civil" | b"islamicc" => AnyCalendarKind::IslamicCivil,
b"islamic-tbla" => AnyCalendarKind::IslamicTabular,
b"islamic-umalqura" => AnyCalendarKind::IslamicUmmAlQura,
b"islamic" => AnyCalendarKind::IslamicObservational,
b"iso" => AnyCalendarKind::Iso,
b"japanese" => AnyCalendarKind::Japanese,
b"japanext" => AnyCalendarKind::JapaneseExtended,
b"persian" => AnyCalendarKind::Persian,
b"roc" => AnyCalendarKind::Roc,
_ => { // Log a warning when a calendar value is passed in but doesn't match any calendars
DataError::custom("bcp47_bytes did not match any calendars").with_debug_context(x); return None;
}
})
} /// Construct from a BCP-47 [`Value`] /// /// Returns `None` if the calendar is unknown. If you prefer an error, use /// [`CalendarError::unknown_any_calendar_kind`]. pubfn get_for_bcp47_value(x: &Value) -> Option<Self> { match *x.as_tinystr_slice() {
[first] if first == "buddhist" => Some(AnyCalendarKind::Buddhist),
[first] if first == "chinese" => Some(AnyCalendarKind::Chinese),
[first] if first == "coptic" => Some(AnyCalendarKind::Coptic),
[first] if first == "dangi" => Some(AnyCalendarKind::Dangi),
[first] if first == "ethioaa" => Some(AnyCalendarKind::EthiopianAmeteAlem),
[first] if first == "ethiopic" => Some(AnyCalendarKind::Ethiopian),
[first] if first == "gregory" => Some(AnyCalendarKind::Gregorian),
[first] if first == "hebrew" => Some(AnyCalendarKind::Hebrew),
[first] if first == "indian" => Some(AnyCalendarKind::Indian),
[first] if first == "islamic" => Some(AnyCalendarKind::IslamicObservational),
[first] if first == "islamicc" => Some(AnyCalendarKind::IslamicCivil),
[first, second] if first == "islamic" && second == "civil" => {
Some(AnyCalendarKind::IslamicCivil)
}
[first, second] if first == "islamic" && second == "tbla" => {
Some(AnyCalendarKind::IslamicTabular)
}
[first, second] if first == "islamic" && second == "umalqura" => {
Some(AnyCalendarKind::IslamicUmmAlQura)
}
[first] if first == "iso" => Some(AnyCalendarKind::Iso),
[first] if first == "japanese" => Some(AnyCalendarKind::Japanese),
[first] if first == "japanext" => Some(AnyCalendarKind::JapaneseExtended),
[first] if first == "persian" => Some(AnyCalendarKind::Persian),
[first] if first == "roc" => Some(AnyCalendarKind::Roc),
_ => { // Log a warning when a calendar value is passed in but doesn't match any calendars
DataError::custom("bcp47_value did not match any calendars")
.with_display_context(x);
None
}
}
}
/// Extract the calendar component from a [`Locale`] /// /// Returns `None` if the calendar is not specified or unknown. If you prefer an error, use /// [`CalendarError::unknown_any_calendar_kind`]. pubfn get_for_locale(l: &Locale) -> Option<Self> {
l.extensions
.unicode
.keywords
.get(&key!("ca"))
.and_then(Self::get_for_bcp47_value)
}
/// Extract the calendar component from a [`DataLocale`] /// /// Returns `None` if the calendar is not specified or unknown. If you prefer an error, use /// [`CalendarError::unknown_any_calendar_kind`]. fn get_for_data_locale(l: &DataLocale) -> Option<Self> {
l.get_unicode_ext(&key!("ca"))
.and_then(|v| Self::get_for_bcp47_value(&v))
}
// Do not make public, this will eventually need fallback // data from the provider fn from_data_locale_with_fallback(l: &DataLocale) -> Self { iflet Some(kind) = Self::get_for_data_locale(l) {
kind
} else { let lang = l.language(); if lang == language!("th") { Self::Buddhist // Other known fallback routes for currently-unsupported calendars // } else if lang == language!("sa") { // Self::IslamicUmalqura // } else if lang == language!("af") || lang == language!("ir") { // Self::Persian
} else { Self::Gregorian
}
}
}
}
impl<C: IntoAnyCalendar> From<C> for AnyCalendar { fn from(c: C) -> AnyCalendar {
c.to_any()
}
}
/// Trait for calendars that may be converted to [`AnyCalendar`] pubtrait IntoAnyCalendar: Calendar + Sized { /// Convert this calendar into an [`AnyCalendar`], moving it /// /// You should not need to call this method directly fn to_any(self) -> AnyCalendar;
/// Convert this calendar into an [`AnyCalendar`], cloning it /// /// You should not need to call this method directly fn to_any_cloned(&self) -> AnyCalendar; /// Convert a date for this calendar into an [`AnyDateInner`] /// /// You should not need to call this method directly fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner;
}
#[cfg(test)] mod tests { usesuper::*; usecrate::Ref; use core::convert::TryInto;
fn single_test_roundtrip(
calendar: Ref<AnyCalendar>,
era: &str,
year: i32,
month_code: &str,
day: u8,
) { let era = types::Era(era.parse().expect("era must parse")); let month = types::MonthCode(month_code.parse().expect("month code must parse"));
let date = Date::try_new_from_codes(era, year, month, day, calendar).unwrap_or_else(|e| {
panic!( "Failed to construct date for {} with {:?}, {}, {}, {}: {}",
calendar.debug_name(),
era,
year,
month,
day,
e,
)
});
let roundtrip_year = date.year(); let roundtrip_era = roundtrip_year.era; let roundtrip_year = roundtrip_year.number; let roundtrip_month = date.month().code; let roundtrip_day = date.day_of_month().0.try_into().expect("Must fit in u8");
assert_eq!(
(era, year, month, day),
(
roundtrip_era,
roundtrip_year,
roundtrip_month,
roundtrip_day
), "Failed to roundtrip for calendar {}",
calendar.debug_name()
);
let iso = date.to_iso(); let reconstructed = Date::new_from_iso(iso, calendar);
assert_eq!(
date, reconstructed, "Failed to roundtrip via iso with {era:?}, {year}, {month}, {day}"
)
}
fn single_test_error(
calendar: Ref<AnyCalendar>,
era: &str,
year: i32,
month_code: &str,
day: u8,
error: CalendarError,
) { let era = types::Era(era.parse().expect("era must parse")); let month = types::MonthCode(month_code.parse().expect("month code must parse"));
let date = Date::try_new_from_codes(era, year, month, day, calendar);
assert_eq!(
date,
Err(error), "Construction with {era:?}, {year}, {month}, {day} did not return {error:?}"
)
}
#[test] fn test_any_construction() { let buddhist = AnyCalendar::new(AnyCalendarKind::Buddhist); let chinese = AnyCalendar::new(AnyCalendarKind::Chinese); let coptic = AnyCalendar::new(AnyCalendarKind::Coptic); let dangi = AnyCalendar::new(AnyCalendarKind::Dangi); let ethioaa = AnyCalendar::new(AnyCalendarKind::EthiopianAmeteAlem); let ethiopian = AnyCalendar::new(AnyCalendarKind::Ethiopian); let gregorian = AnyCalendar::new(AnyCalendarKind::Gregorian); let hebrew = AnyCalendar::new(AnyCalendarKind::Hebrew); let indian = AnyCalendar::new(AnyCalendarKind::Indian); let islamic_civil: AnyCalendar = AnyCalendar::new(AnyCalendarKind::IslamicCivil); let islamic_observational: AnyCalendar =
AnyCalendar::new(AnyCalendarKind::IslamicObservational); let islamic_tabular: AnyCalendar = AnyCalendar::new(AnyCalendarKind::IslamicTabular); let islamic_umm_al_qura: AnyCalendar = AnyCalendar::new(AnyCalendarKind::IslamicUmmAlQura); let japanese = AnyCalendar::new(AnyCalendarKind::Japanese); let japanext = AnyCalendar::new(AnyCalendarKind::JapaneseExtended); let persian = AnyCalendar::new(AnyCalendarKind::Persian); let roc = AnyCalendar::new(AnyCalendarKind::Roc); let buddhist = Ref(&buddhist); let chinese = Ref(&chinese); let coptic = Ref(&coptic); let dangi = Ref(&dangi); let ethioaa = Ref(ðioaa); let ethiopian = Ref(ðiopian); let gregorian = Ref(&gregorian); let hebrew = Ref(&hebrew); let indian = Ref(&indian); let islamic_civil = Ref(&islamic_civil); let islamic_observational = Ref(&islamic_observational); let islamic_tabular = Ref(&islamic_tabular); let islamic_umm_al_qura = Ref(&islamic_umm_al_qura); let japanese = Ref(&japanese); let japanext = Ref(&japanext); let persian = Ref(&persian); let roc = Ref(&roc);
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.24Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-06-20)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.