Duration from float without panic

I'm parsing a string to get a float and attempting to turn it into a duration via Duration::from_secs_f64.
Problem is that from_secs_f64 seems to panic on negative, overflow or infinite numbers.
I can't find a decent way to convert the float to a duration (with appropriate error handling) without adding these extra checks in my code or catching the panic (panic::catch_unwind).
Any ideas?

Check out the source. It's very simple, and can be adjusted rather easily.

I can easily copy the error checking from the the core lib source code but that's ugly and might change in the future and I'll end up panicing if they ever change the conditions.
It seems to my there should be some try option here?

I agree that a non-panicking constructor would be nice. In the meantime, could you convert your floating point seconds to milli-, micro- or nano-seconds instead and use the integer constructor?

1 Like

Without knowing what is going on in your code I would tend to think that the problem is not with 'from_secs_f64'.

Rather it is with the parser. When parsing a string into anything it can fail for all kind of reasons. In this case the error situations are that the string you parse produces negative, overflow or infinite numbers.

It should be the parser error that is handled along with whatever other errors it could produce.

I tend to agree, sadly I'll go for the unsigned int approach. This break compatibility with some old code I have but time should best not be stored in floats anyway.

The parsing is fine. I parse a string to a float and handle errors correctly. The problem is that some valid floats aren't valid Durations and so we're missing some way of checking that without panicing.

Yes but the way I see it, the parser should not be producing just any old floats. It is parsing durations, which happen to be in floating point format I presume, therefore I suggest it should produce valid durations. Which does not include Inf, Nan, etc. The parser should fail with an error.

I would make this argument even more strongly if the strings you are parsing are actually inputs to the program, from a user or file or whatever. One should always check/sanitize inputs at the point of entry, not eave it to the depths of your program where something else might fail.

Correct. But worth asking who better to know what a valid duration is than Duration. I mean we usually count on let user_id = some_string::parse::<u64>(); to know how to handle strings so we get a valid Ok(u64) or an Err. If we then need some more extra checking we can check our user_id variable which is a u64 and not a string anymore.

In our case, though, we're dealing with a duration. I'd expect Duration to be able to "parse" the float. I can then check, if this parsing failed or if it succeeded. Even on success the Duration might not be valid for my specific application. All this, of course, at the point of entry, not later on.

If you were parsing (x, y) input pairs that were required to be coordinates of points on a unit circle, would you expect the coordinates parser to know that constraint? Or would you check that the provided input met the constraint after you had parsed the data? I don't see why constraints on acceptable input for duration should be handled by the input parser; rather it should be happened by a post-input check just as for my unit-circle coordinate example.

1 Like

If I were writing a library to be used by others which received coordinates as an input I would avoid panicing if someone passed in something invalid. If I were writing the library then I'd assume that only I knew what are valid inputs and not my users. I would provide the user of some way to use me as a validator.

I can't see the conceptual difference between some_string.parse::<u64>(); and Duration::from_secs_f64(x), but one returns an Err on invalid input and the other panics.

Six of one, half a dozen of the other.

I guess you just have to do what is most appropriate in your case.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.