std time
— 2019-06-25
Over the past month we've been hard at work to add time
support to the
Runtime crate. One of the things we've had to think about has been examples.
Which means we've had a chance to become intimately familiar with the good and
less good parts of the std::time
API.
In this post we'll look at the std::time
API, and some of the proposed
changes to smooth things out a bit. Also disclaimer: I've been involved with
these proposals, hehe.
Time Types
A quick refresher on what's inside std::time
. There are two types you need to
know about: Duration
and Instant
. An Instant
represents a specific
point in time. A Duration
is a relative time offset. This is different from
some languages which only have a single time type. Personally I quite like
Rust's approach of having two.
Let's put the time types together to first get the current timestamp. Then sleep the thread for 2 seconds. And finally print how much time has passed.
use std::time::{Duration, Instant};
use std::thread::sleep;
let now = Instant::now();
sleep(Duration::from_secs(2));
println!("{}", now.elapsed().as_secs());
Creating Durations
As we've seen before, durations can be created using
Duration::from_secs(n)
. This works well, but is rather verbose. Not only do
we have to import two layers deep, we also need to remember the name of the
method. All in all it takes some getting used to.
Which is why in rust-lang/rust#57391 there's a proposal to add constants to the time module. These constants would represent a single unit of time, which could then be used for addition, substraction and multiplication. E.g. 5 milliseconds is 5 times the millisecond constant.
The exact API is still undecided. But I think it would be nice if the APIs
were brief, and exposed directly under std::time
. This would allow us to
rewrite our example as:
use std::time::Instant;
use std::thread::sleep;
let now = Instant::now();
sleep(2 * time::SEC);
println!("{}", now.elapsed().as_secs());
Creating Instants
Just like creating Duration
s can likely be simplified, so can creating
Instant
s. The most common way of creating an Instant
is by calling
Instant::now
. This too has the problem that we need to remember the exact
type, and call two layers deep into the std
hierarchy.
Which is why
rust-lang/rust#62114
proposes to add a time::now
method. This behaves the same as
time::Instant::now
, but should be more pleasant to use. An example:
use std::{time, thread};
let now = time::now();
thread::sleep(2 * time::SEC);
println!("{}", now.elapsed().as_secs());
Debug Durations
One of the first gotchas you might experience when dealing with time in Rust
is that you cannot simply print a Duration
. If you're like me, you'll run
into this, and after some searching find out that you need to specify a
resolution before you can print. E.g. dur.as_secs
or dur.as_millis
.
This is not great because if you're doing exploratory programming and/or debugging, you may not know the resolution up front. Which means you might need a few tries to find the right resolution. Which isn't a dealbreaker, but it takes speed out of the process.
Instead it would be nice if we could print Duration
s (and Instant
s for
that matter), where they would provide data for all resolutions it
encapsulates.
Duration {
secs: 6,
millis: 6225,
micros: 6224768,
nanos: 6224767054,
}
Perhaps we might also need a pretty-printed version of this. E.g. print
6.225 secs
as the Display
impl. I'm not sure whether that's acceptable
for a stdlib extension, but I sure know that it would make debugging time a
lot easier.
Anyway, let's apply this to our example:
use std::{time, thread};
let now = time::now();
thread::sleep(2 * time::SEC);
dbg!(now.elapsed());
Conclusion
In this post we've talked about the std::time
module, and some of the
changes that could be made to smooth out the workflow.
I hope this was a useful insight into how the std::time
module can be
improved. I figured I'd write this post because I spent some time earlier
today filing an issue, and thought sharing an overarching vision might be
nice.
Thanks for reading all, and hope you have a lovely (non-scorched) week!