From 4ca579160c4f5fb4f59ce51af1b3e96c88298700 Mon Sep 17 00:00:00 2001 From: Tobie Morgan Hitchcock Date: Thu, 22 Sep 2022 02:25:45 +0100 Subject: [PATCH] Ensure datetimes with milliseconds are parsed correctly Closes #250 --- lib/src/sql/common.rs | 16 ++++++++-------- lib/src/sql/datetime.rs | 22 ++++++++++++++++------ 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/lib/src/sql/common.rs b/lib/src/sql/common.rs index 933c275c..26ca892a 100644 --- a/lib/src/sql/common.rs +++ b/lib/src/sql/common.rs @@ -44,14 +44,6 @@ pub fn val_char(chr: char) -> bool { is_alphanumeric(chr as u8) || chr == '_' } -pub fn take_u32(i: &str) -> IResult<&str, u32> { - let (i, v) = take_while(is_digit)(i)?; - match v.parse::() { - Ok(v) => Ok((i, v)), - _ => Err(Error(ParserError(i))), - } -} - pub fn take_u64(i: &str) -> IResult<&str, u64> { let (i, v) = take_while(is_digit)(i)?; match v.parse::() { @@ -68,6 +60,14 @@ pub fn take_usize(i: &str) -> IResult<&str, usize> { } } +pub fn take_u32_len(i: &str) -> IResult<&str, (u32, usize)> { + let (i, v) = take_while(is_digit)(i)?; + match v.parse::() { + Ok(n) => Ok((i, (n, v.len()))), + _ => Err(Error(ParserError(i))), + } +} + pub fn take_digits(i: &str, n: usize) -> IResult<&str, u32> { let (i, v) = take_while_m_n(n, n, is_digit)(i)?; match v.parse::() { diff --git a/lib/src/sql/datetime.rs b/lib/src/sql/datetime.rs index 4f02ac21..86ab65c2 100644 --- a/lib/src/sql/datetime.rs +++ b/lib/src/sql/datetime.rs @@ -1,4 +1,4 @@ -use crate::sql::common::{take_digits, take_digits_range, take_u32}; +use crate::sql::common::{take_digits, take_digits_range, take_u32_len}; use crate::sql::error::IResult; use crate::sql::serde::is_internal_serialization; use chrono::{DateTime, FixedOffset, TimeZone, Utc}; @@ -180,7 +180,17 @@ fn second(i: &str) -> IResult<&str, u32> { fn nanosecond(i: &str) -> IResult<&str, u32> { let (i, _) = char('.')(i)?; - let (i, v) = take_u32(i)?; + let (i, (v, l)) = take_u32_len(i)?; + let v = match l { + l if l <= 2 => v * 10000000, + l if l <= 3 => v * 1000000, + l if l <= 4 => v * 100000, + l if l <= 5 => v * 10000, + l if l <= 6 => v * 1000, + l if l <= 7 => v * 100, + l if l <= 8 => v * 10, + _ => v, + }; Ok((i, v)) } @@ -245,16 +255,16 @@ mod tests { let res = datetime_raw(sql); assert!(res.is_ok()); let out = res.unwrap().1; - assert_eq!("\"2012-04-23T18:25:43.000005631Z\"", format!("{}", out)); + assert_eq!("\"2012-04-23T18:25:43.563100Z\"", format!("{}", out)); } #[test] fn date_time_timezone_utc() { - let sql = "2012-04-23T18:25:43.511Z"; + let sql = "2012-04-23T18:25:43.0000511Z"; let res = datetime_raw(sql); assert!(res.is_ok()); let out = res.unwrap().1; - assert_eq!("\"2012-04-23T18:25:43.000000511Z\"", format!("{}", out)); + assert_eq!("\"2012-04-23T18:25:43.000051100Z\"", format!("{}", out)); } #[test] @@ -263,6 +273,6 @@ mod tests { let res = datetime_raw(sql); assert!(res.is_ok()); let out = res.unwrap().1; - assert_eq!("\"2012-04-24T02:25:43.000000511Z\"", format!("{}", out)); + assert_eq!("\"2012-04-24T02:25:43.511Z\"", format!("{}", out)); } }