use chrono::{DateTime as ChronoDateTime, FixedOffset, SecondsFormat};
use serde::de;
use serde::{Deserializer, Serializer};
use crate::tokens::TOKEN_DATETIME;
pub type DateTime = ChronoDateTime<FixedOffset>;
pub fn to_jsonx_string(dt: &DateTime) -> String {
dt.to_rfc3339_opts(SecondsFormat::AutoSi, true)
}
pub fn parse(input: &str) -> Result<DateTime, chrono::ParseError> {
DateTime::parse_from_rfc3339(input)
}
pub fn serialize<S: Serializer>(dt: &DateTime, serializer: S) -> Result<S::Ok, S::Error> {
crate::constructor::serialize_constructor(serializer, TOKEN_DATETIME, &to_jsonx_string(dt))
}
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<DateTime, D::Error> {
let arg = crate::constructor::deserialize_constructor(deserializer, TOKEN_DATETIME)?;
parse(&arg).map_err(de::Error::custom)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trip() {
for s in [
"2017-12-25T15:00:00Z",
"2006-01-02T15:04:05-07:00",
"1999-01-01T00:00:00.500Z",
] {
let dt = parse(s).unwrap();
assert_eq!(to_jsonx_string(&dt), s);
}
}
#[test]
fn zero_offset_renders_z() {
let dt = parse("2017-12-25T15:00:00+00:00").unwrap();
assert_eq!(to_jsonx_string(&dt), "2017-12-25T15:00:00Z");
}
#[test]
fn rejects_bad() {
assert!(parse("not a date").is_err());
assert!(parse("2017-13-01T00:00:00Z").is_err());
assert!(parse("2017-12-25T15:00:00").is_err());
assert!(parse("2017-12-25T15:00:00Z extra").is_err());
}
}