# Duration has no Rem implementation?

**URL:** <https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117>\
**Category:** language design\
**Created:** [February 11, 2022, 9:52pm UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117 "2022-02-11T21:52:40Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![simbleau](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/simbleau/32/9053_2.png) [@simbleau](https://internals.rust-lang.org/u/simbleau)\
**Post date:** [February 11, 2022, 9:52pm UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/1 "2022-02-11T21:52:40Z")

</div>

I just discovered `std::time::Duration` has no implementation of `std::ops::Rem`.

Is there some nuanced reasons this is the case? Seems like low-hanging fruit to improve the std library.

Why should this be implemented?

> [@Duration has no Rem implementation?](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/5):
>
> As a standard library construct, everything therein should have a high standard of usefulness, which includes eagerly implementing common traits for high operability. Rem, in my humble opinion, is a basic and common operation. Therefore I see Duration lacking basic operability. To circumnavigate this oversight, one has to convert each duration to nanos, modulo the operands, and reconstruct a duration from the remaining nanos. This is rather poor ergonomics.

e.g.

How would this look?

`Duration::ZERO % Duration::ZERO` **PANIC**

`Duration::from_seconds(10) % Duration::from_seconds(3) = Duration::from_seconds(1)`

---

<div class="post-metadata">

**Author:** ![SkiFire13](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skifire13/32/7579_2.png) [@SkiFire13](https://internals.rust-lang.org/u/SkiFire13)\
**Post date:** [February 11, 2022, 10:20pm UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/2 "2022-02-11T22:20:46Z")

</div>

> [@simbleau](#):
>
> Duration::ZERO % Duration::ZERO = Duration::ZERO

This doesn't feel right. I would prefer integer like semantics where division/remainder by 0 results in a panic.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [February 11, 2022, 10:55pm UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/3 "2022-02-11T22:55:44Z")

</div>

Reminder that whenever you propose an addition, you should say _why_ you think it should exist.

The fact that it _could_ exist is not sufficient.

> [@simbleau](#):
>
> Duration::from\_seconds(10) % Duration::from\_seconds(3) = Duration::from\_seconds(1)

This seems reasonable, though I agree with SkiFire that `% Duration::ZERO` should behave like `% 0_u32` does.

---

<div class="post-metadata">

**Author:** ![simbleau](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/simbleau/32/9053_2.png) [@simbleau](https://internals.rust-lang.org/u/simbleau)\
**Post date:** [February 11, 2022, 11:09pm UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/4 "2022-02-11T23:09:54Z")

</div>

Fair point, and agreed.

---

<div class="post-metadata">

**Author:** ![simbleau](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/simbleau/32/9053_2.png) [@simbleau](https://internals.rust-lang.org/u/simbleau)\
**Post date:** [February 11, 2022, 11:20pm UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/5 "2022-02-11T23:20:48Z")

</div>

As a standard library construct, everything therein should have a high standard of usefulness, which includes eagerly implementing common traits for high operability. Rem, in my humble opinion, is a basic and common operation. Therefore I see Duration lacking basic operability.

To circumnavigate this oversight, one has to convert each duration to nanos, modulo the operands, and reconstruct a duration from the remaining nanos. This is rather poor ergonomics.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [February 11, 2022, 11:34pm UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/6 "2022-02-11T23:34:33Z")

</div>

What about `Duration::{pow, sqrt}` too? I actually needed to use these recently to calculate the standard deviation of some durations. Despite me needing to use them, these feel too far away from the intended purpose of `Duration` and I think it's better that I had to fallback to converting to a `f64` and back. It's hard to say exactly where the line should be drawn on the APIs that make sense for a `Duration`.

---

<div class="post-metadata">

**Author:** ![elidupree](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/elidupree/32/4304_2.png) [@elidupree](https://internals.rust-lang.org/u/elidupree)\
**Post date:** [February 11, 2022, 11:49pm UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/7 "2022-02-11T23:49:03Z")

</div>

`pow` and `sqrt` cannot easily be written in a dimensionally correct way. A `Duration` represents an amount of time; square a `Duration`, and you get an amount of "time^2", which would not be a `Duration`, so there would need to be a new type for it, which clearly isn't worth it.

On the other hand, if I understand division-with-rounding right, the remainder when dividing a Duration by either a `Duration` or a dimensionless `u32` is properly a `Duration`.

However, we don't currently have `Duration: Div<Duration>`, and it does seem odd to have `Duration: Rem<Duration>`, as this proposal suggests, without `Duration: Div<Duration>`.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [February 12, 2022, 12:00am UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/8 "2022-02-12T00:00:15Z")

</div>

Interesting prior art: .Net's `TimeSpan` (which is basically a signed `Duration`) turns out to have multiplication and division ~~by both `TimeSpan` and `f64`~~ (EDIT: this was misleading, see @elidupree's comment below instead), but not remainder by either, per [https://docs.microsoft.com/en-us/dotnet/api/system.timespan?view=net-6.0#operators](https://docs.microsoft.com/en-us/dotnet/api/system.timespan?view=net-6.0#operators).

(I do agree, from a math and dimensional analysis perspective, that duration remainder is perfectly reasonable, though.)

---

<div class="post-metadata">

**Author:** ![elidupree](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/elidupree/32/4304_2.png) [@elidupree](https://internals.rust-lang.org/u/elidupree)\
**Post date:** [February 12, 2022, 12:15am UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/9 "2022-02-12T00:15:21Z")

</div>

Nitpick: It doesn't have `TimeSpan * TimeSpan` (which would be dimensionally incorrect), but does have

- `TimeSpan * f64 -> TimeSpan`
- `f64 * TimeSpan -> TimeSpan`
- `TimeSpan / f64 -> TimeSpan `
- `TimeSpan / TimeSpan -> f64`

all of which are correct. (And it doesn't have % because it doesn't interoperate with integers, I guess?)

Adding `Duration / Duration -> u128` would make sense to me, and then `Duration % Duration -> Duration` and `Duration % uX -> Duration` would make sense

---

<div class="post-metadata">

**Author:** ![simbleau](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/simbleau/32/9053_2.png) [@simbleau](https://internals.rust-lang.org/u/simbleau)\
**Post date:** [February 12, 2022, 12:26am UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/10 "2022-02-12T00:26:03Z")

</div>

At a high level, `Duration` is an abstract wrapper of time. At a functional level, there is a level of indirection between the conversion to a discrete unit like milliseconds or nanoseconds. Therefore applying a power or square root to unit-less time doesn't really make sense.

---

<div class="post-metadata">

**Author:** ![toc](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/toc/32/6692_2.png) [@toc](https://internals.rust-lang.org/u/toc)\
**Post date:** [February 12, 2022, 4:14am UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/11 "2022-02-12T04:14:19Z")

</div>

> [@simbleau](#):
>
> Therefore applying a power or square root to unit-less time doesn't really make sense.

Right, but sometimes you have to make e.g. exponentially increasing durations and it's nice to be able to operate within the type's natural precision (as of this writing a `u64` seconds and a `u32` nanoseconds). Ideally there'd be a `(u64, u32/1e9)` fixed point to do unitless operations with, but that's not currently the case.

Edit: which also means these nontrivial additions are equivalent to adding a weird `(u64, u32/1e9)` fixed point type to the language.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [February 12, 2022, 4:29am UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/12 "2022-02-12T04:29:27Z")

</div>

> [@toc](#):
>
> Right, but sometimes you have to make e.g. exponentially increasing durations

Note that you can do that with [https://doc.rust-lang.org/std/time/struct.Duration.html#method.mul\_f64](https://doc.rust-lang.org/std/time/struct.Duration.html#method.mul_f64) -- either by putting the exponent on the float, or by using that every time through the loop.

---

<div class="post-metadata">

**Author:** ![simbleau](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/simbleau/32/9053_2.png) [@simbleau](https://internals.rust-lang.org/u/simbleau)\
**Post date:** [February 12, 2022, 1:59pm UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/13 "2022-02-12T13:59:49Z")

</div>

What is the standard procedure for making a PR for this addition?

Do I make a PR to the rust GitHub repository under a specific branch, like nightly?

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [February 12, 2022, 3:36pm UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/14 "2022-02-12T15:36:49Z")

</div>

PRs are done on “master” which is the branch from which nightly is built. New API is usually first introduced as unstable, but AFAIK that kind of thing doesn’t work for trait implementations\[1\], which are always instantly stabilized. So _can_ open a PR now on master, then either there will be a formal procedure for accepting the PR on in the PR thread itself (via a “final commenting period”, “FCP”), or perhaps an RFC might be necessary though that seems unlikely to me, I think… (I’m not 100% sure what the criterions here are though).

For more feedback/questions you can ask here or also on [https://rust-lang.zulipchat.com/](https://rust-lang.zulipchat.com/).

* * *

1. This means, you’d need to add a `#[(feature = "some_feature_name", since = "1.61.0")]` attribute to the `impl`, where you invent some sensible (but in practice irrelevant) feature name for your PR instead of “`some_feature_name`”.

---

<div class="post-metadata">

**Author:** ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)\
**Post date:** [February 12, 2022, 6:42pm UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/15 "2022-02-12T18:42:21Z")

</div>

> [@simbleau](#):
>
> As a standard library construct, everything therein should have a high standard of usefulness

Complete agreement here.

> [@simbleau](#):
>
> which includes eagerly implementing common traits for high operability

Not at all; we do, in fact, have a high standard of usefulness, and we don't automatically add every trait implementation that _might_ make sense, especially if we don't actually have people presenting specific use cases.

Could you talk more about your use case for wanting a remainder operation on time? Not a way you think someone _might_ use it; a way _you concretely want to use it in production Rust code_. No hypotheticals, please; that's how we can end up with functions that nobody actually uses.

---

<div class="post-metadata">

**Author:** ![simbleau](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/simbleau/32/9053_2.png) [@simbleau](https://internals.rust-lang.org/u/simbleau)\
**Post date:** [February 12, 2022, 7:38pm UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/16 "2022-02-12T19:38:51Z")

</div>

My case is actually (I think) common.

I need a monitor thread to poll a value at routine times. Let's say I need to observe the CPU load 4 times a second. Thus, I need to determine (after a poll finishes) how long to sleep for the next poll time.

You would end up with some code like:

```rust
let start_time = Instant::now();
let frequency = Duration::from_seconds(0.25);
loop {
                        // Sleep until next poll time
                        let time_since_start = (Instant::now() - start_time).as_nanos();
                        let time_till_next = frequency.as_nanos() - (time_since_start % frequency.as_nanos());
                        let sleep_time = Duration::from_nanos(time_till_next as u64);
                        thread::sleep(sleep_time);
                       
                        // Poll CPU here
}

```

With `Rem<Duration>` implemented, we could have:

```rust
let start_time = Instant::now();
let frequency = Duration::from_seconds(0.25);
loop {
                        // Sleep until next poll time
                        let time_since_start = Instant::now() - start_time;
                        let sleep_time = frequency - (time_since_start % frequency);
                        thread::sleep(sleep_time);
                       
                        // Poll CPU here
}

```

_Note: The naive thing to do would be to sleep for 0.25 seconds after polling in the loop, but this is incorrect, and will cause accumulating delay over time, especially if the procedure of polling your value is long._

---

<div class="post-metadata">

**Author:** ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)\
**Post date:** [February 12, 2022, 8:25pm UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/17 "2022-02-12T20:25:03Z")

</div>

I would probably write that by using a [periodic timer](https://docs.rs/async-io/1.6.0/async_io/struct.Timer.html), rather than a sleep, which would handle "wake on next expiry" automatically, and may also support aligning that timer with others on the system to reduce overall wakeups.

(I think there are equivalent timer crates for sync code, I just don't know which one to recommend.)

```rust
let timer = Timer::interval(Duration::from_millis(250));
while let Some(instant) = timer.next().await {
    // Poll CPU here
}

```

Also, in your second example, I think you wanted `time_since_start % frequency`, rather than the other way around. You may also have wanted to drop the `as_nanos()` from the previous line, since this should be `Duration % Duration` giving a `Duration`.

I do appreciate the concrete use case, but it seems like one better served by a different approach, and by something wrapped into a reusable component rather than open-coded.

---

<div class="post-metadata">

**Author:** ![SkiFire13](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skifire13/32/7579_2.png) [@SkiFire13](https://internals.rust-lang.org/u/SkiFire13)\
**Post date:** [February 12, 2022, 9:55pm UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/18 "2022-02-12T21:55:05Z")

</div>

I don't think the two snippets are equivalent. In the second one if `time_since_start` is less than half the value of `frequency` then you won't sleep for long enough. You'll still need to do all the operations of the first version, you'll just be able to skip a couple of `as_nanos()` and `Duration::from_nanos`.

---

<div class="post-metadata">

**Author:** ![simbleau](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/simbleau/32/9053_2.png) [@simbleau](https://internals.rust-lang.org/u/simbleau)\
**Post date:** [February 13, 2022, 5:38pm UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/19 "2022-02-13T17:38:47Z")

</div>

I have fixed the logical typo oversight in the second snippet.

---

<div class="post-metadata">

**Author:** ![simbleau](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/simbleau/32/9053_2.png) [@simbleau](https://internals.rust-lang.org/u/simbleau)\
**Post date:** [February 13, 2022, 5:48pm UTC](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117/20 "2022-02-13T17:48:21Z")

</div>

I'm not entirely sure this is correct...

Here's why:

`timer waits 250ms`  
`polling takes 12ms`  
`timer waits another 250ms`  
^ timer should have waited `238ms`.

This implementation would antedate polling and have increasing inaccuracy over time.

[Next page](https://internals.rust-lang.org/t/duration-has-no-rem-implementation/16117.md?page=2)
