use super::calendar::LunarYear;
pub(crate) const FIRST_YEAR: i32 = 1900;
#[rustfmt::skip]
pub(crate) const LUNAR_YEARS: [(u32, u16, u8); 201] = [
(2415051, 0b1011011010010, 8), (2415435, 0b0011101010010, 0), (2415789, 0b0111010100101, 0), (2416144, 0b1011001001010, 5), (2416527, 0b0011001001011, 0), (2416881, 0b0101010011011, 0), (2417236, 0b1010101011010, 4), (2417620, 0b0010101101010, 0), (2417974, 0b0101101011001, 0), (2418329, 0b1011101010010, 2), (2418713, 0b0011101010010, 0), (2419067, 0b1101100100101, 6), (2419451, 0b0101100100101, 0), (2419805, 0b0101001001011, 0), (2420159, 0b1010010101011, 5), (2420543, 0b0001010101101, 0), (2420897, 0b0010101101011, 0), (2421252, 0b0101101101001, 2), (2421636, 0b0110110101001, 0), (2421991, 0b1110110010010, 7), (2422375, 0b0111010010010, 0), (2422729, 0b0110100100101, 0), (2423083, 0b1101001001101, 5), (2423467, 0b0101001010110, 0), (2423821, 0b0001010110110, 0), (2424175, 0b1010110110101, 4), (2424560, 0b0011011010100, 0), (2424914, 0b0111010101001, 0), (2425269, 0b1111010010010, 2), (2425653, 0b0111010010010, 0), (2426007, 0b0110100100110, 6), (2426390, 0b0010100101011, 0), (2426744, 0b0101001010111, 0), (2427099, 0b1001010110110, 5), (2427483, 0b0101101011010, 0), (2427838, 0b0011011010100, 0), (2428192, 0b0111011001001, 3), (2428576, 0b0011101001001, 0), (2428930, 0b1011010010011, 7), (2429314, 0b0101010010011, 0), (2429668, 0b0010100101011, 0), (2430022, 0b0101001011011, 6), (2430406, 0b0101010101101, 0), (2430761, 0b0010101101010, 0), (2431115, 0b1101101010101, 4), (2431500, 0b0101110100100, 0), (2431854, 0b0101101001001, 0), (2432208, 0b1101010010011, 2), (2432592, 0b0101010010101, 0), (2432946, 0b1010100101101, 7), (2433330, 0b0010100110110, 0), (2433684, 0b0101010101101, 0), (2434039, 0b1010110101010, 5), (2434423, 0b0010110110010, 0), (2434777, 0b0110110100101, 0), (2435132, 0b1110101001010, 3), (2435516, 0b0110101001010, 0), (2435870, 0b0101010010101, 8), (2436253, 0b0101010010111, 0), (2436608, 0b0010101010110, 0), (2436962, 0b0101010110101, 6), (2437346, 0b0101011010101, 0), (2437701, 0b0011011010010, 0), (2438055, 0b0111010100101, 4), (2438439, 0b0111010100101, 0), (2438794, 0b0011001001010, 0), (2439147, 0b0110010010111, 3), (2439531, 0b0101010011011, 0), (2439886, 0b1010101011010, 7), (2440270, 0b0010101101010, 0), (2440624, 0b0101101101001, 0), (2440979, 0b1011101010010, 5), (2441363, 0b0101101010010, 0), (2441717, 0b0101100100101, 0), (2442071, 0b1011001001011, 4), (2442455, 0b0101001001011, 0), (2442809, 0b1010010101011, 8), (2443193, 0b0001010101101, 0), (2443547, 0b0010101101101, 0), (2443902, 0b0101101101001, 6), (2444286, 0b0110110101001, 0), (2444641, 0b0110110010010, 0), (2444995, 0b1110100100101, 4), (2445379, 0b0110100100101, 0), (2445733, 0b1101001001101, 10), (2446117, 0b0101001010110, 0), (2446471, 0b0001010110110, 0), (2446825, 0b0010110110101, 6), (2447209, 0b0011011010101, 0), (2447564, 0b0111010101001, 0), (2447919, 0b1111010010010, 5), (2448303, 0b0111010010010, 0), (2448657, 0b0110100100110, 0), (2449011, 0b0101001010110, 3), (2449394, 0b0101001010111, 0), (2449749, 0b1010011010110, 8), (2450133, 0b0001101011010, 0), (2450487, 0b0011011010101, 0), (2450842, 0b1011011001001, 5), (2451226, 0b0011101001001, 0), (2451580, 0b0011010010011, 0), (2451934, 0b1010100101011, 4), (2452318, 0b0010100101011, 0), (2452672, 0b0101001011011, 0), (2453027, 0b1010101011010, 2), (2453411, 0b0010101101010, 0), (2453765, 0b1101101010101, 7), (2454150, 0b0101110100100, 0), (2454504, 0b0101101001001, 0), (2454858, 0b1101010010011, 5), (2455242, 0b0101010010101, 0), (2455596, 0b0010100101101, 0), (2455950, 0b0101010101101, 4), (2456334, 0b0101010110101, 0), (2456689, 0b1010110101010, 9), (2457073, 0b0010111010010, 0), (2457427, 0b0110110100101, 0), (2457782, 0b1110101001010, 6), (2458166, 0b0110101001010, 0), (2458520, 0b0110010010101, 0), (2458874, 0b1010100101110, 4), (2459258, 0b0010101010110, 0), (2459612, 0b0101010110101, 0), (2459967, 0b1010110110010, 2), (2460351, 0b0011011010010, 0), (2460705, 0b0111010100101, 6), (2461089, 0b0011100100101, 0), (2461443, 0b0011001001011, 0), (2461797, 0b0110010010111, 5), (2462181, 0b0110010101011, 0), (2462536, 0b0010101011010, 0), (2462890, 0b0101011010110, 3), (2463274, 0b0101101101001, 0), (2463629, 0b1011101010010, 11), (2464013, 0b0101101010010, 0), (2464367, 0b0101100100101, 0), (2464721, 0b1101001001011, 6), (2465105, 0b0101001001011, 0), (2465459, 0b0010010101011, 0), (2465813, 0b0010101011011, 5), (2466197, 0b0010110101101, 0), (2466552, 0b0101101101010, 0), (2466907, 0b1101101010010, 2), (2467291, 0b0110110010010, 0), (2467645, 0b1110100100101, 7), (2468029, 0b0110100100101, 0), (2468383, 0b0101001010101, 0), (2468737, 0b1010010101101, 5), (2469121, 0b0010010110110, 0), (2469475, 0b0010110110101, 0), (2469830, 0b0110110101010, 3), (2470214, 0b0111011001001, 0), (2470569, 0b1111010010010, 8), (2470953, 0b0111010010010, 0), (2471307, 0b0110100100110, 0), (2471661, 0b0101001010110, 6), (2472044, 0b0101001010111, 0), (2472399, 0b0010011010110, 0), (2472753, 0b0011011010101, 4), (2473137, 0b0011101010101, 0), (2473492, 0b0011101001001, 0), (2473846, 0b0111010010011, 3), (2474230, 0b0011010010011, 0), (2474584, 0b1010100101011, 7), (2474968, 0b0010100101011, 0), (2475322, 0b0101001011011, 0), (2475677, 0b1010101011010, 5), (2476061, 0b0010101101010, 0), (2476415, 0b0101101100101, 0), (2476770, 0b1011101001010, 4), (2477154, 0b0101101001010, 0), (2477508, 0b1101010010101, 8), (2477892, 0b0101010010101, 0), (2478246, 0b0010100101101, 0), (2478600, 0b0101010101101, 6), (2478984, 0b0101010110101, 0), (2479339, 0b0010110101010, 0), (2479693, 0b0101110100101, 4), (2480077, 0b0110110100101, 0), (2480432, 0b0110101001010, 0), (2480786, 0b1110010010101, 3), (2481170, 0b0110010010110, 0), (2481524, 0b1100101001110, 7), (2481908, 0b0010101010110, 0), (2482262, 0b0101010110101, 0), (2482617, 0b1010110110010, 5), (2483001, 0b0011011010010, 0), (2483355, 0b0111010100101, 0), (2483710, 0b0111001001010, 4), (2484093, 0b0011010001011, 0), (2484447, 0b0110010010111, 8), (2484831, 0b0010010101011, 0), (2485185, 0b0010101011011, 0), (2485540, 0b0101011010110, 6), (2485924, 0b0101101101010, 0), (2486279, 0b0011101010010, 0), (2486633, 0b1011100100101, 4), (2487017, 0b0101100100101, 0), (2487371, 0b0101010001011, 0), (2487725, 0b1010010011011, 2), (2488109, 0b0010010101011, 0), ];
fn year_at(index: usize) -> LunarYear {
let (start, mask, leap) = LUNAR_YEARS[index];
let count = if leap > 0 { 13 } else { 12 };
LunarYear {
year: FIRST_YEAR + index as i32,
start: i64::from(start),
days: (0..count)
.map(|i| if mask >> i & 1 == 1 { 30 } else { 29 })
.collect(),
leap,
}
}
pub(crate) fn lunar_date_of(day: i64) -> Option<(i32, u8, bool, u8)> {
let index = LUNAR_YEARS.partition_point(|row| i64::from(row.0) <= day);
let year = year_at(index.checked_sub(1)?);
let mut start = year.start;
let mut number = 0u8;
for (i, &days) in year.days.iter().enumerate() {
let leap = year.leap > 0 && i == usize::from(year.leap);
if !leap {
number += 1;
}
if day < start + i64::from(days) {
return Some((year.year, number, leap, (day - start + 1) as u8));
}
start += i64::from(days);
}
None
}
#[cfg(test)]
mod tests {
use super::*;
use crate::chinese::calendar::lunar_years;
use crate::test_kernel::full_kernel as kernels;
#[test]
#[ignore = "generates the table: cargo test --release print_table -- --ignored --nocapture"]
fn print_table() {
let kernels = kernels().expect("kernels/de440s.bsp");
for year in lunar_years(&kernels, FIRST_YEAR, 2100).unwrap() {
let mask: u16 = year
.days
.iter()
.enumerate()
.map(|(i, &d)| u16::from(d == 30) << i)
.sum();
println!(
" ({}, 0b{:013b}, {}), // {}",
year.start, mask, year.leap, year.year
);
}
}
#[test]
fn the_table_matches_the_calendar() {
let Some(kernels) = kernels() else { return };
let last = FIRST_YEAR + LUNAR_YEARS.len() as i32 - 1;
let computed = lunar_years(&kernels, FIRST_YEAR, last).unwrap();
for (i, year) in computed.iter().enumerate() {
assert_eq!(&year_at(i), year);
}
assert_eq!(LUNAR_YEARS.len(), 201);
}
#[test]
fn lunar_dates() {
assert_eq!(lunar_date_of(2_458_874), Some((2020, 1, false, 1)));
assert_eq!(lunar_date_of(2_460_045), Some((2023, 2, true, 20)));
assert_eq!(lunar_date_of(2_400_000), None);
}
}