databento 0.47.0

Official Databento client library
Documentation
//! Custom deserializers
use std::collections::HashMap;

use serde::Deserialize;
use time::{format_description::well_known::iso8601::Iso8601, OffsetDateTime};

const LEGACY_DATE_TIME_FORMAT: &[time::format_description::BorrowedFormatItem<'static>] =
    time::macros::format_description!("[year]-[month]-[day] [hour]:[minute]:[second][optional [.[subsecond digits:6]]][optional [+[offset_hour]:[offset_minute]]]");

pub(crate) fn deserialize_date_time<'de, D: serde::Deserializer<'de>>(
    deserializer: D,
) -> Result<OffsetDateTime, D::Error> {
    let dt_str = String::deserialize(deserializer)?;
    time::PrimitiveDateTime::parse(&dt_str, &Iso8601::DEFAULT)
        .map(|dt| dt.assume_utc())
        .or_else(|_| time::OffsetDateTime::parse(&dt_str, LEGACY_DATE_TIME_FORMAT))
        .map_err(serde::de::Error::custom)
}

pub(crate) fn deserialize_opt_date_time_hash_map<'de, D: serde::Deserializer<'de>>(
    deserializer: D,
) -> Result<HashMap<String, Option<OffsetDateTime>>, D::Error> {
    let map: HashMap<String, Option<String>> = HashMap::deserialize(deserializer)?;
    map.into_iter()
        .map(|(k, v)| {
            Ok((
                k,
                if let Some(v) = v {
                    Some(
                        time::PrimitiveDateTime::parse(&v, &Iso8601::DEFAULT)
                            .map_err(serde::de::Error::custom)?
                            .assume_utc(),
                    )
                } else {
                    None
                },
            ))
        })
        .collect::<Result<HashMap<String, Option<OffsetDateTime>>, D::Error>>()
}

pub(crate) fn deserialize_opt_date_time<'de, D: serde::Deserializer<'de>>(
    deserializer: D,
) -> Result<Option<time::OffsetDateTime>, D::Error> {
    if let Some(dt_str) = Option::<String>::deserialize(deserializer)? {
        time::PrimitiveDateTime::parse(&dt_str, &Iso8601::DEFAULT)
            .map(|dt| dt.assume_utc())
            .or_else(|_| time::OffsetDateTime::parse(&dt_str, LEGACY_DATE_TIME_FORMAT))
            .map(Some)
            .map_err(serde::de::Error::custom)
    } else {
        Ok(None)
    }
}