Impl (de)serialization for chrono::NaiveDateTime

Adds implementations of `ToXml` and `FromXml` for
`chrono::NaiveDateTime`.
This commit is contained in:
Stuart Bruce 2025-01-30 09:59:52 +00:00
parent 35f674ff87
commit 1511976b94
2 changed files with 81 additions and 6 deletions

View File

@ -6,7 +6,7 @@ use std::str::FromStr;
use std::{any::type_name, marker::PhantomData};
#[cfg(feature = "chrono")]
use chrono::{DateTime, NaiveDate, Utc};
use chrono::{DateTime, NaiveDate, NaiveDateTime, Utc};
use crate::{Accumulate, Deserializer, Error, FromXml, Id, Kind, Serializer, ToXml};
@ -669,6 +669,68 @@ impl<'xml> FromXml<'xml> for DateTime<Utc> {
const KIND: Kind = Kind::Scalar;
}
#[cfg(feature = "chrono")]
impl ToXml for NaiveDateTime {
fn serialize<W: fmt::Write + ?Sized>(
&self,
field: Option<Id<'_>>,
serializer: &mut Serializer<W>,
) -> Result<(), Error> {
let prefix = match field {
Some(id) => {
let prefix = serializer.write_start(id.name, id.ns)?;
serializer.end_start()?;
Some((prefix, id.name))
}
None => None,
};
serializer.write_str(&self.format("%Y-%m-%dT%H:%M:%S%.f"))?;
if let Some((prefix, name)) = prefix {
serializer.write_close(prefix, name)?;
}
Ok(())
}
}
#[cfg(feature = "chrono")]
impl<'xml> FromXml<'xml> for NaiveDateTime {
fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
match field {
Some(field) => id == field,
None => false,
}
}
fn deserialize<'cx>(
into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut Deserializer<'cx, 'xml>,
) -> Result<(), Error> {
if into.is_some() {
return Err(Error::DuplicateValue(field));
}
let value = match deserializer.take_str()? {
Some(value) => value,
None => return Ok(()),
};
match NaiveDateTime::parse_from_str(value.as_ref(), "%Y-%m-%dT%H:%M:%S%.f") {
Ok(dt) => {
*into = Some(dt);
Ok(())
}
_ => Err(Error::Other("invalid date/time".into())),
}
}
type Accumulator = Option<Self>;
const KIND: Kind = Kind::Scalar;
}
#[cfg(feature = "chrono")]
impl ToXml for NaiveDate {
fn serialize<W: fmt::Write + ?Sized>(

View File

@ -1,23 +1,36 @@
#![cfg(feature = "chrono")]
use chrono::{DateTime, TimeZone, Utc};
use chrono::{DateTime, NaiveDateTime, TimeZone, Utc};
use similar_asserts::assert_eq;
use instant_xml::{from_str, to_string, FromXml, ToXml};
#[derive(Debug, Eq, PartialEq, FromXml, ToXml)]
struct Test {
dt: DateTime<Utc>,
struct Test<T> {
dt: T,
}
type TestUtcDateTime = Test<DateTime<Utc>>;
#[test]
fn datetime() {
let dt = Utc.with_ymd_and_hms(2022, 11, 21, 21, 17, 23).unwrap();
let test = Test { dt };
let xml = "<Test><dt>2022-11-21T21:17:23+00:00</dt></Test>";
assert_eq!(to_string(&test).unwrap(), xml);
assert_eq!(from_str::<Test>(xml).unwrap(), test);
assert_eq!(from_str::<TestUtcDateTime>(xml).unwrap(), test);
let zulu = xml.replace("+00:00", "Z");
assert_eq!(from_str::<Test>(&zulu).unwrap(), test);
assert_eq!(from_str::<TestUtcDateTime>(&zulu).unwrap(), test);
}
type TestNaiveDateTime = Test<NaiveDateTime>;
#[test]
fn naive_datetime() {
let dt = NaiveDateTime::parse_from_str("2022-11-21T21:17:23", "%Y-%m-%dT%H:%M:%S").unwrap();
let test = Test { dt };
let xml = "<Test><dt>2022-11-21T21:17:23</dt></Test>";
assert_eq!(to_string(&test).unwrap(), xml);
assert_eq!(from_str::<TestNaiveDateTime>(xml).unwrap(), test);
}