Using std::time::Duration

I’m trying to work through the gigasecond exercise.

I can’t seem to use std::time::Duration though. I’m getting the impression there’s some conflicting documentation.

I see an example such as Duration::seconds(-2 * 3600 + 2) used in a file with use chrono::prelude::*; use time::Duration; at the top.

Well that gives me an error:

| use time::Duration;
| ^^^^ Did you mean std::time?

So I change it, and the error goes away.

But then I get an error with my code, even though I’m pretty sure it’s being used as shown in the example

8 | start + Duration::seconds(1_000_000_000)
| ^^^^^^^^^^^^^^^^^ function or associated item not found in std::time::Duration

But something similar to that is what’s shown in the example in the docs at https://docs.rs/chrono/0.4.6/chrono/

But at the top of that page, under the Duration section:

Chrono does not yet natively support the standard Duration type, but it will be supported in the future. Meanwhile you can convert between two types with Duration::from_std and Duration::to_std methods.

Hi, could you paste the code (or some minimal example to https://play.rust-lang.org/ ?) What type is your start variable?

2 Likes

I don't think it'll work if I paste it here. It's run from a test as part of the exerciser project. (https://github.com/exercism/rust/tree/master/exercises/gigasecond) But here's the function I'm trying to complete:

(extern crate chrono;
use chrono::{DateTime, Utc};
use chrono::prelude::*;
use std::time::Duration;

// Returns a Utc DateTime one billion seconds after start.
pub fn after(start: DateTime<Utc>) -> DateTime<Utc> {
 start + std::time::Duration::seconds(1_000_000_000)
}

I'm willing to accept I may not be able to just add start, but the error I'm getting indicates to me that the first problem is my use of `Duration'.

Oh I tried preceding Duration::seconds with std::time since my first post. The results are the same though.

You could just use the types from chrono exclusively (including chrono’s Duration instead of std’s) and it will work, check this out: https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=b7a5a67237a93b2b6b7adb9ca73d1cf3

1 Like

Sweet! Problem solved, thanks.

It seems as if you are confusing the documentation of chronos Duration with the one from std. The one from std doesn’t have Duration::seconds, that “construictor” is only available in chronos version of a duration.

Therefore, always double check the documentation you are looking at.

Well… this is mentioned on the chrono crate doc

Chrono does not yet natively support the standard Duration type, but it will be supported in the future. Meanwhile you can convert between two types with Duration::from_std and Duration::to_std methods.

And further down in that same doc in an example

use chrono::prelude::*;
use time::Duration;

assert_eq!(dt1.signed_duration_since(dt2), Duration::seconds(-2 * 3600 + 2));
assert_eq!(dt2.signed_duration_since(dt1), Duration::seconds(2 * 3600 - 2));
assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) + Duration::seconds(1_000_000_000),

It seems as if you are confusing the documentation of chrono s Duration with the one from std

I rather feel that I’m not confusing the documentation, but it is confusing me.

1 Like

That example is not using std::time::Duration, it is using time::Duration from the time-crate:

Chrono currently uses the time::Duration type from the time crate to represent the magnitude of a time span.

1 Like

Ok, so do you understand why one might get confused? Since I’m looking at the chrono doc, shouldn’t it use Duration from chrono-crate?

And this text near the top of the doc:

Chrono does not yet natively support the standard Duration type, but it will be supported in the future.

That must be outdated, because this works:

use chrono::{DateTime, Utc, Duration};

There is no Duration in the chorono crate, it is just a re-export of the one from time.

I can’t see std::time::Duration there…

1 Like

Thank you @NobbZ for trying to explain this to me. I still don’t completely understand how I would have found the solution to my problem by looking at the chrono-crate doc, but I appreciate you trying to clear things up. As I learn a bit more about rust perhaps it will become clear. I’m not really wired for this kind of thing, probably.

Btw, if you look at the Duration doc you will see, that there is no function seconds, but only from_secs (and as_secs). Therefore your example should be

// Returns a Utc DateTime one billion seconds after start.
pub fn after(start: DateTime<Utc>) -> DateTime<Utc> {
    start + std::time::Duration::from_secs(1_000_000_000)
}

which will not compile, because you can’t add a DateTime and a Duration.

To quote Steve Klabnik from a Reddit post:

The time crate is all of the stuff that used to be in std::time, but we didn’t feel was good enough to stabilize. It’s basically abandoned; it’s the last crate in https://github.com/rust-lang-deprecated/ from that process and in the last two years, nobody has claimed it.

So in other words, it seems chrono uses the Duration from the time crate instead of the one from std because it has more features that never made it into the standard library.

There’s actually a currently pending pull request to merge the time crate into chrono entirely: https://github.com/chronotope/chrono/pull/286

Hopefully that clears things up a bit!

1 Like

What is the std::time module actually good for? It seems really minimal and i can’t imagine why anyone would use it over chrono. Is it just used internally by rustc/cargo and cannot be in a third-party crate for that reason?

If all you need is to track ‘how many seconds/nanoseconds are there between these two moments in time’, std::time will suffice, but yeah, if you want much more than that, it’s not very helpful.

I think the reason a lot of the functionality got moved out of std is because of Rust’s stability guarantees - yes, the core team could just merge time or chrono into the standard library and stabilize it, but then we’re stuck with that API for the foreseeable future. Having it out of std and versioned independently means it can develop at its own pace without having to worry as much about backwards compatibility. This is fairly common in the Rust ecosystem - sometimes the work becomes part of the standard library (e.g. futures), sometimes it stays as its own crate (e.g. regex).

i understand the rationale of removing time from std, but leaving that half-functional relic std::time in there, without any warning label, is bound to confuse people, especially those who come from other languages and assume that the standard library contains the preferred types/methods for something.

I thing you misunderstood something. There is no plan to remove time from std! Not now, not in the future. It may be depracated at some point, but even that is not planned. @17cupsofcoffee was talking about the time crate!

std::time is very useful btw. If you want to mesasure the time a functions takes to execute you can use that.
If you want to sleep for a certain time you can use that.
It is not however used if you really want to do things like weeks/days calculation, because that's way too compliated (just think about how may different calendars are out there!). Timezones etc. is way too compliated and should be implemented by a crate (in this case chrono).

1 Like

Yes, i got that, sorry for being unclear. What i meant by “removing” was:

i.e. some parts of that module that were previously there are not anymore. I just meant to say that a name as general as std::time is a bit “big” for something that provides the functionality of a stopwatch, which is probably why OP got confused here.