From 914e82d66c996c18063b88fcd78a7174f6332178 Mon Sep 17 00:00:00 2001 From: Robert Bastian Date: Tue, 30 Sep 2025 21:12:52 +0200 Subject: [PATCH 1/2] reference algorithm --- components/calendar/src/cal/chinese.rs | 116 +++++++++++++++++++------ 1 file changed, 88 insertions(+), 28 deletions(-) diff --git a/components/calendar/src/cal/chinese.rs b/components/calendar/src/cal/chinese.rs index c6d3feda26d..01abaf02262 100644 --- a/components/calendar/src/cal/chinese.rs +++ b/components/calendar/src/cal/chinese.rs @@ -176,8 +176,7 @@ impl Rules for China { let Some((number, is_leap)) = month_code.parsed() else { return Err(DateError::UnknownMonthCode(month_code)); }; - // Computed via code from - // + // Computed by `generate_reference_years` let extended = match (number, is_leap, day > 29) { (1, false, false) => 1972, (1, false, true) => 1970, @@ -213,27 +212,23 @@ impl Rules for China { (8, true, true) => 1718, (9, false, false) => 1972, (9, false, true) => 1972, - (9, true, false) => 1832, + (9, true, false) => 2014, (9, true, true) => -5738, (10, false, false) => 1972, (10, false, true) => 1972, - (10, true, false) => 1870, + (10, true, false) => 1984, (10, true, true) => -4098, // Dec 31, 1972 is 1972-M11-26, dates after that // are in the next year (11, false, false) if day > 26 => 1971, (11, false, false) => 1972, (11, false, true) => 1969, - // Specced backwards-looking algorithm produces 1642, but - // 2033 is a better date with a forwards-looking algorithm. - // See - // Data from: (11, true, false) => 2033, (11, true, true) => -2173, (12, false, false) => 1971, (12, false, true) => 1971, - (12, true, false) => 1403, - (12, true, true) => -180, + // M12L not possible + (12, true, _) => return Err(DateError::InconsistentMonth), _ => return Err(DateError::UnknownMonthCode(month_code)), }; Ok(self.year_data(extended)) @@ -342,13 +337,7 @@ impl Rules for Dangi { let Some((number, is_leap)) = month_code.parsed() else { return Err(DateError::UnknownMonthCode(month_code)); }; - // Computed via code from - // - // - // Some (marked) dates use a forward looking algorithm from - // - // to produce a better in-range date. - // Code for that is + // Computed by `generate_reference_years` let extended = match (number, is_leap, day > 29) { (1, false, false) => 1972, (1, false, true) => 1970, @@ -359,7 +348,7 @@ impl Rules for Dangi { (2, true, false) => 1947, (2, true, true) => 1765, (3, false, false) => 1972, - (3, false, true) => 1968, + (3, false, true) => 1966, (3, true, false) => 1966, (3, true, true) => 1955, (4, false, false) => 1972, @@ -381,31 +370,26 @@ impl Rules for Dangi { (8, false, false) => 1972, (8, false, true) => 1971, (8, true, false) => 1957, - // Uses forward-looking algorithm (was: 1718) - (8, true, true) => 2052, + (8, true, true) => 1718, (9, false, false) => 1972, (9, false, true) => 1972, - // Uses forward-looking algorithm (was: 1832) - (9, true, false) => 1972, + (9, true, false) => 2014, (9, true, true) => -5738, (10, false, false) => 1972, (10, false, true) => 1972, - // Uses forward-looking algorithm (was: 1870) (10, true, false) => 1984, - (10, true, true) => -3946, + (10, true, true) => -4098, // Dec 31, 1972 is 1972-M11-26, dates after that // are in the next year (11, false, false) if day > 26 => 1971, (11, false, false) => 1972, (11, false, true) => 1969, - // Uses forward-looking algorithm (was: 1851) (11, true, false) => 2033, (11, true, true) => -2173, (12, false, false) => 1971, (12, false, true) => 1971, - (12, true, false) => 1889, - (12, true, true) => -1182, - + // M12L not possible + (12, true, _) => return Err(DateError::InconsistentMonth), _ => return Err(DateError::UnknownMonthCode(month_code)), }; Ok(self.year_data(extended)) @@ -2299,4 +2283,80 @@ mod test { ); } } + + #[test] + #[ignore] + fn generate_reference_years() { + use crate::Date; + let calendar = crate::cal::LunarChinese::new_dangi(); + let reference_year_end = Date::from_rata_die( + crate::cal::abstract_gregorian::LAST_DAY_OF_REFERENCE_YEAR, + calendar, + ); + let year_1900_start = Date::try_new_gregorian(1900, 1, 1) + .unwrap() + .to_calendar(calendar); + let year_2035_end = Date::try_new_gregorian(2035, 12, 31) + .unwrap() + .to_calendar(calendar); + for month in 1..=12 { + for leap in [false, true] { + if month == 12 && leap { + continue; + } + 'outer: for long in [false, true] { + for (start_year, start_month, end_year, end_month, by) in [ + ( + reference_year_end.extended_year(), + reference_year_end.month().month_number(), + year_1900_start.extended_year(), + year_1900_start.month().month_number(), + -1, + ), + ( + reference_year_end.extended_year(), + reference_year_end.month().month_number(), + year_2035_end.extended_year(), + year_2035_end.month().month_number(), + 1, + ), + ( + year_1900_start.extended_year(), + year_1900_start.month().month_number(), + -10000, + 1, + -1, + ), + ] { + let mut year = start_year; + while year * by < end_year * by { + if year == start_year && month as i32 * by < start_month as i32 * by + || year == end_year && month as i32 * by > end_month as i32 * by + { + year += by; + continue; + } + let data = China.year_data(year); + let leap_month = data.leap_month().unwrap_or(15); + let days_in_month = data.days_in_month({ + if leap && month + 1 == leap_month { + month + 1 + } else { + month + (month + 1 > leap_month) as u8 + } + }); + if (!long || (days_in_month == 30)) + && (!leap || month + 1 == leap_month) + { + println!("({month}, {leap:?}, {long:?}) => {year},"); + continue 'outer; + } + year += by; + } + } + println!("({month}, {leap:?}, {long:?}) => todo!(),") + } + } + } + } } From ca3b6df3067fbf6eecaa1b334b1ef4d6ed74bb94 Mon Sep 17 00:00:00 2001 From: Robert Bastian Date: Tue, 30 Sep 2025 21:57:32 +0200 Subject: [PATCH 2/2] ah --- components/calendar/src/cal/chinese.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/components/calendar/src/cal/chinese.rs b/components/calendar/src/cal/chinese.rs index 01abaf02262..9c20dc8da4a 100644 --- a/components/calendar/src/cal/chinese.rs +++ b/components/calendar/src/cal/chinese.rs @@ -227,8 +227,8 @@ impl Rules for China { (11, true, true) => -2173, (12, false, false) => 1971, (12, false, true) => 1971, - // M12L not possible - (12, true, _) => return Err(DateError::InconsistentMonth), + (12, true, false) => 1403, + (12, true, true) => -180, _ => return Err(DateError::UnknownMonthCode(month_code)), }; Ok(self.year_data(extended)) @@ -388,8 +388,8 @@ impl Rules for Dangi { (11, true, true) => -2173, (12, false, false) => 1971, (12, false, true) => 1971, - // M12L not possible - (12, true, _) => return Err(DateError::InconsistentMonth), + (12, true, false) => 1403, + (12, true, true) => -180, _ => return Err(DateError::UnknownMonthCode(month_code)), }; Ok(self.year_data(extended)) @@ -2288,7 +2288,7 @@ mod test { #[ignore] fn generate_reference_years() { use crate::Date; - let calendar = crate::cal::LunarChinese::new_dangi(); + let calendar = crate::cal::LunarChinese::new_china(); let reference_year_end = Date::from_rata_die( crate::cal::abstract_gregorian::LAST_DAY_OF_REFERENCE_YEAR, calendar, @@ -2301,9 +2301,6 @@ mod test { .to_calendar(calendar); for month in 1..=12 { for leap in [false, true] { - if month == 12 && leap { - continue; - } 'outer: for long in [false, true] { for (start_year, start_month, end_year, end_month, by) in [ (