//! This module contains types and implementations for the Korean Dangi calendar. //! //! ```rust //! use icu::calendar::dangi::Dangi; //! use icu::calendar::{Date, DateTime, Ref}; //! //! let dangi = Dangi::new(); //! let dangi = Ref(&dangi); // to avoid cloning //! //! // `Date` type //! let dangi_date = Date::try_new_dangi_date_with_calendar(4356, 6, 6, dangi) //! .expect("Failed to initialize Dangi Date instance."); //! //! // `DateTime` type //! let dangi_datetime = DateTime::try_new_dangi_datetime_with_calendar( //! 4356, 6, 6, 13, 1, 0, dangi, //! ) //! .expect("Failed to initialize Dangi DateTime instance."); //! //! // `Date` checks //! assert_eq!(dangi_date.year().number, 4356); //! assert_eq!(dangi_date.year().related_iso, Some(2023)); //! assert_eq!(dangi_date.year().cyclic.unwrap().get(), 40); //! assert_eq!(dangi_date.month().ordinal, 6); //! assert_eq!(dangi_date.day_of_month().0, 6); //! //! // `DateTime` checks //! assert_eq!(dangi_datetime.date.year().number, 4356); //! assert_eq!(dangi_datetime.date.year().related_iso, Some(2023)); //! assert_eq!(dangi_datetime.date.year().cyclic.unwrap().get(), 40); //! assert_eq!(dangi_datetime.date.month().ordinal, 6); //! assert_eq!(dangi_datetime.date.day_of_month().0, 6); //! assert_eq!(dangi_datetime.time.hour.number(), 13); //! assert_eq!(dangi_datetime.time.minute.number(), 1); //! assert_eq!(dangi_datetime.time.second.number(), 0); //! ```
usecrate::calendar_arithmetic::CalendarArithmetic; usecrate::calendar_arithmetic::PrecomputedDataSource; usecrate::chinese_based::{
chinese_based_ordinal_lunar_month_from_code, ChineseBasedPrecomputedData,
ChineseBasedWithDataLoading, ChineseBasedYearInfo,
}; usecrate::provider::chinese_based::DangiCacheV1Marker; usecrate::AsCalendar; usecrate::{
chinese_based::ChineseBasedDateInner,
types::{self, Era, FormattableYear},
AnyCalendarKind, Calendar, CalendarError, Date, DateTime, Iso, Time,
}; use core::cmp::Ordering; use core::num::NonZeroU8; use icu_provider::prelude::*; use tinystr::tinystr;
/// The Dangi Calendar /// /// The Dangi Calendar is a lunisolar calendar used traditionally in North and South Korea. /// It is often used today to track important cultural events and holidays like Seollal /// (Korean lunar new year). It is similar to the Chinese lunar calendar (see `Chinese`), /// except that observations are based in Korea (currently UTC+9) rather than China (UTC+8). /// This can cause some differences; for example, 2012 was a leap year, but in the Dangi /// calendar the leap month was 3, while in the Chinese calendar the leap month was 4. /// /// This calendar is currently in a preview state: formatting for this calendar is not /// going to be perfect. /// /// ```rust /// use icu::calendar::{chinese::Chinese, dangi::Dangi, Date}; /// use tinystr::tinystr; /// /// let iso_a = Date::try_new_iso_date(2012, 4, 23).unwrap(); /// let dangi_a = iso_a.to_calendar(Dangi::new()); /// let chinese_a = iso_a.to_calendar(Chinese::new()); /// /// assert_eq!(dangi_a.month().code.0, tinystr!(4, "M03L")); /// assert_eq!(chinese_a.month().code.0, tinystr!(4, "M04")); /// /// let iso_b = Date::try_new_iso_date(2012, 5, 23).unwrap(); /// let dangi_b = iso_b.to_calendar(Dangi::new()); /// let chinese_b = iso_b.to_calendar(Chinese::new()); /// /// assert_eq!(dangi_b.month().code.0, tinystr!(4, "M04")); /// assert_eq!(chinese_b.month().code.0, tinystr!(4, "M04L")); /// ``` /// # Era codes /// /// This Calendar supports a single era code "dangi" based on the year -2332 ISO (2333 BCE) as year 1. Typically /// years will be formatted using cyclic years and the related ISO year. /// /// # Month codes /// /// This calendar is a lunisolar calendar. It supports regular month codes `"M01" - "M12"` as well /// as leap month codes `"M01L" - "M12L"`. #[derive(Clone, Debug, Default)] pubstruct Dangi {
data: Option<DataPayload<DangiCacheV1Marker>>,
}
/// The inner date type used for representing [`Date`]s of [`Dangi`]. See [`Date`] and [`Dangi`] for more detail. #[derive(Debug, Eq, PartialEq, PartialOrd, Ord)] pubstruct DangiDateInner(ChineseBasedDateInner<Dangi>);
type Inner = ChineseBasedDateInner<Dangi>;
// we want these impls without the `C: Copy/Clone` bounds impl Copy for DangiDateInner {} impl Clone for DangiDateInner { fn clone(&self) -> Self {
*self
}
}
// These impls just make custom derives on types containing C // work. They're basically no-ops impl PartialEq for Dangi { fn eq(&self, _: &Self) -> bool { true
}
} impl Eq for Dangi {} #[allow(clippy::non_canonical_partial_ord_impl)] // this is intentional impl PartialOrd for Dangi { fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
Some(Ordering::Equal)
}
}
impl Ord for Dangi { fn cmp(&self, _: &Self) -> Ordering {
Ordering::Equal
}
}
impl Dangi { /// Creates a new [`Dangi`] with some precomputed calendrical calculations. /// /// ✨ *Enabled with the `compiled_data` Cargo feature.* /// /// [ Help choosing a constructor](icu_provider::constructors) #[cfg(feature = "compiled_data")] pubconstfn new() -> Self { Self {
data: Some(DataPayload::from_static_ref( crate::provider::Baked::SINGLETON_CALENDAR_DANGICACHE_V1,
)),
}
}
impl<A: AsCalendar<Calendar = Dangi>> Date<A> { /// Construct a new Dangi date from a `year`, `month`, and `day`. /// `year` represents the Chinese year counted infinitely with -2332 (2333 BCE) as year 1; /// `month` represents the month of the year ordinally (ex. if it is a leap year, the last month will be 13, not 12); /// `day` indicates day of month. /// /// This date will not use any precomputed calendrical calculations, /// one that loads such data from a provider will be added in the future (#3933) /// /// ```rust /// use icu::calendar::dangi::Dangi; /// use icu::calendar::Date; /// /// let dangi = Dangi::new(); /// /// let date_dangi = Date::try_new_dangi_date_with_calendar(4356, 6, 18, dangi) /// .expect("Failed to initialize Dangi Date instance."); /// /// assert_eq!(date_dangi.year().number, 4356); /// assert_eq!(date_dangi.year().cyclic.unwrap().get(), 40); /// assert_eq!(date_dangi.year().related_iso, Some(2023)); /// assert_eq!(date_dangi.month().ordinal, 6); /// assert_eq!(date_dangi.day_of_month().0, 18); /// ``` pubfn try_new_dangi_date_with_calendar(
year: i32,
month: u8,
day: u8,
calendar: A,
) -> Result<Date<A>, CalendarError> { let year_info = calendar
.as_calendar()
.get_precomputed_data()
.load_or_compute_info(year); let arithmetic = Inner::new_from_ordinals(year, month, day, year_info);
Ok(Date::from_raw(
DangiDateInner(ChineseBasedDateInner(arithmetic?)),
calendar,
))
}
}
impl<A: AsCalendar<Calendar = Dangi>> DateTime<A> { /// Construct a new Dangi DateTime from integers. See `try_new_dangi_date_with_calendar`. /// /// This datetime will not use any precomputed calendrical calculations, /// one that loads such data from a provider will be added in the future (#3933) /// /// ```rust /// use icu::calendar::dangi::Dangi; /// use icu::calendar::DateTime; /// /// let dangi = Dangi::new(); /// /// let dangi_datetime = DateTime::try_new_dangi_datetime_with_calendar( /// 4356, 6, 6, 13, 1, 0, dangi, /// ) /// .expect("Failed to initialize Dangi DateTime instance."); /// /// assert_eq!(dangi_datetime.date.year().number, 4356); /// assert_eq!(dangi_datetime.date.year().related_iso, Some(2023)); /// assert_eq!(dangi_datetime.date.year().cyclic.unwrap().get(), 40); /// assert_eq!(dangi_datetime.date.month().ordinal, 6); /// assert_eq!(dangi_datetime.date.day_of_month().0, 6); /// assert_eq!(dangi_datetime.time.hour.number(), 13); /// assert_eq!(dangi_datetime.time.minute.number(), 1); /// assert_eq!(dangi_datetime.time.second.number(), 0); /// ``` pubfn try_new_dangi_datetime_with_calendar(
year: i32,
month: u8,
day: u8,
hour: u8,
minute: u8,
second: u8,
calendar: A,
) -> Result<DateTime<A>, CalendarError> {
Ok(DateTime {
date: Date::try_new_dangi_date_with_calendar(year, month, day, calendar)?,
time: Time::try_new(hour, minute, second, 0)?,
})
}
}
type DangiCB = calendrical_calculations::chinese_based::Dangi; impl ChineseBasedWithDataLoading for Dangi { type CB = DangiCB; fn get_precomputed_data(&self) -> ChineseBasedPrecomputedData<Self::CB> {
ChineseBasedPrecomputedData::new(self.data.as_ref().map(|d| d.get()))
}
}
impl Dangi { /// Get a `FormattableYear` from an integer Dangi year; optionally, a `ChineseBasedYearInfo` /// can be passed in for faster results. fn format_dangi_year(
year: i32,
year_info_option: Option<ChineseBasedYearInfo>,
) -> FormattableYear { let era = Era(tinystr!(16, "dangi")); let number = year; // constant 364 from https://github.com/EdReingold/calendar-code2/blob/main/calendar.l#L5704 let cyclic = (number as i64 - 1 + 364).rem_euclid(60) as u8; let cyclic = NonZeroU8::new(cyclic + 1); // 1-indexed let rata_die_in_year = iflet Some(info) = year_info_option {
info.new_year::<DangiCB>(year)
} else {
Inner::fixed_mid_year_from_year(number)
}; let iso_formattable_year = Iso::iso_from_fixed(rata_die_in_year).year(); let related_iso = Some(iso_formattable_year.number);
types::FormattableYear {
era,
number,
cyclic,
related_iso,
}
}
}
#[cfg(test)] mod test {
usesuper::*; usecrate::chinese::Chinese; use calendrical_calculations::rata_die::RataDie;
/// Run a test twice, with two calendars fn do_twice(
dangi_calculating: &Dangi,
dangi_cached: &Dangi,
test: implFn(crate::Ref<Dangi>, &'static str),
) {
test(crate::Ref(dangi_calculating), "calculating");
test(crate::Ref(dangi_cached), "cached");
}
fn check_cyclic_and_rel_iso(year: i32) { let iso = Date::try_new_iso_date(year, 6, 6).unwrap(); let chinese = iso.to_calendar(Chinese::new_always_calculating()); let dangi = iso.to_calendar(Dangi::new_always_calculating()); let chinese_year = chinese.year().cyclic; let korean_year = dangi.year().cyclic;
assert_eq!(
chinese_year, korean_year, "Cyclic year failed for year: {year}"
); let chinese_rel_iso = chinese.year().related_iso; let korean_rel_iso = dangi.year().related_iso;
assert_eq!(
chinese_rel_iso, korean_rel_iso, "Rel. ISO year equality failed for year: {year}"
);
assert_eq!(korean_rel_iso, Some(year), "Dangi Rel. ISO failed!");
}
#[test] fn test_cyclic_same_as_chinese_near_present_day() { for year in1923..=2123 {
check_cyclic_and_rel_iso(year);
}
}
#[test] fn test_cyclic_same_as_chinese_near_rd_zero() { for year in -100..=100 {
check_cyclic_and_rel_iso(year);
}
}
#[test] fn test_iso_to_dangi_roundtrip() { letmut fixed = -1963020; let max_fixed = 1963020; letmut iters = 0; let max_iters = 560; let dangi_calculating = Dangi::new_always_calculating(); let dangi_cached = Dangi::new(); while fixed < max_fixed && iters < max_iters { let rata_die = RataDie::new(fixed); let iso = Iso::iso_from_fixed(rata_die);
do_twice(&dangi_calculating, &dangi_cached, |dangi, calendar_type| { let korean = iso.to_calendar(dangi); let result = korean.to_calendar(Iso);
assert_eq!(
iso, result, "[{calendar_type}] Failed roundtrip ISO -> Dangi -> ISO for fixed: {fixed}"
);
});
fixed += 7043;
iters += 1;
}
}
#[test] fn test_dangi_consistent_with_icu() { // Test cases for this test are derived from existing ICU Intl.DateTimeFormat. If there is a bug in ICU, // these test cases may be affected, and this calendar's output may not be entirely valid.
// There are a number of test cases which do not match ICU for dates very far in the past or future, // see #3709.
let dangi_calculating = Dangi::new_always_calculating(); let dangi_cached = Dangi::new();
for case in cases { let iso = Date::try_new_iso_date(case.iso_year, case.iso_month, case.iso_day).unwrap();
do_twice(&dangi_calculating, &dangi_cached, |dangi, calendar_type| { let dangi = iso.to_calendar(dangi); let dangi_rel_iso = dangi.year().related_iso; let dangi_cyclic = dangi.year().cyclic; let dangi_month = dangi.month().ordinal; let dangi_day = dangi.day_of_month().0;
assert_eq!(
dangi_rel_iso,
Some(case.expected_rel_iso), "[{calendar_type}] Related ISO failed for test case: {case:?}"
);
assert_eq!(
dangi_cyclic.unwrap().get(),
case.expected_cyclic, "[{calendar_type}] Cyclic year failed for test case: {case:?}"
);
assert_eq!(
dangi_month, case.expected_month, "[{calendar_type}] Month failed for test case: {case:?}"
);
assert_eq!(
dangi_day, case.expected_day, "[{calendar_type}] Day failed for test case: {case:?}"
);
});
}
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet am 2026-06-18)
¤
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.