Convert std::time::SystemTime to chrono::datetime::DateTime

I'm building a tiny ls -al clone in Rust to get to know the language better. I managed to show the permissions and file names, now I want to display the timestamp for each directory entry. std::fs::Metadata has a modified function that returns a std::time::SystemTime (result). I now want to convert it into something that I can strftime :smile:

I asked that question on Twitter and got the recommendation to use chrono. But I don't understand how to convert my std::time::SystemTime to a chrono::datetime::DateTime.

Any help is appreciated <3

1 Like

As the documentations says:

Although a SystemTime cannot be directly inspected, the UNIX_EPOCH constant is provided in this module as an anchor in time to learn information about a SystemTime. By calculating the duration from this fixed point in time, a SystemTime can be converted to a human-readable time

so you can do:

    use std::time::{Duration, SystemTime, UNIX_EPOCH};

    fn main() {
        let now = SystemTime::now();
        let seconds = now.duration_since(UNIX_EPOCH).unwrap().as_secs();
        println!("{}", seconds);
    }   

But the fact that SystemTime and Duration do not expose its fields just sucks. It causes only problems.

4 Likes

If chrono does not yet feature From implementations for the stdlib types then perhaps this is a nice opportunity for a PR?

For now, use the following: (Same for DateTime<Local>)

fn system_time_to_date_time(t: SystemTime) -> DateTime<UTC> {
    let (sec, nsec) = match t.duration_since(UNIX_EPOCH) {
        Ok(dur) => (dur.as_secs() as i64, dur.subsec_nanos()),
        Err(e) => { // unlikely but should be handled
            let dur = e.duration();
            let (sec, nsec) = (dur.as_secs() as i64, dur.subsec_nanos());
            if nsec == 0 {
                (-sec, 0)
            } else {
                (-sec - 1, 1_000_000_000 - nsec)
            }
        },
    };
    UTC.timestamp(sec, nsec)
}

Chrono 0.3 would switch to std::time::SystemTime and std::time::Duration for the primary timekeeping, so hopefully this workaround will be gone.

6 Likes

Thanks to all of you :slight_smile: It works now! :slight_smile:

When I feel more comfortable with Rust, I'll try to PR to chrono :wink:

Use chrono DateTime conversion like this

extern crate chrono;
use chrono::{DateTime, Local, Utc};
use std::time::SystemTime;

fn main() {
    let st_now = SystemTime::now();
    dbg!(&st_now);
    let dt_now_utc: DateTime<Utc> = st_now.clone().into();
    dbg!(&dt_now_utc);
    let dt_now_local: DateTime<Local> = st_now.clone().into();
    dbg!(&dt_now_local);
}

Other chrono types do not satisfy the needed trait type, e.g.

the trait bound `DateTime<FixedOffset>: From<SystemTime>` is not satisfied
the following other types implement trait `From<T>`:
  <DateTime<FixedOffset> as From<DateTime<Local>>>
  <DateTime<FixedOffset> as From<DateTime<Utc>>>
  <DateTime<Local> as From<DateTime<FixedOffset>>>
  <DateTime<Local> as From<DateTime<Utc>>>
  <DateTime<Local> as From<SystemTime>>
  <DateTime<Utc> as From<DateTime<FixedOffset>>>
  <DateTime<Utc> as From<DateTime<Local>>>
  <DateTime<Utc> as From<SystemTime>>
required because of the requirements on the impl of `Into<DateTime<FixedOffset>>` for `SystemTime`

So this does not work:

let dt: DateTime<FixedOffset> = systemtime.clone().into();

Derived from SO post datetime format - How do I convert a SystemTime to ISO 8601 in Rust? - Stack Overflow


FYI this old post is a top result for some search queries, that's why I updated.

1 Like

I'd argue that that is a good reason for a chrono API extension that makes this conversation from SystemTime to chrono::DateTime painless. Assuming that such an API doesn't exist yet of course.
Perhaps something like
impl From<std::time::SystemTime> for chrono::DateTime.

It might be worth requesting or contributing that feature on chrono's GitHub.