diff --git a/crates/tor-netdoc/src/types/misc.rs b/crates/tor-netdoc/src/types/misc.rs index 5f43a10de..764cd2e7d 100644 --- a/crates/tor-netdoc/src/types/misc.rs +++ b/crates/tor-netdoc/src/types/misc.rs @@ -206,6 +206,7 @@ mod timeimpl { /// space between the date and time. /// /// (Example: "2020-10-09 17:38:12") + #[derive(derive_more::Into, derive_more::From)] pub(crate) struct Iso8601TimeSp(SystemTime); /// Formatting object for parsing the space-separated Iso8601 format. @@ -224,9 +225,26 @@ mod timeimpl { } } - impl From for SystemTime { - fn from(t: Iso8601TimeSp) -> SystemTime { - t.0 + /// A wall-clock time, encoded in ISO8601 format without an intervening + /// space. + /// + /// (Example: "2020-10-09T17:38:12") + #[derive(derive_more::Into, derive_more::From)] + pub(crate) struct Iso8601TimeNoSp(SystemTime); + + /// Formatting object for parsing the space-separated Iso8601 format. + const ISO_8601NOSP_FMT: &[FormatItem] = + format_description!("[year]-[month]-[day]T[hour]:[minute]:[second]"); + + impl std::str::FromStr for Iso8601TimeNoSp { + type Err = Error; + fn from_str(s: &str) -> Result { + let d = PrimitiveDateTime::parse(s, &ISO_8601NOSP_FMT).map_err(|e| { + EK::BadArgument + .at_pos(Pos::at(s)) + .with_msg(format!("invalid time: {}", e)) + })?; + Ok(Iso8601TimeNoSp(d.assume_utc().into())) } } } @@ -671,6 +689,15 @@ mod test { assert!("2020-09-29".parse::().is_err()); assert!("too bad, waluigi time".parse::().is_err()); + let t = "2020-09-29T13:36:33".parse::()?; + let t: SystemTime = t.into(); + assert_eq!(t, parse_rfc3339("2020-09-29T13:36:33Z").unwrap()); + + assert!("2020-09-29 13:36:33".parse::().is_err()); + assert!("2020-09-29Q13:99:33".parse::().is_err()); + assert!("2020-09-29".parse::().is_err()); + assert!("too bad, waluigi time".parse::().is_err()); + Ok(()) }