Skip to content
12 changes: 12 additions & 0 deletions library/std/src/sys/pal/hermit/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ struct Timespec {
}

impl Timespec {
#[unstable(feature = "time_systemtime_limits", issue = "none")]
const MAX: Timespec = Self::new(i64::MAX, 1_000_000_000 - 1);

#[unstable(feature = "time_systemtime_limits", issue = "none")]
const MIN: Timespec = Self::new(i64::MIN, 0);

const fn zero() -> Timespec {
Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } }
}
Expand Down Expand Up @@ -209,6 +215,12 @@ pub struct SystemTime(Timespec);
pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero());

impl SystemTime {
#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MAX: SystemTime = SystemTime { t: Timespec::MAX };

#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MIN: SystemTime = SystemTime { t: Timespec::MIN };

pub fn new(tv_sec: i64, tv_nsec: i32) -> SystemTime {
SystemTime(Timespec::new(tv_sec, tv_nsec))
}
Expand Down
6 changes: 6 additions & 0 deletions library/std/src/sys/pal/sgx/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ impl Instant {
}

impl SystemTime {
#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MAX: SystemTime = SystemTime(Duration::MAX);

#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MIN: SystemTime = SystemTime(Duration::ZERO);

pub fn now() -> SystemTime {
SystemTime(usercalls::insecure_time())
}
Expand Down
6 changes: 6 additions & 0 deletions library/std/src/sys/pal/solid/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ pub struct SystemTime(abi::time_t);
pub const UNIX_EPOCH: SystemTime = SystemTime(0);

impl SystemTime {
#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MAX: SystemTime = SystemTime(abi::time_t::MAX);

#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MIN: SystemTime = SystemTime(abi::time_t::MIN);

pub fn now() -> SystemTime {
let rtc = unsafe {
let mut out = MaybeUninit::zeroed();
Expand Down
18 changes: 18 additions & 0 deletions library/std/src/sys/pal/uefi/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,24 @@ impl Instant {
}

impl SystemTime {
#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MAX: SystemTime = MAX_UEFI_TIME;

#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MIN: SystemTime = SystemTime::from_uefi(r_efi::efi::Time {
year: 1900,
month: 1,
day: 1,
hour: 0,
minute: 0,
second: 0,
nanosecond: 0,
timezone: -1440,
daylight: 0,
pad1: 0,
pad2: 0,
});

pub(crate) const fn from_uefi(t: r_efi::efi::Time) -> Self {
Self(system_time_internal::from_uefi(&t))
}
Expand Down
15 changes: 15 additions & 0 deletions library/std/src/sys/pal/unix/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ pub(crate) struct Timespec {
}

impl SystemTime {
#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MAX: SystemTime = SystemTime { t: Timespec::MAX };

#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MIN: SystemTime = SystemTime { t: Timespec::MIN };

#[cfg_attr(any(target_os = "horizon", target_os = "hurd"), allow(unused))]
pub fn new(tv_sec: i64, tv_nsec: i64) -> Result<SystemTime, io::Error> {
Ok(SystemTime { t: Timespec::new(tv_sec, tv_nsec)? })
Expand Down Expand Up @@ -61,6 +67,15 @@ impl fmt::Debug for SystemTime {
}

impl Timespec {
#[unstable(feature = "time_systemtime_limits", issue = "none")]
const MAX: Timespec = unsafe { Self::new_unchecked(i64::MAX, 1_000_000_000 - 1) };

// As described below, on AppleOS, dates before epoch are represented differently.
// This is not an issue here however, because we are using tv_sec = i64::MIN,
// which will cause the compatibility wrapper to not be executed at all.
#[unstable(feature = "time_systemtime_limits", issue = "none")]
const MIN: Timespec = unsafe { Self::new_unchecked(i64::MIN, 0) };

const unsafe fn new_unchecked(tv_sec: i64, tv_nsec: i64) -> Timespec {
Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds::new_unchecked(tv_nsec as u32) } }
}
Expand Down
6 changes: 6 additions & 0 deletions library/std/src/sys/pal/unsupported/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ impl Instant {
}

impl SystemTime {
#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MAX: SystemTime = Duration::ZERO;

#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MIN: SystemTime = Duration::MAX;

pub fn now() -> SystemTime {
panic!("time not implemented on this platform")
}
Expand Down
6 changes: 6 additions & 0 deletions library/std/src/sys/pal/wasip1/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ impl Instant {
}

impl SystemTime {
#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MAX: SystemTime = SystemTime(Duration::MAX);

#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MIN: SystemTime = SystemTime(Duration::ZERO);

pub fn now() -> SystemTime {
SystemTime(current_time(wasi::CLOCKID_REALTIME))
}
Expand Down
6 changes: 6 additions & 0 deletions library/std/src/sys/pal/wasip2/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ impl Instant {
}

impl SystemTime {
#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MAX: SystemTime = SystemTime(Duration::MAX);

#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MIN: SystemTime = SystemTime(Duration::ZERO);

pub fn now() -> SystemTime {
let now = wasip2::clocks::wall_clock::now();
SystemTime(Duration::new(now.seconds, now.nanoseconds))
Expand Down
16 changes: 16 additions & 0 deletions library/std/src/sys/pal/windows/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,22 @@ impl Instant {
}

impl SystemTime {
#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MAX: SystemTime = SystemTime {
t: c::FILETIME {
dwLowDateTime: (i64::MAX & 0xFFFFFFFF) as u32,
dwHighDateTime: (i64::MAX >> 32) as u32,
},
};

#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MIN: SystemTime = SystemTime {
t: c::FILETIME {
dwLowDateTime: (i64::MIN & 0xFFFFFFFF) as u32,
dwHighDateTime: (i64::MIN >> 32) as u32,
},
};

pub fn now() -> SystemTime {
unsafe {
let mut t: SystemTime = mem::zeroed();
Expand Down
6 changes: 6 additions & 0 deletions library/std/src/sys/pal/xous/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ impl Instant {
}

impl SystemTime {
#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MAX: SystemTime = SystemTime(Duration::MAX);

#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MIN: SystemTime = SystemTime(Duration::ZERO);

pub fn now() -> SystemTime {
let result = blocking_scalar(systime_server(), GetUtcTimeMs.into())
.expect("failed to request utc time in ms");
Expand Down
40 changes: 40 additions & 0 deletions library/std/src/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,46 @@ impl SystemTime {
#[stable(feature = "assoc_unix_epoch", since = "1.28.0")]
pub const UNIX_EPOCH: SystemTime = UNIX_EPOCH;

/// Represents the maximum value representable by [`SystemTime`] on this platform.
///
/// This value differs a lot between platforms, but it is always the case
/// that any positive addition to [`SystemTime::MAX`] will fail.
///
/// # Examples
///
/// ```no_run
/// #![feature(time_systemtime_limits)]
/// use std::time::{Duration, SystemTime};
///
/// // Adding zero will change nothing.
/// assert_eq!(SystemTime::MAX.checked_add(Duration::ZERO), Some(SystemTime::MAX));
///
/// // But adding just 1ns will already fail.
/// assert_eq!(SystemTime::MAX.checked_add(Duration::new(0, 1)), None);
/// ```
#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MAX: SystemTime = SystemTime(time::SystemTime::MAX);

/// Represents the minimum value representable by [`SystemTime`] on this platform.
///
/// This value differs a lot between platforms, but it is always the case
/// that any positive subtraction from [`SystemTime::MIN`] will fail.
///
/// # Examples
///
/// ```
/// #![feature(time_systemtime_limits)]
/// use std::time::{Duration, SystemTime};
///
/// // Subtracting zero will change nothing.
/// assert_eq!(SystemTime::MIN.checked_sub(Duration::ZERO), Some(SystemTime::MIN));
///
/// // But subtracting just 1ns will already fail.
/// assert_eq!(SystemTime::MIN.checked_sub(Duration::new(0, 1)), None);
/// ```
#[unstable(feature = "time_systemtime_limits", issue = "none")]
pub const MIN: SystemTime = SystemTime(time::SystemTime::MIN);

/// Returns the system time corresponding to "now".
///
/// # Examples
Expand Down
19 changes: 19 additions & 0 deletions library/std/tests/time.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![feature(duration_constants)]
#![feature(time_systemtime_limits)]

use std::fmt::Debug;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
Expand Down Expand Up @@ -237,9 +238,27 @@ fn system_time_duration_since_max_range_on_unix() {
let min = SystemTime::UNIX_EPOCH - (Duration::new(i64::MAX as u64 + 1, 0));
let max = SystemTime::UNIX_EPOCH + (Duration::new(i64::MAX as u64, 999_999_999));

assert_eq!(min, SystemTime::MIN);
assert_eq!(max, SystemTime::MAX);

let delta_a = max.duration_since(min).expect("duration_since overflow");
let delta_b = min.duration_since(max).expect_err("duration_since overflow").duration();

assert_eq!(Duration::MAX, delta_a);
assert_eq!(Duration::MAX, delta_b);
}

#[test]
fn system_time_max_min() {
// First, test everything with checked_* and Duration::ZERO.
assert_eq!(SystemTime::MAX.checked_add(Duration::ZERO), Some(SystemTime::MAX));
assert_eq!(SystemTime::MAX.checked_sub(Duration::ZERO), Some(SystemTime::MAX));
assert_eq!(SystemTime::MIN.checked_add(Duration::ZERO), Some(SystemTime::MIN));
assert_eq!(SystemTime::MIN.checked_sub(Duration::ZERO), Some(SystemTime::MIN));

// Now do the same again with checked_* but try by ± a single nanosecond.
assert!(SystemTime::MAX.checked_add(Duration::new(0, 1)).is_none());
assert!(SystemTime::MAX.checked_sub(Duration::new(0, 1)).is_some());
assert!(SystemTime::MIN.checked_add(Duration::new(0, 1)).is_some());
assert!(SystemTime::MIN.checked_sub(Duration::new(0, 1)).is_none());
}
Loading