use crate::LunarError;
use crate::stem_branch::EarthlyBranch;
pub fn time_index(hour: u8, minute: u8) -> Result<u8, LunarError> {
if hour > 23 || minute > 59 {
return Err(LunarError::InvalidTime { hour, minute });
}
let index = match hour {
0 => 0,
1 | 2 => 1,
3 | 4 => 2,
5 | 6 => 3,
7 | 8 => 4,
9 | 10 => 5,
11 | 12 => 6,
13 | 14 => 7,
15 | 16 => 8,
17 | 18 => 9,
19 | 20 => 10,
21 | 22 => 11,
23 => 12,
_ => unreachable!(),
};
Ok(index)
}
pub fn time_index_to_branch(time_index: u8) -> Result<EarthlyBranch, LunarError> {
if time_index > 12 {
return Err(LunarError::InvalidTimeIndex { time_index });
}
Ok(EarthlyBranch::from_index((time_index % 12) as usize))
}
pub fn is_early_zi(time_index: u8) -> Result<bool, LunarError> {
if time_index > 12 {
return Err(LunarError::InvalidTimeIndex { time_index });
}
Ok(time_index == 0)
}
pub fn is_late_zi(time_index: u8) -> Result<bool, LunarError> {
if time_index > 12 {
return Err(LunarError::InvalidTimeIndex { time_index });
}
Ok(time_index == 12)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn branch_maps_both_zi_halves_to_zi() {
assert_eq!(time_index_to_branch(0).unwrap(), EarthlyBranch::Zi);
assert_eq!(time_index_to_branch(12).unwrap(), EarthlyBranch::Zi);
}
#[test]
fn branch_maps_intermediate_indices() {
assert_eq!(time_index_to_branch(1).unwrap(), EarthlyBranch::Chou);
assert_eq!(time_index_to_branch(6).unwrap(), EarthlyBranch::Wu);
assert_eq!(time_index_to_branch(11).unwrap(), EarthlyBranch::Hai);
}
#[test]
fn early_and_late_zi_predicates() {
assert!(is_early_zi(0).unwrap());
assert!(!is_early_zi(12).unwrap());
assert!(is_late_zi(12).unwrap());
assert!(!is_late_zi(0).unwrap());
}
#[test]
fn invalid_time_index_is_rejected() {
assert_eq!(
time_index_to_branch(13),
Err(LunarError::InvalidTimeIndex { time_index: 13 })
);
assert_eq!(
is_early_zi(13),
Err(LunarError::InvalidTimeIndex { time_index: 13 })
);
assert_eq!(
is_late_zi(13),
Err(LunarError::InvalidTimeIndex { time_index: 13 })
);
}
}