Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Duration fmt::Debug impl doesn't honor alignment #88059

Closed
hawkw opened this issue Aug 15, 2021 · 3 comments
Closed

Duration fmt::Debug impl doesn't honor alignment #88059

hawkw opened this issue Aug 15, 2021 · 3 comments
Labels
C-bug Category: This is a bug.

Comments

@hawkw
Copy link
Contributor

hawkw commented Aug 15, 2021

It appears that the fmt::Debug implementation for std::time::Duration ignores alignment/width specifiers.

For example, see this playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d5daccbe4b2e510f4dcee8d85e421b47

I tried this code:

Formatting a Duration with alignment/width specifiers (with a f64 for comparison).

fn main() {
    use std::time::Duration;
    let some_duration = Duration::from_millis(100) + Duration::from_micros(555);
    println!(" left aligned `Duration` = {:>20?} foo", some_duration);
    println!(" left aligned `f64`      = {:>20?} foo", 100.555f64);
    println!("right aligned `Duration` = {:<20?} foo", some_duration);
    println!("right aligned `f64`      = {:<20?} foo", 100.555f64)
}

I expected to see this happen:

The durations should be padded to fill the specified width, and aligned based on the alignment specifier (identically to the f64 value. I would expect to see output that looks like this:

 left aligned `Duration` =            100.555ms foo
 left aligned `f64`      =              100.555 foo
right aligned `Duration` = 100.555ms            foo
right aligned `f64`      = 100.555              foo

Instead, this happened:

The Durations are not padded to the specified width, and are not aligned based on the format specifier. The output looks like this:

 left aligned `Duration` = 100.555ms foo
 left aligned `f64`      =              100.555 foo
right aligned `Duration` = 100.555ms foo
right aligned `f64`      = 100.555              foo

Meta

rustc --version --verbose:
On my machine, the version is:

rustc 1.53.0 (53cb7b09b 2021-06-17)
binary: rustc
commit-hash: 53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b
commit-date: 2021-06-17
host: x86_64-unknown-linux-gnu
release: 1.53.0
LLVM version: 12.0.1

In the playground this also occurs on stable 1.54.0, and on 1.56.0-nightly (2021-08-14 8007b506ac5da629f223). Looking at the git blame, though, it looks like Duration's Debug impl has had this behavior since 9eeb13f (prior to that commit, it simply derived Debug).

@hawkw hawkw added the C-bug Category: This is a bug. label Aug 15, 2021
@hawkw
Copy link
Contributor Author

hawkw commented Aug 15, 2021

I'd be happy to work on a PR to change this behavior, provided it's agreed that we would want to honor fill/width/alignment here?

hawkw added a commit to tokio-rs/console that referenced this issue Aug 15, 2021
This looks somewhat nicer, IMO --- and, `top` and `htop` do this. It
would be nice to also left-align other numeric values (a la
`top`/`htop`), but we can't do that for `Duration`s currently, as the
`fmt::Debug` impl for `std::time::Duration` simply ignores alignment
specifiers (see rust-lang/rust#88059).

We could write our own custom formatter for durations, I guess...
@Friz64
Copy link

Friz64 commented Aug 16, 2021

Is this related to #87905?

hawkw added a commit to tokio-rs/console that referenced this issue Aug 17, 2021
This looks somewhat nicer, IMO --- and, `top` and `htop` do this. It
would be nice to also left-align other numeric values (a la
`top`/`htop`), but we can't do that for `Duration`s currently, as the
`fmt::Debug` impl for `std::time::Duration` simply ignores alignment
specifiers (see rust-lang/rust#88059).

We could write our own custom formatter for durations, I guess...
@michiel-de-muynck
Copy link
Contributor

Fixed by #88999.

the8472 pushed a commit to the8472/rust that referenced this issue Sep 22, 2021
Duration's Debug formatting previously ignored the width parameter.
This commit fixes that.

Fixes issue rust-lang#88059.
the8472 added a commit to the8472/rust that referenced this issue Sep 22, 2021
Make `Duration` respect `width` when formatting using `Debug`

When printing or writing a `std::time::Duration` using `Debug` formatting, it previously completely ignored any specified `width`. This is unlike types like integers and floats, which do pad to `width`, for both `Display` and `Debug`, though not all types consider `width` in their `Debug` output (see e.g. rust-lang#30164). Curiously, `Duration`'s `Debug` formatting *did* consider `precision`.

This PR makes `Duration` pad to `width` just like integers and floats, so that
```rust
format!("|{:8?}|", Duration::from_millis(1234))
```
returns
```
|1.234s  |
```

Before you ask "who formats `Debug` output?", note that `Duration` doesn't actually implement `Display`, so `Debug` is currently the only way to format `Duration`s. I think that's wrong, and `Duration` should get a `Display` implementation, but in the meantime there's no harm in making the `Debug` formatting respect `width` rather than ignore it.

I chose the default alignment to be left-aligned. The general rule Rust uses is: numeric types are right-aligned by default, non-numeric types left-aligned. It wasn't clear to me whether `Duration` is a numeric type or not. The fact that a formatted `Duration` can end with suffixes of variable length (`"s"`, `"ms"`, `"µs"`, etc.) made me lean towards left-alignment, but it would be trivial to change it.

Fixes issue rust-lang#88059.
bors added a commit to rust-lang-ci/rust that referenced this issue Sep 24, 2021
Make `Duration` respect `width` when formatting using `Debug`

When printing or writing a `std::time::Duration` using `Debug` formatting, it previously completely ignored any specified `width`. This is unlike types like integers and floats, which do pad to `width`, for both `Display` and `Debug`, though not all types consider `width` in their `Debug` output (see e.g. rust-lang#30164). Curiously, `Duration`'s `Debug` formatting *did* consider `precision`.

This PR makes `Duration` pad to `width` just like integers and floats, so that
```rust
format!("|{:8?}|", Duration::from_millis(1234))
```
returns
```
|1.234s  |
```

Before you ask "who formats `Debug` output?", note that `Duration` doesn't actually implement `Display`, so `Debug` is currently the only way to format `Duration`s. I think that's wrong, and `Duration` should get a `Display` implementation, but in the meantime there's no harm in making the `Debug` formatting respect `width` rather than ignore it.

I chose the default alignment to be left-aligned. The general rule Rust uses is: numeric types are right-aligned by default, non-numeric types left-aligned. It wasn't clear to me whether `Duration` is a numeric type or not. The fact that a formatted `Duration` can end with suffixes of variable length (`"s"`, `"ms"`, `"µs"`, etc.) made me lean towards left-alignment, but it would be trivial to change it.

Fixes issue rust-lang#88059.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

4 participants