A few problems with the duration type
I'm finding myself wanting to divide a Duration into another Duration, to get a percentage as a float (convert to float and then divide), and to multiply/divide Durations by Floats (convert to float, do operation, then back). Those div/mul implementations would be nice. Also, I can't seem to do math on durations without cloning them, when they come from a borrowed struct. Implementations on reference versions would be nice. Thoughts?
Sorry for the lack of detail, it's pretty late.
The original author of Chrono here.
I'm very unsure about the multiplication and division on the Duration, especially when it involves a floating point operation. You wouldn't want Duration::days(10) * 0.1f32 to return Duration::days(1) + Duration::nanoseconds(1_287_460) (yes, that's an exactly rounded result). Even when it doesn't involve floating point numbers, its lack of other numeric operations is concerning (Rem wouldn't make much sense for Duration, to name one). Chrono's Duration type was designed as neither a general unit-of-measure type nor a fully number-like type, so copying their interface is hard.
I do think that conversion from/to floating point numbers is worth considering. num_* methods are named so that it explicitly returns an integer (the number of something can never go fractional); total_* methods might be added for them, for example.
Fair enough. That is definitely an issue when dealing with floats. Thoughts on borrowed math?
I bumped my head against this very thing today; I went looking for impl Div<Duration> for Duration { type Output = f64 } and was very surprised to find it wasn't there. Once you have a special data-type for representing durations, it's pretty useful to be able to say "this test run took 0.73 times as long as the reference" or "we hit a problem, wait 1.2 times the previous timeout before trying again". Even Rem might be useful: "We can run seven end-to-end tests before the go-live date, with three-and-a-half days to spare."
I guess it could be surprising for people to get oddly-rounded numbers when dealing with floats, but that's an issue with floats in general, not specific to Durations, and such people are probably going to get surprised by rounding sooner or later anyway.
What is the canonical way to multiply a Duration by a f32? I'm multiplying frame duration values (1-100ms durations) by a speed effect in a video game. The operation I need is Duration * f32 -> Duration. I'm not too worried about loss of precision or edge cases, but I do want to write ideomatic rust.
You wouldn't want
Duration::days(10) * 0.1f32to returnDuration::days(1) + Duration::nanoseconds(1_287_460)(yes, that's an exactly rounded result).
I personally wouldn't expect there to be such guarantees when dividing durations / multiplying by float - just like I wouldn't expect them in general when working with floats. These operations however are very handy when high precision is not required. +1 for this feature.
You wouldn't want
Duration::days(10) * 0.1f32to returnDuration::days(1) + Duration::nanoseconds(1_287_460)(yes, that's an exactly rounded result).I personally wouldn't expect there to be such guarantees when dividing durations / multiplying by float - just like I wouldn't expect them in general when working with floats.
Uh... That is exactly what I would expect. Floating point numbers are not "fuzzy", there is a specification on how they work which covers the meaning of operations like this, and yes, if you convert a floating point number to an integral type it should be exactly rounded. (The more interesting question is what to do with Duration::days(10) * NaN; possible options include a panic, or 0 for consistency with f32 as i32.)