// SPDX-License-Identifier: MPL-2.0 use core::time::Duration; use aster_time::{read_monotonic_time, read_start_time}; use spin::Once; use time::{Date, Month, PrimitiveDateTime, Time}; use crate::prelude::*; /// This struct corresponds to `SystemTime` in Rust std. #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct SystemTime(PrimitiveDateTime); pub static START_TIME: Once = Once::new(); pub(super) static START_TIME_AS_DURATION: Once = Once::new(); pub(super) fn init() { let start_time = convert_system_time(read_start_time()).unwrap(); START_TIME_AS_DURATION .call_once(|| start_time.duration_since(&SystemTime::UNIX_EPOCH).unwrap()); START_TIME.call_once(|| start_time); } impl SystemTime { /// The unix epoch, which represents 1970-01-01 00:00:00 pub const UNIX_EPOCH: SystemTime = SystemTime::unix_epoch(); const fn unix_epoch() -> Self { // 1970-01-01 00:00:00 let Ok(date) = Date::from_ordinal_date(1970, 1) else { unreachable!() }; let Ok(time) = Time::from_hms_nano(0, 0, 0, 0) else { unreachable!() }; SystemTime(PrimitiveDateTime::new(date, time)) } /// Returns the current system time pub fn now() -> Self { // The get real time result should always be valid START_TIME .get() .unwrap() .checked_add(read_monotonic_time()) .unwrap() } /// Add a duration to self. If the result does not exceed inner bounds return Some(t), else return None. pub fn checked_add(&self, duration: Duration) -> Option { let duration = convert_to_time_duration(duration); self.0.checked_add(duration).map(SystemTime) } /// Subtract a duration from self. If the result does not exceed inner bounds return Some(t), else return None. pub fn checked_sub(&self, duration: Duration) -> Option { let duration = convert_to_time_duration(duration); self.0.checked_sub(duration).map(SystemTime) } /// Returns the duration since an earlier time. Return error if `earlier` is later than self. pub fn duration_since(&self, earlier: &SystemTime) -> Result { if self.0 < earlier.0 { return_errno_with_message!( Errno::EINVAL, "duration_since can only accept an earlier time" ); } let duration = self.0 - earlier.0; Ok(convert_to_core_duration(duration)) } /// Return the difference between current time and the time when self was created. /// Return Error if current time is earlier than creating time. /// The error can happen if self was created by checked_add. pub fn elapsed(&self) -> Result { let now = SystemTime::now(); now.duration_since(self) } } /// convert ostd::time::Time to System time fn convert_system_time(system_time: aster_time::SystemTime) -> Result { let month = match Month::try_from(system_time.month) { Ok(month) => month, Err(_) => return_errno_with_message!(Errno::EINVAL, "unknown month in system time"), }; let date = match Date::from_calendar_date(system_time.year as _, month, system_time.day) { Ok(date) => date, Err(_) => return_errno_with_message!(Errno::EINVAL, "Invalid system date"), }; let time_ = match Time::from_hms_nano( system_time.hour, system_time.minute, system_time.second, system_time.nanos.try_into().unwrap(), ) { Ok(time_) => time_, Err(_) => return_errno_with_message!(Errno::EINVAL, "Invalid system time"), }; Ok(SystemTime(PrimitiveDateTime::new(date, time_))) } /// FIXME: need to further check precision loss /// convert core::time::Duration to time::Duration const fn convert_to_time_duration(duration: Duration) -> time::Duration { let seconds = duration.as_secs() as i64; let nanoseconds = duration.subsec_nanos() as i32; time::Duration::new(seconds, nanoseconds) } /// FIXME: need to further check precision loss /// convert time::Duration to core::time::Duration const fn convert_to_core_duration(duration: time::Duration) -> Duration { let seconds = duration.whole_seconds() as u64; let nanoseconds = duration.subsec_nanoseconds() as u32; Duration::new(seconds, nanoseconds) }