# Time units in std::time

**URL:** <https://internals.rust-lang.org/t/time-units-in-std-time/8024>\
**Category:** libs\
**Created:** [July 21, 2018, 12:54pm UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024 "2018-07-21T12:54:32Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![newpavlov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/newpavlov/32/3290_2.png) [@newpavlov](https://internals.rust-lang.org/u/newpavlov)\
**Post date:** [July 21, 2018, 12:54pm UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024/1 "2018-07-21T12:54:32Z")

</div>

> <https://github.com/rust-lang/rust/pull/52556>

The main unresolved question is: should we include minute, hour and day or not? And if yes, how they should be named, simply `DAY`, or something like `SI_DAY`, `STD_DAY`?

---

<div class="post-metadata">

**Author:** ![kennytm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kennytm/32/161_2.png) [@kennytm](https://internals.rust-lang.org/u/kennytm)\
**Post date:** [July 21, 2018, 3:40pm UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024/2 "2018-07-21T15:40:52Z")

</div>

IMO We should either name them `DAY`, `HOUR` and `MINUTE`, or just don’t include them at all.

## Prior art: Name conventions from other standard libraries

| Language | ns | µs | ms | s | min | h | day | week |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| [C#](https://msdn.microsoft.com/en-us/library/system.timespan(v=vs.110).aspx) | - | - | Milliseconds | Seconds | Minutes | Hours | Days | - |
| [C++](https://en.cppreference.com/w/cpp/chrono/duration) (types)\* | nanoseconds | microseconds | milliseconds | seconds | minutes | hours | days | weeks |
| C++ (literal suffix) | ns | us | ms | s | min | h | - | - |
| [D](https://dlang.org/phobos/core_time.html)\* | nsecs | usecs | msecs | seconds | minutes | hours | days | weeks |
| [Dart](https://api.dartlang.org/stable/1.24.3/dart-core/Duration-class.html) | - | Microseconds | Milliseconds | Seconds | Minutes | Hours | Days | - |
| [Go](https://golang.org/pkg/time/#Duration) | Nanosecond | Microsecond | Millisecond | Second | Minute | Hour | - | - |
| [Java](https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html) | Nanos | - | Millis | Seconds | Minutes | Hours | Days | - |
| [Nim](https://nim-lang.org/docs/times.html#milliseconds,int)\* | - | - | milliseconds | seconds | minutes | hours | days | - |
| [Python](https://docs.python.org/3/library/datetime.html#timedelta-objects) | - | microseconds | milliseconds | seconds | minutes | hours | days | weeks |
| [Rust (std)](https://doc.rust-lang.org/std/time/struct.Duration.html) | nanos | micros | millis | secs | - | - | - | - |
| [Rust (chrono)](https://docs.rs/chrono/0.4.4/chrono/struct.Duration.html) | nanoseconds | microseconds | milliseconds | seconds | minutes | hours | days | weeks |

Note\*:

- C++20 also defines “months” (exactly 1/12 years) and “years” (exactly 365.2425 days). I don’t see how these can be useful.
- D also defines “hnsecs” (100 nanoseconds), a unit often used in Windows APIs.
- Nim’s `TimeInterval` is not calendar-independent.

---

<div class="post-metadata">

**Author:** ![Tom-Phinney](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tom-phinney/32/3299_2.png) [@Tom-Phinney](https://internals.rust-lang.org/u/Tom-Phinney)\
**Post date:** [July 21, 2018, 3:41pm UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024/3 "2018-07-21T15:41:25Z")

</div>

Why not add an si!() macro that permits specifying a constant duration, or simply an SI unit? E.g.,

```rust
let observation_interval: duration = si!(3 da 6 hr 19.05 s 273 ns);
let timeout: duration = si!(1500 us);
CONST SI_US: duration = si!(µs);

```

Since the underlying representation is UTF-8, both `1500 us` and `1500 µs` can be acceptable. A future RFC could include SI scaling units if that proved desirable (though personally I’d rather not see `1.5 kius` as a way of writing `1536 µs`).

**Edit** : Added example of an isolated unit.

---

<div class="post-metadata">

**Author:** ![newpavlov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/newpavlov/32/3290_2.png) [@newpavlov](https://internals.rust-lang.org/u/newpavlov)\
**Post date:** [July 21, 2018, 4:05pm UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024/4 "2018-07-21T16:05:04Z")

</div>

Ideally I would prefer to have custom literal suffixes à la C++. So we could write something like this:

```rust
use std::time::suffixes::*;

let observation_interval = 3d + 6h + 19s + 273us;
// for those who don't like `us`
let timeout = 1500µs;

```

Plus don’t forget that day, hour and minute are not SI units per se.

---

<div class="post-metadata">

**Author:** ![Tom-Phinney](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tom-phinney/32/3299_2.png) [@Tom-Phinney](https://internals.rust-lang.org/u/Tom-Phinney)\
**Post date:** [July 21, 2018, 4:22pm UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024/5 "2018-07-21T16:22:50Z")

</div>

> [@newpavlov](#):
>
> Plus don’t forget that day, hour and minute are not SI units per se.

True. But `si_extended!()` is too cumbersome a macro name. The problem with `day` or `da` is of course the occasional leap-second, which currently occurs about every 18 months but which will become more frequent over the centuries due to earth-moon tidal momentum transfer. That same leap-second is what complicates hour and minute, since the extra second is represented by 23:59:60 .

---

<div class="post-metadata">

**Author:** ![kennytm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kennytm/32/161_2.png) [@kennytm](https://internals.rust-lang.org/u/kennytm)\
**Post date:** [July 21, 2018, 4:51pm UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024/6 "2018-07-21T16:51:13Z")

</div>

Minutes, hours and days are considered “[Non-SI units accepted for use with the International System of Units](https://www.bipm.org/en/publications/si-brochure/table6.html)” (with standardized symbol and conversion factor `1min = 60s`, `1h = 3600s` and `1d = 86400s`), which I think is fine. They are not in SI proper simply because they aren’t related to seconds by factors of 10n.

BTW, for easy tracking, we have _rejected_ additions of [`Durations::from_{minutes, hours, days}`](https://github.com/rust-lang/rust/pull/47097) previously because of confusion when a timezone change is involved,

```rust
// cargo-deps: chrono, chrono-tz
extern crate chrono;
extern crate chrono_tz;
use chrono::{Duration, TimeZone};
fn main() {
    let eastern_time = chrono_tz::US::Eastern;
    let datetime_1 = eastern_time.ymd(2018, 3, 11).and_hms(1, 59, 59);
    let datetime_2 = eastern_time.ymd(2018, 3, 11).and_hms(3, 0, 0);
    assert_eq!(datetime_2 - datetime_1, Duration::seconds(1));
}

```

I don’t think leap seconds is a blocking issue, [chrono](https://docs.rs/chrono/0.4.4/chrono/naive/struct.NaiveTime.html#leap-second-handling) for instance simply treated `hh:mm:60` as the same as `hh:(mm+1):00`.

---

<div class="post-metadata">

**Author:** ![Tom-Phinney](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tom-phinney/32/3299_2.png) [@Tom-Phinney](https://internals.rust-lang.org/u/Tom-Phinney)\
**Post date:** [July 21, 2018, 8:14pm UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024/7 "2018-07-21T20:14:25Z")

</div>

> [@kennytm](#):
>
> I don’t think leap seconds is a blocking issue, [chrono](https://docs.rs/chrono/0.4.4/chrono/naive/struct.NaiveTime.html#leap-second-handling) for instance simply treated `hh:mm:60` as the same as `hh:(mm+1):00` .

Well `23:59:60`, `23:60:00`, and `24:00:00` are all problematic for software that expects a value in the range `(00..=23).(00..=59).(00..=59)`. Nor can the extra second conveniently be ignored, as it might turn up in logs, and even worse in the computation of a derivative as in speed, flow rate, etc.

Edited to show ranges in Rust syntax.

---

<div class="post-metadata">

**Author:** ![kennytm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kennytm/32/161_2.png) [@kennytm](https://internals.rust-lang.org/u/kennytm)\
**Post date:** [July 21, 2018, 8:31pm UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024/8 "2018-07-21T20:31:14Z")

</div>

That’s not a concern because we are only talking about durations here, not time points.

---

<div class="post-metadata">

**Author:** ![Tom-Phinney](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tom-phinney/32/3299_2.png) [@Tom-Phinney](https://internals.rust-lang.org/u/Tom-Phinney)\
**Post date:** [July 21, 2018, 8:51pm UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024/9 "2018-07-21T20:51:34Z")

</div>

Then I don't understand your prior statement

> [@kennytm](#):
>
> I don’t think leap seconds is a blocking issue

I was raising the unpredictable leap-second as the likely reason why minutes, hours and days had not made it into SI units. I was not intending to imply that `duration` would ever involve leap-seconds directly (though a duration computed from the difference of two time stamps obviously would have to take such a possibility into account). The issue over leap-seconds is why many industrial automation standards use [TAI](https://www.timeanddate.com/time/international-atomic-time.html) rather than UTC, so that the leap-second irregularity does not enter into computations of duration.

---

<div class="post-metadata">

**Author:** ![kennytm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kennytm/32/161_2.png) [@kennytm](https://internals.rust-lang.org/u/kennytm)\
**Post date:** [July 21, 2018, 10:36pm UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024/10 "2018-07-21T22:36:16Z")

</div>

We’re talking Rust here, how SI categorizes a unit is out of scope.

If you read [PR 47097](https://github.com/rust-lang/rust/pull/47097) I’ve linked above you’ll see the reason “days” and “hours” being rejected was solely because of timezone change (e.g. 2018 Mar 11th 01:00:00 EST + 24 hours = 2018 Mar 12th 02:00:00 EDT could be unexpected to humans) and process durability (your process will die before the day ends, consider a cron job instead). Nobody from the team mentioned leap seconds or SI, which is why I say it’s not a blocker or concern.

Further, “minutes” was allowed in 47097 but simplifying a factor of mere 60 doesn’t provide much advantage, and thus the entire PR was abandoned. The discussion from 47097 affects this PR here, as they have the equivalent semantics.

---

<div class="post-metadata">

**Author:** ![Tom-Phinney](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tom-phinney/32/3299_2.png) [@Tom-Phinney](https://internals.rust-lang.org/u/Tom-Phinney)\
**Post date:** [July 22, 2018, 12:59am UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024/11 "2018-07-22T00:59:11Z")

</div>

My initial post in this thread attempted to point out that a simple macro could provide a way to write `duration` in proper SI units, with `us` as a supported alternative to the harder-to-enter unit `µs`. Unfortunately my follow-up posts derailed into a discussion about SI units. 😢 apologies

---

<div class="post-metadata">

**Author:** ![vitalyd](https://avatars.discourse-cdn.com/v4/letter/v/edb3f5/32.png) [@vitalyd](https://internals.rust-lang.org/u/vitalyd)\
**Post date:** [July 22, 2018, 1:54am UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024/12 "2018-07-22T01:54:48Z")

</div>

> [@newpavlov](#):
>
> Ideally I would prefer to have custom literal suffixes à la C++. So we could write something like this:
> 
> ```rust
> use std::time::suffixes::*;
> 
> let observation_interval = 3d + 6h + 19s + 273us;
> // for those who don't like `us`
> let timeout = 1500µs;
> 
> ```

This. I’d love for there to be custom suffixes - I think that’s a really cool feature of C++, and works particularly nicely with time units.

---

<div class="post-metadata">

**Author:** ![Tom-Phinney](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tom-phinney/32/3299_2.png) [@Tom-Phinney](https://internals.rust-lang.org/u/Tom-Phinney)\
**Post date:** [July 22, 2018, 6:08am UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024/13 "2018-07-22T06:08:27Z")

</div>

I canceled a reply to the same @newpavlov post about six hours ago because I concluded that [my original suggestion](https://internals.rust-lang.org/t/time-units-in-std-time/8024/3), that of a macro to handle [SI time units and non-SI time units accepted for SI](https://en.wikipedia.org/wiki/International_System_of_Units), was the best approach and it had already been shared. The problem I have with the C++ approach is that it is **not** SI precisely because it appends alphanumeric suffixes to numeric values, whereas SI requires there to be an intervening space between the value (which could be symbolic) and the SI suffix. The si!() macro would need such space separation to parse, thus resulting in contained sequences that actually are **valid** SI.

---

<div class="post-metadata">

**Author:** ![Tom-Phinney](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tom-phinney/32/3299_2.png) [@Tom-Phinney](https://internals.rust-lang.org/u/Tom-Phinney)\
**Post date:** [July 22, 2018, 6:27am UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024/14 "2018-07-22T06:27:03Z")

</div>

Side rant: I suppose that my quest for SI units is on a par with the desire that the US would use the metric system. I am so-o-o tired of reading `mb` in a press release when `MB` was intended. The fact that there is an almost ten-orders-of-magnitude difference between the two units seems to escape the innumerate authors.

---

<div class="post-metadata">

**Author:** ![bujiraso](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bujiraso/32/4286_2.png) [@bujiraso](https://internals.rust-lang.org/u/bujiraso)\
**Post date:** [July 22, 2018, 11:01am UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024/15 "2018-07-22T11:01:00Z")

</div>

Since these are hard constants, I dislike the idea of including these units as simple words like “DAY”, “HOUR”, etc., as I find it lacks enough information to describe to naive developers if there is or is not extra work happening on the back-end around the fuzzy points like DST. Experienced developers are less interesting to contemplate for this naming choice as they will generally follow good practices, read documentation, and test properly to figure it out.

With that in mind, I actually think something like SI\_DAY is a good idea, as it encourages the naive developer to take a moment and think “oh wait what’s the SI mean?” and nudges them to take a quick look at the docs. An experienced developer will notice that they’re all constants in measures of seconds or will know about SI and find it obvious.

Despite my clear preference, @kennytm’s post is very clear in showing that this is not the existing standard, so if we decide to follow suit with most of the other languages in the naming scheme of this fairly common ambiguity, then at bare minimum we are in parity with other languages, so that’s okay, too!

---

<div class="post-metadata">

**Author:** ![killercup](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/killercup/32/3256_2.png) [@killercup](https://internals.rust-lang.org/u/killercup)\
**Post date:** [July 22, 2018, 2:35pm UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024/16 "2018-07-22T14:35:51Z")

</div>

More prior art: Diesel has an interval DSL that implements methods like `hours`, and `minutes` on `i32`, `i64`, and `f64` and return `PgInterval` (our representation of the Postgres interval type): [https://docs.rs/diesel/1.2.1/diesel/pg/expression/extensions/trait.IntervalDsl.html](https://docs.rs/diesel/1.2.1/diesel/pg/expression/extensions/trait.IntervalDsl.html)

---

<div class="post-metadata">

**Author:** ![killercup](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/killercup/32/3256_2.png) [@killercup](https://internals.rust-lang.org/u/killercup)\
**Post date:** [July 22, 2018, 2:40pm UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024/17 "2018-07-22T14:40:23Z")

</div>

As [mentioned on reddit](https://www.reddit.com/r/rust/comments/90p21w/time_units_in_stdtime/e2scdfb/), a parser for a subset of ISO8601 duration strings as a `const fn` would make a pretty sweet constructor for Duration, too. (Though currently not possible to implement because of `const fn` “RFC-needed” limits, and it’s also not possible to mark the `from_str` function in an impl of `FromStr` as a `const fn`, sadly.)

---

<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:30am UTC](https://internals.rust-lang.org/t/time-units-in-std-time/8024/18 "2019-03-25T08:30:34Z")

</div>

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