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

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.

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.

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.

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.