use std::time::SystemTime; use chrono::{DateTime, Datelike, NaiveDate, NaiveTime, Timelike, Utc}; #[derive(Debug)] pub struct Date { repr: u16, } impl Date { pub fn new(repr: u16) -> anyhow::Result { let date = Date { repr }; anyhow::ensure!(date.day() <= 31, "invalid day for date: {} (0x{:#X})", date.day(), repr); anyhow::ensure!( date.month() <= 12, "invalid month for date: {} (0x{:#X})", date.month(), repr ); Ok(date) } #[allow(dead_code)] pub fn from_day_month_year(day: u8, month: u8, year: u16) -> anyhow::Result { anyhow::ensure!(day <= 31, "invalid day: {}", day); anyhow::ensure!(month <= 12, "invalid month: {}", month); anyhow::ensure!(1980 <= year && year <= 2107, "invalid year: {}", year); let repr = day as u16 | (month as u16) << 4 | (year - 1980) << 8; Ok(Date { repr }) } #[allow(dead_code)] pub fn from_system_time(time: SystemTime) -> anyhow::Result { let datetime: DateTime = time.into(); let date = datetime.date_naive(); Date::from_day_month_year( date.day() as u8, date.month0() as u8 + 1, date.year_ce().1 as u16, ) } pub fn day(&self) -> u8 { (self.repr & 0x1F) as u8 } pub fn month(&self) -> u8 { ((self.repr & 0x1E0) >> 5) as u8 } pub fn year(&self) -> u16 { ((self.repr & 0xFE00) >> 9) as u16 + 1980 } pub fn to_naive_date(&self) -> NaiveDate { NaiveDate::from_ymd_opt(self.year() as i32, self.month() as u32, self.day() as u32).unwrap() } } #[derive(Debug)] pub struct Time { repr: u16, } impl Time { pub fn new(time: u16) -> anyhow::Result