diff --git a/src/naive/time/mod.rs b/src/naive/time/mod.rs index b0f730feb6..797b7bb42f 100644 --- a/src/naive/time/mod.rs +++ b/src/naive/time/mod.rs @@ -1324,26 +1324,38 @@ impl fmt::Display for NaiveTime { /// let t = NaiveTime::from_hms_nano_opt(23, 59, 59, 1_234_567_890).unwrap(); // leap second /// assert_eq!("23:59:60.23456789".parse::(), Ok(t)); /// +/// // Seconds are optional +/// let t = NaiveTime::from_hms_opt(23, 56, 0).unwrap(); +/// assert_eq!("23:56".parse::(), Ok(t)); +/// /// assert!("foo".parse::().is_err()); /// ``` impl str::FromStr for NaiveTime { type Err = ParseError; fn from_str(s: &str) -> ParseResult { - const ITEMS: &[Item<'static>] = &[ + const HOUR_AND_MINUTE: &[Item<'static>] = &[ Item::Numeric(Numeric::Hour, Pad::Zero), Item::Space(""), Item::Literal(":"), Item::Numeric(Numeric::Minute, Pad::Zero), + ]; + const SECOND_AND_NANOS: &[Item<'static>] = &[ Item::Space(""), Item::Literal(":"), Item::Numeric(Numeric::Second, Pad::Zero), Item::Fixed(Fixed::Nanosecond), Item::Space(""), ]; + const TRAILING_WHITESPACE: &[Item<'static>] = &[ + Item::Space(""), + ]; let mut parsed = Parsed::new(); - parse(&mut parsed, s, ITEMS.iter())?; + let s = parse_and_remainder(&mut parsed, s, HOUR_AND_MINUTE.iter())?; + // Seconds are optional, don't fail if parsing them doesn't succeed. + let s = parse_and_remainder(&mut parsed, s, SECOND_AND_NANOS.iter()).unwrap_or(s); + parse(&mut parsed, s, TRAILING_WHITESPACE.iter())?; parsed.to_naive_time() } } diff --git a/src/naive/time/tests.rs b/src/naive/time/tests.rs index 72491fbd2c..ddb827b745 100644 --- a/src/naive/time/tests.rs +++ b/src/naive/time/tests.rs @@ -226,7 +226,7 @@ fn test_time_fmt() { } #[test] -fn test_date_from_str() { +fn test_time_from_str() { // valid cases let valid = [ "0:0:0", @@ -234,6 +234,7 @@ fn test_date_from_str() { "0:0:0.0000003", " 4 : 3 : 2.1 ", " 09:08:07 ", + " 09:08 ", " 9:8:07 ", "23:59:60.373929310237", ]; @@ -265,7 +266,7 @@ fn test_date_from_str() { assert!("".parse::().is_err()); assert!("x".parse::().is_err()); assert!("15".parse::().is_err()); - assert!("15:8".parse::().is_err()); + assert!("15:".parse::().is_err()); assert!("15:8:x".parse::().is_err()); assert!("15:8:9x".parse::().is_err()); assert!("23:59:61".parse::().is_err());