24

I have a SystemTime variable and I want to get the ISO 8601 format from that date.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Mathe Eliel
  • 658
  • 2
  • 6
  • 16

3 Answers3

19

The chrono package is the right tool for the job here. SystemTime may or may not be UTC, and chrono takes care of many irritating little details.

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

fn iso8601(st: &std::time::SystemTime) -> String {
    let dt: DateTime<Utc> = st.clone().into();
    format!("{}", dt.format("%+"))
    // formats like "2001-07-08T00:34:60.026490+09:30"
}

To customize the format differently, see the chrono::format::strftime docs.

NovaDenizen
  • 5,089
  • 14
  • 28
  • `std::time::SystemTime` is tagged with the `Clone` trait so passing a value instead of a reference should be preferred here. – Florian Dec 04 '22 at 08:20
  • Could you explain "SystemTime may or may not be UTC"? I don't see that mentioned in the docs and [this answer](https://stackoverflow.com/a/75714786/10238) to a similar question says "SystemTime itself is completely independent of timezones." – jmcnamara Jun 10 '23 at 00:09
13

Convert it to a chrono::DateTime then use to_rfc3339:

use chrono::{DateTime, Utc}; // 0.4.15
use std::time::SystemTime;

fn main() {
    let now = SystemTime::now();
    let now: DateTime<Utc> = now.into();
    let now = now.to_rfc3339();

    println!("{}", now);
}
2020-10-01T01:47:12.746202562+00:00

The docs explain the naming choice of the methods:

ISO 8601 allows some freedom over the syntax and RFC 3339 exercises that freedom to rigidly define a fixed format

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 1
    You can also use the following .format() string to represent something close to JavaScript's .toISOString() function: `Utc::now().format("%Y-%m-%dT%H:%M:%S%.3fZ")` to get something like this: `2022-12-29T00:00:00.000Z` Playground Link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7cc9bcdc4022347b8a38bd81c84df3e9 – Vince Pike Dec 29 '22 at 14:09
  • 1
    in the latest version of chrono 0.4.23, it says here https://docs.rs/chrono/0.4.23/chrono/struct.DateTime.html#method.to_rfc3339 that its _"Available on crate features alloc or std only."_, which required me to add `features = ["alloc"]` to Cargo.toml like this: `chrono = { version = "0.4.23", default_features = false, features = ["alloc"] }` – Luke Schoen Mar 07 '23 at 01:41
  • but i got the time without SystemTime because i couldn't get it to work, i just used chrono with `let now: DateTime = Utc::now();` and added features `features = ["alloc", "clock"]` – Luke Schoen Mar 07 '23 at 02:03
4

You can also use the time crate (doc). With the latest alpha release (0.3.0-ALPHA-0) you can use format_into() method while providing a &mut impl io::Write. Alternatively, you can simply use the format() method which is also compatible with older stable releases.

use time::{
    format_description::well_known::Rfc3339, // For 0.3.0-alpha-0
    // Format::Rfc3339, // For 0.2 stable versions
    OffsetDateTime
};
use std::time::SystemTime;

fn to_rfc3339<T>(dt: T) -> String where T: Into<OffsetDateTime> {
    dt.into().format(&Rfc3339)
}

fn main() {
   let now = SystemTime::now();
   println!("{}", to_rfc3339(now));
}

Playground

You will have to add the formatting feature to your Cargo.toml to use format_into() (i.e. formatting on v0.3+ require the feature to be enabled).

Note that you can also specify your own strftime-like format string to format/format_into.

YenForYang
  • 2,998
  • 25
  • 22