use crate::duration::Duration;
use std::fmt;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Time {
pub hour: u8,
pub minute: u8,
pub second: u8,
pub millisecond: u16,
}
impl Time {
pub const MIDNIGHT: Time = Time {
hour: 0,
minute: 0,
second: 0,
millisecond: 0,
};
pub const NOON: Time = Time {
hour: 12,
minute: 0,
second: 0,
millisecond: 0,
};
pub const MAX: Time = Time {
hour: 23,
minute: 59,
second: 59,
millisecond: 999,
};
pub fn new(hour: u8, minute: u8, second: u8, millisecond: u16) -> Self {
Time {
hour,
minute,
second,
millisecond,
}
}
pub fn from_hms(hour: u8, minute: u8, second: u8) -> Self {
Time {
hour,
minute,
second,
millisecond: 0,
}
}
pub fn is_valid(&self) -> bool {
self.hour < 24 && self.minute < 60 && self.second < 60 && self.millisecond < 1000
}
pub fn total_seconds(&self) -> u32 {
self.hour as u32 * 3600 + self.minute as u32 * 60 + self.second as u32
}
pub fn total_millis(&self) -> u32 {
self.total_seconds() * 1000 + self.millisecond as u32
}
pub fn hour12(&self) -> (u8, bool) {
if self.hour == 0 {
(12, false)
} else if self.hour < 12 {
(self.hour, false)
} else if self.hour == 12 {
(12, true)
} else {
(self.hour - 12, true)
}
}
pub fn is_pm(&self) -> bool {
self.hour >= 12
}
}
impl fmt::Display for Time {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{:02}:{:02}:{:02}",
self.hour, self.minute, self.second
)
}
}
impl std::ops::Add<Duration> for Time {
type Output = Time;
fn add(self, delta: Duration) -> Time {
let total_ms = self.total_millis() as i64 + delta.total_millis();
let ms_per_day: i64 = 86_400_000;
let mut ms = total_ms % ms_per_day;
if ms < 0 {
ms += ms_per_day;
}
Time {
hour: (ms / 3_600_000 % 24) as u8,
minute: (ms / 60_000 % 60) as u8,
second: (ms / 1000 % 60) as u8,
millisecond: (ms % 1000) as u16,
}
}
}
impl std::ops::Sub<Duration> for Time {
type Output = Time;
fn sub(self, delta: Duration) -> Time {
self + Duration::new(-delta.secs, -delta.nanos)
}
}
impl std::ops::Sub<Time> for Time {
type Output = Duration;
fn sub(self, rhs: Time) -> Duration {
let diff_ms =
self.total_millis() as i64 - rhs.total_millis() as i64;
Duration::from_millis(diff_ms)
}
}