use crate::time::Duration; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct Instant(Duration); /// When a Timezone is specified, the stored Duration is in UTC. If timezone is unspecified, then /// the timezone is assumed to be in UTC. /// /// UEFI SystemTime is stored as Duration from 1900-01-01-00:00:00 with timezone -1440 as anchor #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct SystemTime(Duration); pub const UNIX_EPOCH: SystemTime = SystemTime::from_uefi(r_efi::efi::Time { year: 1970, month: 1, day: 1, hour: 0, minute: 0, second: 0, nanosecond: 0, timezone: 0, daylight: 0, pad1: 0, pad2: 0, }); const MAX_UEFI_TIME: SystemTime = SystemTime::from_uefi(r_efi::efi::Time { year: 9999, month: 12, day: 31, hour: 23, minute: 59, second: 59, nanosecond: 999_999_999, timezone: 1440, daylight: 0, pad1: 0, pad2: 0, }); impl Instant { pub fn now() -> Instant { // If we have a timestamp protocol, use it. if let Some(x) = instant_internal::timestamp_protocol() { return x; } if let Some(x) = instant_internal::platform_specific() { return x; } panic!("time not implemented on this platform") } pub fn checked_sub_instant(&self, other: &Instant) -> Option { self.0.checked_sub(other.0) } pub fn checked_add_duration(&self, other: &Duration) -> Option { Some(Instant(self.0.checked_add(*other)?)) } pub fn checked_sub_duration(&self, other: &Duration) -> Option { Some(Instant(self.0.checked_sub(*other)?)) } } impl SystemTime { pub(crate) const fn from_uefi(t: r_efi::efi::Time) -> Self { Self(system_time_internal::from_uefi(&t)) } #[expect(dead_code)] pub(crate) const fn to_uefi(self, timezone: i16, daylight: u8) -> Option { system_time_internal::to_uefi(&self.0, timezone, daylight) } pub fn now() -> SystemTime { system_time_internal::now() .unwrap_or_else(|| panic!("time not implemented on this platform")) } #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] pub const fn sub_time(&self, other: &SystemTime) -> Result { // FIXME: ok_or_else with const closures match self.0.checked_sub(other.0) { Some(duration) => Ok(duration), None => Err(other.0 - self.0), } } #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] pub const fn checked_add_duration(&self, other: &Duration) -> Option { let temp = self.0.checked_add(*other)?; // Check if can be represented in UEFI // FIXME: const PartialOrd let mut cmp = temp.as_secs() - MAX_UEFI_TIME.0.as_secs(); if cmp == 0 { cmp = temp.subsec_nanos() as u64 - MAX_UEFI_TIME.0.subsec_nanos() as u64; } if cmp <= 0 { Some(SystemTime(temp)) } else { None } } #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] pub const fn checked_sub_duration(&self, other: &Duration) -> Option { Some(SystemTime(self.0.checked_sub(*other)?)) } } pub(crate) mod system_time_internal { use r_efi::efi::{RuntimeServices, Time}; use super::super::helpers; use super::*; use crate::mem::MaybeUninit; use crate::ptr::NonNull; const SECS_IN_MINUTE: u64 = 60; const SECS_IN_HOUR: u64 = SECS_IN_MINUTE * 60; const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24; const TIMEZONE_DELTA: u64 = 1440 * SECS_IN_MINUTE; pub fn now() -> Option { let runtime_services: NonNull = helpers::runtime_services()?; let mut t: MaybeUninit