From 8c993cdbba4fbe9eb6c6d0be1de46cbf6f257060 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Tue, 11 Nov 2025 11:46:11 +0100 Subject: [PATCH 01/11] time: Implement SystemTime::{MIN, MAX} This commit introduces two new constants to SystemTime: `MIN` and `MAX`, whose value represent the maximum values for the respective data type, depending upon the platform. Technically, this value is already obtainable during runtime with the following algorithm: Use `SystemTime::UNIX_EPOCH` and call `checked_add` (or `checked_sub`) repeatedly with `Duration::new(0, 1)` on it, until it returns None. Mathematically speaking, this algorithm will terminate after a finite amount of steps, yet it is impractical to run it, as it takes practically forever. Besides, this commit also adds a unit test. Concrete implementation depending upon the platform is done in later commits. In the future, the hope of the authors lies within the creation of a `SystemTime::saturating_add` and `SystemTime::saturating_sub`, similar to the functions already present in `std::time::Duration`. However, for those, these constants are crucially required, thereby this should be seen as the initial step towards this direction. --- library/std/src/time.rs | 40 +++++++++++++++++++++++++++++++++++++++ library/std/tests/time.rs | 19 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 87aaf9091f1bc..d8637207822e1 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -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 diff --git a/library/std/tests/time.rs b/library/std/tests/time.rs index be1948af91564..31cc7171fe52e 100644 --- a/library/std/tests/time.rs +++ b/library/std/tests/time.rs @@ -1,4 +1,5 @@ #![feature(duration_constants)] +#![feature(time_systemtime_limits)] use std::fmt::Debug; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; @@ -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()); +} From db29e663f68ead7f6b236aed0864220ed07b1224 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Tue, 11 Nov 2025 11:49:18 +0100 Subject: [PATCH 02/11] pal/unix: Implement SystemTime::{MIN, MAX} --- library/std/src/sys/pal/unix/time.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index c207f41cad4b5..12449c856b3e9 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -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 { Ok(SystemTime { t: Timespec::new(tv_sec, tv_nsec)? }) @@ -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) } } } From ae9d06447db784edee745f73d7b22a6910fde9c2 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Tue, 11 Nov 2025 15:11:29 +0100 Subject: [PATCH 03/11] pal/hermit: Implement SystemTime::{MIN, MAX} This commit implements `SystemTime::MIN` and `SystemTime::MAX` for for HermitOS, which itself is more or less identical to the Unix implementation. --- library/std/src/sys/pal/hermit/time.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index bd6fd5a3de428..aaea951e337c4 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -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 } } } @@ -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)) } From eae063906a6c579ad9282c69eefa4638a6399046 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Tue, 11 Nov 2025 15:13:10 +0100 Subject: [PATCH 04/11] pal/sgx: Implement SystemTime::{MIN, MAX} This commit implements `SystemTime::MIN` and `SystemTime::MAX` for sgx. The implementation uses a `Duration` to store the Unix time, thereby implying `Duration::ZERO` and `Duration::MAX` as the limits. --- library/std/src/sys/pal/sgx/time.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/std/src/sys/pal/sgx/time.rs b/library/std/src/sys/pal/sgx/time.rs index db4cf2804bf13..0c20ec6852585 100644 --- a/library/std/src/sys/pal/sgx/time.rs +++ b/library/std/src/sys/pal/sgx/time.rs @@ -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()) } From 45789f26a6a7825f418bfff8ed67df40a75913fd Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Tue, 11 Nov 2025 15:14:16 +0100 Subject: [PATCH 05/11] pal/solid: Implement SystemTime::{MIN, MAX} This commit implements `SystemTime::MIN` and `SystemTime::MAX` for solid. The implementation uses a `time_t` to store the system time within a single value (i.e. no dual secs/nanosecs handling), thereby implying its `::MIN` and `::MAX` values as the respective boundaries. --- library/std/src/sys/pal/solid/time.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/std/src/sys/pal/solid/time.rs b/library/std/src/sys/pal/solid/time.rs index c39d715c6a6f6..b691603759a2e 100644 --- a/library/std/src/sys/pal/solid/time.rs +++ b/library/std/src/sys/pal/solid/time.rs @@ -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(); From 7a7c8e1875bb349906d493c36e860fdfeccf79a9 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Tue, 11 Nov 2025 15:15:42 +0100 Subject: [PATCH 06/11] pal/uefi: Implement SystemTime::{MIN, MAX} This commit implements `SystemTime::MIN` and `SystemTime::MAX` for the UEFI platform. UEFI has a weird way to store times, i.e. a very complicated struct. The standard proclaims "1900-01-01T00:00:00+0000" to be the lowest possible value and `MAX_UEFI_TIME` is already present for the upper limit. --- library/std/src/sys/pal/uefi/time.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs index 861b98da18daf..36cf9c11569f0 100644 --- a/library/std/src/sys/pal/uefi/time.rs +++ b/library/std/src/sys/pal/uefi/time.rs @@ -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)) } From 90636a2c5ce0533aa2ff285692cfccfb6cb32207 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Tue, 11 Nov 2025 15:17:59 +0100 Subject: [PATCH 07/11] pal/wasip1: Implement SystemTime::{MIN, MAX} This commit implements `SystemTime::MIN` and `SystemTime::MAX` for wasip1. Similar to sgx, a `Duration` is used to store the time, thereby depending on those limits. --- library/std/src/sys/pal/wasip1/time.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/std/src/sys/pal/wasip1/time.rs b/library/std/src/sys/pal/wasip1/time.rs index 0d8d0b59ac14a..057819eb5f49a 100644 --- a/library/std/src/sys/pal/wasip1/time.rs +++ b/library/std/src/sys/pal/wasip1/time.rs @@ -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)) } From 1c2e6c16af148fdfe9a476774c725f1c107dfc8d Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Tue, 11 Nov 2025 15:19:11 +0100 Subject: [PATCH 08/11] wasip2: Implement SystemTime::{MIN, MAX} See the wasip1 implementation, which is functionally equivalent. --- library/std/src/sys/pal/wasip2/time.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/std/src/sys/pal/wasip2/time.rs b/library/std/src/sys/pal/wasip2/time.rs index 434891839944d..118033cbad750 100644 --- a/library/std/src/sys/pal/wasip2/time.rs +++ b/library/std/src/sys/pal/wasip2/time.rs @@ -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)) From ecdcc48416f841d0986da3630fd3a70807a9035e Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Tue, 11 Nov 2025 15:19:53 +0100 Subject: [PATCH 09/11] pal/windows: Implement SystemTime::{MIN, MAX} This commit implements `SystemTime::MIN` and `SystemTime::MAX` for the Windows platform. Windows is weird. The Win32 documentation makes no statement on a maximum value here. Next to this, there are two conflicting types: `SYSTEMTIME` and `FILETIME`. Rust's Standard Library uses `FILETIME`, whose limit will (probably) be `i64::MAX` packed into two integers. However, `SYSTEMTIME` has a lower-limit. --- library/std/src/sys/pal/windows/time.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs index 0d31b80e56afc..e9e8b58c0ec98 100644 --- a/library/std/src/sys/pal/windows/time.rs +++ b/library/std/src/sys/pal/windows/time.rs @@ -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(); From 6e196192a46de09b12a2750b2e87dd7e3dcdd200 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Tue, 11 Nov 2025 15:22:53 +0100 Subject: [PATCH 10/11] pal/xous: Implement SystemTime::{MIN, MAX} This commit implements `SystemTime::MIN` and `SystemTime::MAX` for xous. It is similar to wasip1, wasip2, and sgx in the sense of once again using a `Duration` to store the value. --- library/std/src/sys/pal/xous/time.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/std/src/sys/pal/xous/time.rs b/library/std/src/sys/pal/xous/time.rs index ae8be81c0b7c5..5cb59a3783c93 100644 --- a/library/std/src/sys/pal/xous/time.rs +++ b/library/std/src/sys/pal/xous/time.rs @@ -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"); From e5745aa07c3b5a572741625d218b274040e17f94 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Tue, 11 Nov 2025 15:25:23 +0100 Subject: [PATCH 11/11] pal/unsupported: Implement SystemTime::{MIN, MAX} This commit implements `SystemTime::MIN` and `SystemTime::MAX` for all unsupported platforms. Unsupported platforms store a `SystemTime` in a `Duration`, just like wasip1, sgx, and a few others, thereby implying `Duration::ZERO` and `Duration::MAX` as the respective limits. --- library/std/src/sys/pal/unsupported/time.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/std/src/sys/pal/unsupported/time.rs b/library/std/src/sys/pal/unsupported/time.rs index 6d67b538a96bf..de5a359fa1c19 100644 --- a/library/std/src/sys/pal/unsupported/time.rs +++ b/library/std/src/sys/pal/unsupported/time.rs @@ -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") }