#[macro_export]
macro_rules! custom_format_xtime {
    ($name:ident, $fmt:expr) => {
        pub struct $name;

        impl serde_with::SerializeAs<$crate::xtime::datatime::XTime> for $name {
            fn serialize_as<S>(source: &$crate::xtime::datatime::XTime, serializer: S) -> Result<S::Ok, S::Error>
            where
                S: serde::Serializer,
            {
                let s = source.format_timestr($fmt);
                serializer.serialize_str(&s)
            }
        }

        impl<'de> serde_with::DeserializeAs<'de, $crate::xtime::datatime::XTime> for $name {
            fn deserialize_as<D>(deserializer: D) -> Result<$crate::xtime::datatime::XTime, D::Error>
            where
                D: serde::Deserializer<'de>,
            {
                let s = <String as serde::Deserialize>::deserialize(deserializer)?;
                $crate::xtime::datatime::XTime::from_timestr(&s, $fmt).map_err(serde::de::Error::custom)
            }
        }
    };
}

custom_format_xtime!(XTimeYMDHMZ1, crate::xtime::datatime::XTimeStrFormat::YMDHMZ1);
custom_format_xtime!(XTimeYMDHMZ2, crate::xtime::datatime::XTimeStrFormat::YMDHMZ2);
custom_format_xtime!(XTimeYMDHMZ3, crate::xtime::datatime::XTimeStrFormat::YMDHMZ3);

#[cfg(test)]
mod tests {
    use crate::xtime::datatime::XTime;
    use crate::xtime::datatime_serde::{XTimeYMDHMZ1, XTimeYMDHMZ2};
    use serde::{Deserialize, Serialize};
    use serde_with::serde_as;
    #[test]
    fn test_case_xtime_ymdhmz1() {
        #[serde_as]
        #[derive(Deserialize, Serialize)]
        struct MyTime {
            #[serde_as(as = "XTimeYMDHMZ1")]
            time: XTime,
        }

        let json_str = r#"{"time":"20231110144351"}"#;
        let my_time: MyTime = serde_json::from_str(json_str).unwrap();
        assert_eq!(my_time.time.as_timestamp_s(), 1699598631);
        assert_eq!(serde_json::to_string(&my_time).unwrap(), json_str);
    }

    #[test]
    fn test_case_xtime_ymdhmz2() {
        #[serde_as]
        #[derive(Deserialize, Serialize)]
        struct MyTime {
            #[serde_as(as = "XTimeYMDHMZ2")]
            time: XTime,
        }

        let json_str = r#"{"time":"2023-11-10 14:43:51"}"#;
        let my_time: MyTime = serde_json::from_str(json_str).unwrap();
        assert_eq!(my_time.time.as_timestamp_s(), 1699598631);
        assert_eq!(serde_json::to_string(&my_time).unwrap(), json_str);
    }
}
