Duration::new(secs, nanos) can panic, because if its nanos argument is greater than 999,999,999, it propagates the excess into the seconds field, and that addition can overflow. Thus for example
use std::time::Duration;
fn main() {
println!("{:?}", Duration::new(u64::MAX, 1_000_000_000_u32));
}
Can we add an alternative version, probably named try_new, that returns an Err value in case of overflow, instead? I want this for parsing textual representations of timestamps: I'm already returning Result<Duration, MyTimestampParseError> for a bunch of other failure cases, including overflow detected during decimal-to-binary conversion, so it seems inconsistent for this one overflow case to panic. (Also, if I wrote the parser correctly, the panic is unreachable, but the compiler can't prove it.)
Checked Duration constructors exist for conversion from f32 and f64 (try_from_secs_f32 and ..._f64), but f64 does not have enough bits to represent present-day times with nanosecond precision[1], so these are inherently lossy for my use case.
I suppose by “desired range” you mean that nanos < 1_000_000_000? Because I don’t interpret it that way. The statement was
which referred to “overflow” as described in
So doing a checked_add of two Duration should do exactly the right thing here (and I cannot imagine that approach being improperly optimized, either; though I did not check the code it generates).
To clarify, what I want is indeed exactly shorthand for Duration::from_secs(secs).checked_add(Duration::from_nanos(nanos as u64)). Thanks for the suggestion, I don't think I would have thought to try that. (I did check the code generation; Duration::from_secs and Duration::from_nanos both call Duration::new, but the compiler can prove that those calls supply arguments that cannot lead to the panic.)
It's fine for my use case that Duration::from_secs(10).checked_add(Duration::from_nanos(3_000_000_000)) == Duration::new(13, 0). I just want to get rid of the panic on Duration::new(u64::MAX, 1_000_000_000), mainly so that I can statically verify that the larger program never panics.
(My parser already prevents the nanos argument from going outside the subsecond range, i.e. the compiler could in principle prove nanos <= 999_999_999_u32 if it was clever enough. But it isn't.)
In cases where the compiler fails to prove something you know to be true, you could add an assert!. In addition to checking the condition, that will also cause the compiler to assume it to hold after running the assert, which can improve optimization.