You can see in the parsing function documentation that the function is greedy while obeying the intrinsic parsing width, which means that when "matching" your format, it will try to consume the most characters it can left to right, respecting a maximum value. As a unix timestamp (%s) doesn't have a maximum number of characters, you can see in the source that the maximum number of characters allowed is usize::MAX (which is at least 65535). In this example, the whole string (1595879159050208) is consumed as the timestamp Tue May 12 02:50:08 50573367 UTC
(veeeeeeery far in the future), and the remaining digits (%6f) cannot be found.
We can test this by adding a space to your format: "%s %6f"
. In this case, a new error shows up (ParseError(NotEnough)
) which is better explained by using DateTime::parse_from_str docs:
Note that this method requires a timezone in the string. See NaiveDateTime::parse_from_str for a version that does not require a timezone in the to-be-parsed str.
So using NaiveDateTime:
use chrono::prelude::*;
fn main() {
let utc: DateTime<Utc> = Utc::now();
let format = "%s %6f";
let string = utc.format(format).to_string();
println!("{}", string); // 1595902520 811515
let parsed = NaiveDateTime::parse_from_str(&string, format);
println!("{:?}", parsed); // Ok(2020-07-28T02:15:20.811515)
}
Unfortunately, you want to parse the original string, with no spaces. For that I think you can:
- Parse the string to an i64 as µs using the standard library and calculate the number of seconds / nanoseconds from there, using NaiveDateTime::from_timestamp
- Slice the string and parse seconds / microseconds separately
- If you don't care about sub-second precision, pass a slice of the original string to
parse_from_str
, formatting with just %s
Using the second option:
use chrono::prelude::*;
fn main() {
let utc: DateTime<Utc> = Utc::now();
let format = "%s%6f";
let string = utc.format(format).to_string();
println!("{}", string); // 1595904294646258
let secs = string[..string.len() - 6].parse();
let microsecs = string[string.len() - 6..].parse::<u32>();
let parsed = match (secs, microsecs) {
(Ok(s), Ok(us)) => NaiveDateTime::from_timestamp_opt(s, us * 1000),
_ => None,
};
println!("{:?}", parsed); // Some(2020-07-28T02:44:54.646258)
}