crate::ix!();
pub mod naive_date_format {
use super::*;
const FORMAT: &'static str = "%m/%d/%Y";
pub fn serialize<S>(date: &NaiveDate, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&format!("{}", date.format(FORMAT)))
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<NaiveDate, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
let formats = [
"%-m/%-d/%y",
"%m/%d/%y",
"%m/%d/%Y",
];
for format in &formats {
if let Ok(date) = NaiveDate::parse_from_str(&s, format) {
return Ok(date);
}
}
Err(serde::de::Error::custom("Failed to parse date"))
}
}
#[cfg(test)]
mod serde_naive_date_format_tests {
use super::*;
use chrono::NaiveDate;
use serde_test::{assert_de_tokens_error, Token};
use serde::de::value::Error;
use serde::de::IntoDeserializer;
use serde::de::value::StringDeserializer;
#[test]
fn test_deserialize_date() {
let date_strings = vec![
"01/02/2023",
"01/02/23",
"1/2/23",
"invalid_date"
];
let parsed_dates: Vec<Result<NaiveDate, _>> = date_strings.iter()
.map(|date_str| {
naive_date_format::deserialize::<StringDeserializer<Error>>(
date_str.to_string().into_deserializer()
)
})
.collect();
let first_date = match parsed_dates.first() {
Some(Ok(date)) => date.clone(),
_ => return assert!(false, "No valid dates found for comparison"),
};
for parsed_date in parsed_dates.iter() {
match parsed_date {
Ok(date) => assert_eq!(*date, first_date, "All dates should deserialize to the same NaiveDate"),
_ => continue, }
}
for date_str in date_strings {
let result: Result<NaiveDate, _> = naive_date_format::deserialize::<StringDeserializer<Error>>(
date_str.to_string().into_deserializer()
);
match date_str {
"01/02/2023" | "01/02/23" | "1/2/23" => {
assert!(result.is_ok(), "Date {:?} should deserialize successfully", date_str);
}
_ => {
assert_de_tokens_error::<NaiveDate>(
&[Token::String(date_str)],
"input contains invalid characters",
);
}
}
}
}
}