# \[Pre-RFC\] More convenient Duration formatting

**URL:** <https://internals.rust-lang.org/t/pre-rfc-more-convenient-duration-formatting/5384>\
**Category:** libs\
**Created:** [June 10, 2017, 10:32am UTC](https://internals.rust-lang.org/t/pre-rfc-more-convenient-duration-formatting/5384 "2017-06-10T10:32:13Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![birkenfeld](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/birkenfeld/32/1150_2.png) [@birkenfeld](https://internals.rust-lang.org/u/birkenfeld)\
**Post date:** [June 10, 2017, 10:32am UTC](https://internals.rust-lang.org/t/pre-rfc-more-convenient-duration-formatting/5384/1 "2017-06-10T10:32:14Z")

</div>

# Summary

This RFC proposes a more convenient method of formatting `std::time::Duration` methods to strings.

# Motivation

The `std::time` API is currently pretty bare-bones, compared to time libraries in other languages. This is because date/time processing is a hairy area, and it is preferred that a `std`-worthy API be iterated outside of `std`. Examples of available 3rd-party libraries are `time` and `chrono`.

Still, for some applications, e.g. measuring time elapsed while a piece of code runs, `std::time` is perfectly usable, except that printing the results in a non-`Debug` manner is tedious. This RFC tries to help in this area, namely adding a method of formatting `Duration` values with some degree of customization.

# Detailed design

This RFC does not propose to implement `Display` on `Duration`. This might be used later for a standards conforming exact representation (see “Alternatives” below). Instead, a new method called `display()` is added, similar to that on `Path`, returning a `Display` struct with a `std::fmt::Display` impl.

This provides the opportunity of adding arguments to `display()`, which is useful since a `Duration` can be expressed in different units, and the string formatting language is not capable of expressing this on its own. The proposed signature is:

```rust
fn display<U: Into<Option<Unit>>>(&self, unit: U) -> Display

```

with

```rust
enum Unit { Secs, Millis, Micros, Nanos }

```

The `std::fmt::Display` impl for `Display` can then format the duration according to the given unit, using the number format given in the format string specification. `None` selects the unit so that the number is above 1. The unit is added to the result unless “alternate” format is requested with `#`.

Examples:

```rust
let d = Duration::new(0, 500_000_000);
format!("{}", d.display(None)) // -> "500 ms"
format!("{}", d.display(Unit::Secs)) // -> "0.5 s"
format!("{:.3}", d.display(Unit::Secs)) // -> "0.500 s"
format!("{}", d.display(Unit::Micros)) // -> "500000 us"
format!("{:#}", d.display(Unit::Micros)) // -> "500000"

```

# How We Teach This

This is a new API with entry in the library reference.

In the book and Rust by Example, there is currently no example using Duration other than as an argument to `thread::sleep`.

# Drawbacks

- When stabilized, will be around forever, might not be useful enough for all cases.

# Alternatives

The `time` crate implements `Display` on its `Duration`, which uses ISO 8601 format (`PxDTy.yyyS`). Standard conforming, but not very readable. The `chrono` crate just reuses `time::Duration`.

# Unresolved questions

- More units? Years, months, days, hours, minutes?
- Can `Unit` be otherwise useful later?
- Instead of `Option<Unit>`, add `Unit::Auto`?
- Swap meaning of alternate/normal format?
- Support exponential notation?

---

<div class="post-metadata">

**Author:** ![zackw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/zackw/32/2071_2.png) [@zackw](https://internals.rust-lang.org/u/zackw)\
**Post date:** [June 10, 2017, 1:27pm UTC](https://internals.rust-lang.org/t/pre-rfc-more-convenient-duration-formatting/5384/2 "2017-06-10T13:27:18Z")

</div>

I like what you propose for sub-second durations, but for longer durations, a human-readable notation in days, hours, minutes, and seconds would be nice. Python’s [`datetime.timedelta`](https://docs.python.org/3/library/datetime.html#timedelta-objects) does this:

```python
>>> print(timedelta(minutes=20, seconds=42.12))
0:20:42.120000
>>> print(timedelta(hours=2, minutes=0, seconds=42))
2:00:42
>>> print(timedelta(days=6, hours=2, minutes=20, seconds=42.12))
6 days, 2:00:42.120000
>>> print(timedelta(days=367, minutes=20))
367 days, 0:20:00

```

That’s using the ` __str__ ` conversion on a timedelta object, which would correspond to `Display` in Rust. Note that unlike ISO 8601 duration notation, the hours, minutes, and seconds fields are never omitted even if they are zero, and it doesn’t try to do years, months, or weeks. I’m not a huge fan of the automatic switching between `%d` and `%.6f` for the seconds field.

---

<div class="post-metadata">

**Author:** ![stebalien](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/stebalien/32/228_2.png) [@stebalien](https://internals.rust-lang.org/u/stebalien)\
**Post date:** [June 10, 2017, 5:02pm UTC](https://internals.rust-lang.org/t/pre-rfc-more-convenient-duration-formatting/5384/3 "2017-06-10T17:02:48Z")

</div>

An alternative would be to introduce `Duration` and `Time` format traits but that would take quite a bit of design work.

---

<div class="post-metadata">

**Author:** ![droundy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/droundy/32/2054_2.png) [@droundy](https://internals.rust-lang.org/u/droundy)\
**Post date:** [June 16, 2017, 10:52pm UTC](https://internals.rust-lang.org/t/pre-rfc-more-convenient-duration-formatting/5384/4 "2017-06-16T22:52:13Z")

</div>

I certainly would prefer `Unit::Auto` over the `Option<Unit>` interface.

I agree with @zackw that support for longer times would be important, particularly in the likely scenario that the `Unit` enum cannot be extended to support additional units. When using longer durations (and in particular non-decimal units), I think the user should be able to print with either combined units or decimal notation. e.g. 1.25 hours in some contexts is easier to read than 1:15, particularly when taken to extremes (1.23421 years is easier to read and compare with other durations (also in years) than the same value expressed in years, weeks, days, hours, and seconds.

It might be good to add a complementary method

```
fn in_units(u: Unit) -> f64

```

which would just do the unit conversion.

Another approach to this task would be to forget all this, and simply define constants (of type `Duration`) for the different units, and then implemnt the `Div` trait between two durations.

```
impl std::ops::Div for Duration {
    type Output = f64;
    fn div(self, rhs: Self) -> f64 ...
}

```

Then we could achieve all the same formatting except the auto-formatting by

```
format!("{} s", d/Duration::second); // -> "0.5 s"

```

etc. Autoformatting could be omitted, or it could be decided that autoformatting is the `Display` method for durations.

---

<div class="post-metadata">

**Author:** ![seanmonstar](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/seanmonstar/32/36_2.png) [@seanmonstar](https://internals.rust-lang.org/u/seanmonstar)\
**Post date:** [June 16, 2017, 11:15pm UTC](https://internals.rust-lang.org/t/pre-rfc-more-convenient-duration-formatting/5384/5 "2017-06-16T23:15:29Z")

</div>

> [@droundy](#):
>
> in the likely scenario that the Unit enum cannot be extended to support additional units.

As an input argument, it probably shouldn't be an `enum` for exactly this reason. Instead, probably constants:

```rust
pub struct Unit(Inner);

impl Unit {
    pub const SECONDS: Unit = Unit(Inner::Seconds);
    pub const MILLIS: Unit = Unit(Inner::Millis);
    // etc
}

enum Inner {
    Seconds,
    Millis,
    Nanos,
    // etc
}

```

Usage as:

```rust
format!("{}", d.display(Unit::MILLIS));

```

With the inner enum private, new variants can be easily added, and new `consts` aren't a breaking change at all.

---

<div class="post-metadata">

**Author:** ![droundy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/droundy/32/2054_2.png) [@droundy](https://internals.rust-lang.org/u/droundy)\
**Post date:** [June 16, 2017, 11:30pm UTC](https://internals.rust-lang.org/t/pre-rfc-more-convenient-duration-formatting/5384/6 "2017-06-16T23:30:11Z")

</div>

I would add that I see no reason for Unit to be a distinct type. What is wrong with these constants being of type `Duration`? That describes their type perfectly well.

To answer my own question, I guess the advantage of a separate type is if you are excited about having the display method include the units. This seems to me very little value to be gained at the cost of introducing an entire new type into the crate, with its whole slew of constants.

---

<div class="post-metadata">

**Author:** ![nikomatsakis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nikomatsakis/32/5410_2.png) [@nikomatsakis](https://internals.rust-lang.org/u/nikomatsakis)\
**Post date:** [June 17, 2017, 1:00am UTC](https://internals.rust-lang.org/t/pre-rfc-more-convenient-duration-formatting/5384/7 "2017-06-17T01:00:02Z")

</div>

> [@seanmonstar](#):
>
> As an input argument, it probably shouldn't be an enum for exactly this reason.

Maybe with RFC [https://github.com/rust-lang/rfcs/pull/2008](https://github.com/rust-lang/rfcs/pull/2008) that concern could be ammeliorated...?

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [March 25, 2019, 8:28am UTC](https://internals.rust-lang.org/t/pre-rfc-more-convenient-duration-formatting/5384/8 "2019-03-25T08:28:39Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
