A `Duration` is created from a second and nanoseconds variable. The
documentation says: "This constructor will panic if the carry from the
nanoseconds overflows the seconds counter". This was, however, not tested
in the tests. I doubt the behavior will ever regress, but it is usually a
good idea to test all documented behavior.
Improve `Debug` impl of `time::Duration`
Hi there!
For a long time now, I was getting annoyed by the derived `Debug` impl of `Duration`. Usually, I use `Duration` to either do quick'n'dirty benchmarking or measuring the time of some operation in general. The output of the derived Debug impl is hard to parse for humans: is { secs: 0, nanos: 968360102 } or { secs: 0, nanos 98507324 } longer?
So after running into the annoyance several times (sometimes building my own function to print the Duration properly), I decided to tackle this. Now the output looks like this:
```
Duration::new(1, 0) => 1s
Duration::new(1, 1) => 1.000000001s
Duration::new(1, 300) => 1.0000003s
Duration::new(1, 4000) => 1.000004s
Duration::new(1, 600000) => 1.0006s
Duration::new(1, 7000000) => 1.007s
Duration::new(0, 0) => 0ns
Duration::new(0, 1) => 1ns
Duration::new(0, 300) => 300ns
Duration::new(0, 4001) => 4.001µs
Duration::new(0, 600300) => 600.3µs
Duration::new(0, 7000000) => 7ms
```
Note that I implemented the formatting manually and didn't use floats. No information is "lost" when printing. So `Duration::new(123_456_789_000, 900_000_001)` prints as `123456789000.900000001s`.
~~This is not yet finished~~, but I wanted to open the PR now already in order to get some feedback (maybe everyone likes the derived impl).
### Still ToDo:
- [x] Respect precision ~~and width~~ parameter of the formatter (see [this comment](https://github.com/rust-lang/rust/pull/50364#issuecomment-386107107))
### Alternatives/Decisions
- Should large durations displayed in minutes, hours, days, ...? For now, I decided not to because the current formatting is close the how a `Duration` is stored. From this new `Debug` output, you can still easily see what the values of `secs` and `nanos` are. A formatting like `3h 27m 12s 9ms` might be more appropriate for a `Display` impl?
- Should this rather be a `Display` impl and should `Debug` be derived? Maybe this formatting is too fancy for `Debug`? In my opinion it's not and, as already mentioned, from the current format one can still very easily determine the values for `secs` and `nanos`.
- Whitespace between the number and the unit?
### Notes for reviewers
- ~~The combined diff sucks. Rather review both commits individually.~~
- ~~In the unit test, I am building my own type implementing `fmt::Write` to test the output. Maybe there is already something like that which I can use?~~
- My `Debug` impl block is marked as `#[stable(...)]`... but that's fine since the derived Debug impl was stable already, right?
---
~~Apart from the main change, I moved all `time` unit tests into the `tests` directory. All other `libcore` tests are there, so I guess it was simply an oversight. Prior to this change, the `time` tests weren't run, so I guess this is kind of a bug fix. If my `Debug` impl is rejected, I can of course just send the fix as PR.~~ (this was already merged in #50466)
Previously, the code would panic for high precision values. Now it
has the same behavior as printing normal floating point values: if
a high precision is specified, '0's are added.
Rounding is done like for printing floating point numbers. If the
first digit which isn't printed (due to the precision parameter) is
larger than '4', the number is rounded up.
Prior to this, Duration simply derived Debug. Since Duration doesn't
implement `Display`, the only way to inspect its value is to use
`Debug`. Unfortunately, the derived `Debug` impl is far from optimal
for humans. In many cases, Durations are used for some quick'n'dirty
benchmarking (or in general: measuring the time of some code). Correctly
understanding the output of Duration's Debug impl is not easy (e.g.
is "{ secs: 0, nanos: 968360102 }" or "{ secs: 0, nanos 98507324 }"
shorter?).
This commit replaces the derived impl with a manual one. It prints
the duration as seconds (i.e. "3.1803s") if the duration is longer than
a second, otherwise it prints it in either ms, µs or ns (depending on
the duration's length). This already helps readability a lot and it
never omits information that is stored.
This `Debug` impl does *not* respect the following formatting parameters:
- fill/align/padding: difficult to implement, probably not worth it
- alternate # flag: not clear what this should do
All other tests of libcore reside in the tests/ directory,
too. Apparently the tests of `time.rs` weren't run before, at
least not by `x.py test src/libcore`.