Rfcs: Better Display implementation for Duration

Created on 15 May 2015  Â·  13Comments  Â·  Source: rust-lang/rfcs

The brand new time::Duration type has a rather odd choice for its Display. It's attempting to show the smallest unit that doesn't lose any precision, unless the duration is at least 1 second, at which point it discards all sub-second precision. This is very odd, because it means that round numbers change units, so e.g. 252999ns, 253000ns, and 253001ns display respectively as 252999ns, 253µs, and 253001ns.

I would suggest that it should display using the largest unit that is <= the duration, in a floating-point format with zero to three decimals of precision (with rounding). This would mean that 2000ns would display as 2µs, 2001ns would display as 2.001µs, and 2100ns would display as 2.1µs. The cap of 3 decimal places of precision is because anything beyond that is likely to be irrelevant, and humans don't really like reading long numbers without grouping separators, and we especially don't like trying to compare two numbers that have significantly different amounts of precision.

Examples

| Duration | Display |
| --- | --- |
| 1ns | 1ns |
| 1_000ns | 1µs |
| 1_000_000ns | 1ms |
| 1_000_000_000ns | 1s |
| 999ns | 999ns |
| 1_001ns | 1.001µs |
| 1_100ns | 1.1µs |
| 1_234_567ns | 1.235ms |
| 1_234_567_890ns | 1.235s |
| 1_000_000_001ns | 1s |
| 1_000_999_999ns | 1.001s |

We might also want to support the precision flag, so you can say e.g. {:.3} to always force 3 digits of precision.

T-libs

Most helpful comment

Unless I'm missing something the current std::time::Duration doesn't have a Display impl: https://doc.rust-lang.org/std/time/struct.Duration.html#implementations... At least it's not working for me.

All 13 comments

It currently doesn't discard any precision - it shows the duration as %d.%09d if it is in seconds.

Oh you're right, I misread the code, I was looking at the branch that was used if nanos was 0.

I would prefer not to round - that would cause durations to randomly not align.

Updated to suggest that we also support the precision flag, so you can say {:.3} if you want to force 3 digits of precision (e.g. so your timing runs line up nicer).

I'd personally be fine this this proposal

I've started working on an implementation.

I doubt we can afford not showing some of the precision by default. I’m fine with dropping it in case of formatter like {:3}, though.

I'm with nagisa on this one. I've seen my share of problems that were hard to find because crucial information was discarded by default. Declaring a width in the format string is the optimal solution here, because it allows the programmer to clearly state their intent, and they usually have more knowledge about their code than we do.

There's several problems I have with that.

The first is I strongly disagree with the idea that, just because we don't know the intent of the programmer's code, we should throw up our hands and discard any attempt to provide a reasonable default. Sure, it's plausible that someone might have a duration where every single digit is significant, and displaying 1234567890ns as 1.235s will discard that information, but I believe it to be very unlikely for this to be the case. And in the rare case where it is true, the programmer can easily opt in to showing all precision.

The second is that there's no way for the user to request the kind of dynamic precision that I have here as the default. When you give a precision to a formatter, you're requesting that exact precision. You can't say "show up to 3 digits". Sure, we could explicitly define a precision as "show up to N digits", but that would be inconsistent with all existing precedent and would be surprising. It would also then make it impossible for the user who actually does want exactly 3 digits to get what they want. So that's a no-go. Alternatively, we could define the # flag as "trim trailing zeros", except the current core::fmt infrastructure does not provide any way to actually get at this flag from library code, and it would again be inconsistent with all existing precedent, and not particularly discoverable. So again, a no-go.

The third issue is that you're not even attempting to address the claim that past about 3 digits of precision, the values become fairly meaningless, possibly representing noise or accumulated error, or otherwise just plain not useful. Remember, this is the Display implementation we're talking about here; this is meant for showing to a user. It's not intended to be used to produce something machine-readable. Humans don't like reading noise, and they also really don't like reading excessively long numbers. If you're displaying a Duration in a situation where the extra precision really is meaningful, then go ahead and use a {:9} format to show it. But in the vast majority of cases (I'd even go so far as to say every non-contrived case) that's just not a good default.

Sure, it's plausible that someone might have a duration where every single digit is significant, and displaying 1234567890ns as 1.235s will discard that information, but I believe it to be very unlikely for this to be the case.

There’s at least one person (me) who wrongly thought leaking resources would be very unlikely/harmless in the past on various occasions.

You can't say "show up to 3 digits".

This is a limitation of our formatting infrastructure, which should be considered for fixing, because this kind of request is (or might be) also useful for floats and integers.

you're not even attempting to address the claim that past about 3 digits of precision, the values become fairly meaningless, possibly representing noise or accumulated error, or otherwise just plain not useful.

You can’t consider Duration in isolation only. Even small changes in value of time are very significant when used in calculations with big values, such as speed of light. Difference between 1000999999ns * c (displayed as 1.001s * c) and 1000500000ns * c (displayed as 1.001s * c) is almost 150km, which is not that insignificant in my eyes.

Maybe there’s a standard way to annotate that value is not written down in full (a la ≈)?

@nagisa It strikes me as rather unlikely that someone is going to be using Duration to represent values in calculations with the speed of light. But even if someone does do that, I'm not sure how the default Format implementation for Duration really has any bearing on that calculation, since the string value of the Duration is not going to affect the results. And if your sole concern is in printing the components of the calculation (e.g. the duration) in addition to the result, I don't think it's unreasonable to tell the user that they should be requesting high precision if they think it's meaningful (e.g. {:9}).

Also FWIW, Duration cannot represent values with more precision than nanoseconds, which means that if you did use a Duration in a physics calculation with the speed of light, your results could have error of almost 1 foot. Depending on what you're doing these calculations for, that 1 foot difference could be just as meaningful as your 150km difference (which, in the abstract, isn't necessarily meaningful itself; it depends on what the value is being used for).

Maybe there’s a standard way to annotate that value is not written down in full (a la ≈)?

What would be the use in that? If the default printing of Duration prints everything like ≈1.001s, that would render it useless for a great many things (or at least very annoying to use because of the completely pointless visual noise).

Ultimately, it seems like you're trying to optimize for really unlikely edge cases, and treating the existence of the edge case as an argument against having default behavior that is appropriate in the overwhelming majority of cases where a Duration will be shown to a user. I don't find this argument at all convincing, and I'm not sure why you do.

Unless I'm missing something the current std::time::Duration doesn't have a Display impl: https://doc.rust-lang.org/std/time/struct.Duration.html#implementations... At least it's not working for me.

And the Debug implementation already follows what this RFC issue proposed. (rust-lang/rust#50364).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mahkoh picture mahkoh  Â·  3Comments

camden-smallwood-zz picture camden-smallwood-zz  Â·  3Comments

3442853561 picture 3442853561  Â·  3Comments

mqudsi picture mqudsi  Â·  3Comments

3442853561 picture 3442853561  Â·  3Comments