Pre-RFC: Adding minutes & hours API to time::Duration

Summary

This RFC would add the following methods to time::Duration;

impl Duration {
    fn from_mins(mins: u64) -> Self;
    fn from_hours(hours: u64) -> Self;
    fn as_mins(&self) -> u64;
    fn as_hours(&self) -> u64;
}

Motivation

When using time::Duration for longer running tasks, such as background processes, or for user facing output having constructors and accessors for minutes and hours would reduce a small amount of boilerplate that can occur frequently in these kinds of programs. It adds more semantic way to create and use time::Duration.

Current

// minutes
duration.as_secs() / 60

// hours
duration.as_secs() / 3600
// or to be more semantically clear.
duration.as_secs() / 60 / 60

Proposed

// minutes
duration.as_mins()
// hours
duration.as_hours()

Drawbacks

We could not add these methods as it could be seen as too niche, preferring to defer this functionality to third-party crates.

Unresolved questions

  • Should it be hours or hrs? hrs would match the shortened name scheme, however it might not be as clear as hours, and hours is only one character longer than mins.
2 Likes

We have tried adding these before, could you address the comments raised in the PR?

2 Likes

Thank you for the link, I can't believe I missed this!

So to address the feedback, which I believe is that these methods, namely hours could be misused in a way that would outweigh their usefulness due to how infrequently this pattern appears.

The two use cases I saw considered in that RFC was simulation software and long running backend processes. I would say that this API would be more frequently used in user facing applications, system measurement tools, and particularly embedded applications where external timers like cron might not be available.

I would agree with not adding days or anything beyond, however I don't think it's unreasonable to have tasks that need to be run in an hour, or for the next few hours.

1 Like
// hours
duration.as_secs() * 120

You mean 3600, right?

2 Likes

Whoopsie! This right here is exhibit A as to why these methods should exist!

4 Likes

I think have methods for minutes and hours would be great.

I guess I'll go ahead and start a bikeshed: what about using f64 instead of u64? I know u64 is consistent with the existing Duration::from_*() methods, but I'm much more likely to have a fractional minute or hour than I am a fractional milli/micro/nano second.

My personal ideal would be supporting both f64 and u64 somehow (I'm not really a fan of having a bunch of *_f32() and *_f64() suffixed methods)... maybe with generics? I'm not sure what the right trait bound would be though.

This made me aware of another mistake in the proposal:

// minutes
duration.as_secs() * 60

should be

duration.as_secs() / 60

As I understand it, the main concern in this thread was that it would encourage using the API in the wrong way.

For example, someone could write duration.as_hours() / 24. to get the number of days, which might produce the wrong result because of daylight saving. To do this properly, you need a library like chrono.

According to this comment, the main use case of std::time::Duration is benchmarking, where converting to/from hours or days is not needed.

That seems like a fairly large assumption as Rust gets used for higher-level things. To avoid this:

The API could be:

duration.as_approximate_hours();
duration.as_approximate_minutes();
duration.of_approximate_minutes( .. );

etc.

It would meet the use-cases while clearly signaling that there is something inexact about the duration which should then prompt the user to read the docs which could explain those issues.

This would make the API useful to those needing higher-level (beyond benchmarking) kinds of durations without setting up the wrong expectations.

1 Like

Rather than supporting f64 or similar, it might be better to have:

Duration::from_approximate_days_hours_minutes_seconds( ... )
Duration::from_approximate_hours_minutes( ... )
etc.

For higher-level things, you should probably use something like chrono instead, which also supports days and larger time spans.