Change:
<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --I tried this code on M1 macOS: It's expected to succeed. Instead, this happened: It seems that there is something wrong with the casting in Rust std: This problem does not exist on x8664-apple-darwin, because . <!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: <!-- Include a backtrace in the code block by setting in your environment. E.g. . <details<summaryBacktrace</summary<p</p</details--
label +T-libs +O-macos +O-arm
Seems related to the time resolution difference on Apple M1, cc
The reason for this behavior is that uses platform-specific resolution while uses nanosecond resolution. For Macos x86-64 and Linux this does not matter because on those platforms the resolution of is also nanoseconds. resolution on my M1 is 125 / 3 ≈ 41.67 ns. So when you add 50 ns to you are adding 1 to its internal representation (= ~41.67 ns). When the duration is calculated it gets rounded down to = ⌊1 * 125 / 3⌋ = 41 ns. + = because 41 ns is less than the minimum resolution.
So is it considered a bug? Should we round 41 ns up to 1?
Thought about this some more. We allow those operations: Duration = Instant - Instant Instant = Instant + Duration bool = Instant == Instant That can't be changed, so simple arithmetic identities such as i0 + (i1 - i0) == i1 should hold if there is no overflow. In particular because the current behavior leads to real bugs. The only way to achieve this is IMHO to change the internal representation for on MacOS to nanosecond resolution because otherwise the resolution of the machine timer influences Instant/Duration arithmetic. cc What do you think?
We should do this, but I'm not sure we can do it everywhere — (and the other functions) is only available in Darwin 16 (macOS 10.12, iOS 10) and newer, which is newer than our supported versions. We can certainly do it on macOS+aarch64 targets though, since those should always have it.
This seems pretty severe. I'm a novice contributor, but I do have an M1 device if there's anything I can do to aid the development of a fix here. Also, should this get some sort of I-prioritize doohickey?
But the documentation says: So the consequence would seem that we can any range and precision limitations from the underlying type and thus rounding errors are part of the API? I don't see the benefit of it, but it's documented.
It is documented for Instant, yes. But we do allow arithmetic operations (+/-) between Duration and Instant leading to those problems, that - at minimum - violate the principle of the least surprise. It is exacerbated by the fact that Linux, Windows and macOS x86-64 (de facto because numer and denom are both 1) Instants all use nanosecond resolution. We should just use . We don't specify which version of iOS we support, so no idea if we could use it for ios as well. ) apparently totally unconcerned about overflow, so I assume that numer will stay small.
It tried to use but this didn't fix the issue. The changes: I also a test which still fails: I'm not sure how to correctly get from Rust, so I looked the value up in my local file and used : Note that this enum uses and possibly:
That can't work, because you are still adjusting the value returned by with numerator and denominator in Also this can only be done for macOS aarch64 where it is always available. It just occurred to me that we don't even need to use , we can just use the standard UNIX implementation () for macOS aarch64 except that we need to use . Defining a local const for to 8 is fine is fine for testing, but it should become a PR to before merging.
The test passes now with your proposed changes:

Discussion:
} } <del> #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] </del> <ins> #[cfg(any( all(target_os = "macos", any(not(target_arch = "aarch64"), miri)), target_os = "ios", target_os = "watchos" ))] </ins> mod inner { use crate::sync::atomic::{AtomicU64, Ordering}; use crate::sys::cvt;

} } <del> #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "watchos")))] </del> <ins> #[cfg(not(any( all(target_os = "macos", any(not(target_arch = "aarch64"), miri)), target_os = "ios", target_os = "watchos" )))] </ins> mod inner { use crate::fmt; use crate::mem::MaybeUninit;

impl Instant { pub fn now() -> Instant { <del> Instant { t: Timespec::now(libc::CLOCK_MONOTONIC) } </del> <ins> #[cfg(target_os = "macos")] const clock_id: libc::clockid_t = libc::CLOCK_UPTIME_RAW; #[cfg(not(target_os = "macos"))] const clock_id: libc::clockid_t = libc::CLOCK_MONOTONIC; Instant { t: Timespec::now(clock_id) } </ins> } pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {

} } <del> #[cfg(not(any(target_os = "dragonfly", target_os = "espidf", target_os = "horizon")))] pub type clock_t = libc::c_int; #[cfg(any(target_os = "dragonfly", target_os = "espidf", target_os = "horizon"))] pub type clock_t = libc::c_ulong; </del> impl Timespec { <del> pub fn now(clock: clock_t) -> Timespec { </del> <ins> pub fn now(clock: libc::clockid_t) -> Timespec { </ins> // Try to use 64-bit time in preparation for Y2038. #[cfg(all(target_os = "linux", target_env = "gnu", target_pointer_width = "32"))] {

// Changing the order of instant math shouldn't change the results, // especially when the expression reduces to X + identity. assert_eq!((now + offset) - now, (now - now) + offset); <ins> // On any platform, `Instant` should have the same resolution as `Duration` (e.g. 1 nanosecond) // or better. Otherwise, math will be non-associative (see #91417). let now = Instant::now(); let provided_offset = Duration::from_nanos(1); let later = now + provided_offset; let measured_offset = later - now; assert_eq!(measured_offset, provided_offset); </ins> } #[test]