Ensure datetimes with milliseconds are parsed correctly

Closes #250
This commit is contained in:
Tobie Morgan Hitchcock 2022-09-22 02:25:45 +01:00
parent 4d22b052a7
commit 4ca579160c
2 changed files with 24 additions and 14 deletions

View file

@ -44,14 +44,6 @@ pub fn val_char(chr: char) -> bool {
is_alphanumeric(chr as u8) || chr == '_' 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::<u32>() {
Ok(v) => Ok((i, v)),
_ => Err(Error(ParserError(i))),
}
}
pub fn take_u64(i: &str) -> IResult<&str, u64> { pub fn take_u64(i: &str) -> IResult<&str, u64> {
let (i, v) = take_while(is_digit)(i)?; let (i, v) = take_while(is_digit)(i)?;
match v.parse::<u64>() { match v.parse::<u64>() {
@ -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::<u32>() {
Ok(n) => Ok((i, (n, v.len()))),
_ => Err(Error(ParserError(i))),
}
}
pub fn take_digits(i: &str, n: usize) -> IResult<&str, u32> { pub fn take_digits(i: &str, n: usize) -> IResult<&str, u32> {
let (i, v) = take_while_m_n(n, n, is_digit)(i)?; let (i, v) = take_while_m_n(n, n, is_digit)(i)?;
match v.parse::<u32>() { match v.parse::<u32>() {

View file

@ -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::error::IResult;
use crate::sql::serde::is_internal_serialization; use crate::sql::serde::is_internal_serialization;
use chrono::{DateTime, FixedOffset, TimeZone, Utc}; use chrono::{DateTime, FixedOffset, TimeZone, Utc};
@ -180,7 +180,17 @@ fn second(i: &str) -> IResult<&str, u32> {
fn nanosecond(i: &str) -> IResult<&str, u32> { fn nanosecond(i: &str) -> IResult<&str, u32> {
let (i, _) = char('.')(i)?; 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)) Ok((i, v))
} }
@ -245,16 +255,16 @@ mod tests {
let res = datetime_raw(sql); let res = datetime_raw(sql);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap().1; 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] #[test]
fn date_time_timezone_utc() { 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); let res = datetime_raw(sql);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap().1; 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] #[test]
@ -263,6 +273,6 @@ mod tests {
let res = datetime_raw(sql); let res = datetime_raw(sql);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap().1; 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));
} }
} }