use super::{Frame, ParseError};
pub use chrono::NaiveDateTime as DateTime;
impl TryFrom<Frame> for DateTime {
type Error = ParseError;
fn try_from(frame: Frame) -> Result<Self, Self::Error> {
const ID: u32 = 0x350;
const LEN: usize = 8;
if frame.id() != ID {
return Err(ParseError::Id { frame });
}
let data: [u8; LEN] = match frame.data().try_into() {
Ok(data) => data,
Err(_) => {
return Err(ParseError::Len {
frame,
expected: LEN,
})
}
};
let seconds = data[0];
let minutes = data[1];
let hours = data[2];
let year = u16::from_be_bytes([data[3], data[4]]);
let month = data[5];
let day = data[6];
let date = chrono::NaiveDate::from_ymd_opt(
year.into(),
month.into(),
day.into(),
)
.ok_or_else(|| ParseError::Data {
frame: frame.clone(),
detail: "invalid date".to_owned(),
})?;
let datetime = date
.and_hms_opt(hours.into(), minutes.into(), seconds.into())
.ok_or_else(|| ParseError::Data {
frame: frame.clone(),
detail: "invalid time".to_owned(),
})?;
Ok(datetime)
}
}
#[cfg(test)]
mod tests {
use super::{DateTime, Frame};
use chrono::{Datelike, Timelike};
#[test]
fn test_correct_time() {
let frame =
Frame::from_id_data_len(0x350, [7, 34, 13, 7, 231, 1, 11, 1], 8)
.unwrap();
let dt = DateTime::try_from(frame).unwrap();
assert_eq!(dt.year(), 2023);
assert_eq!(dt.month(), 1);
assert_eq!(dt.day(), 11);
assert_eq!(dt.hour(), 13);
assert_eq!(dt.second(), 7);
}
}