diff --git a/src/naive/datetime/serde.rs b/src/naive/datetime/serde.rs index 25af3e4186..f23805e0f3 100644 --- a/src/naive/datetime/serde.rs +++ b/src/naive/datetime/serde.rs @@ -3,6 +3,7 @@ use serde::{de, ser}; use super::NaiveDateTime; use crate::serde::ne_timestamp; +use crate::{infallible, serde_module}; /// Serialize a `NaiveDateTime` as an RFC 3339 string /// @@ -53,1034 +54,177 @@ impl<'de> de::Deserialize<'de> for NaiveDateTime { } } -/// Used to serialize/deserialize from nanosecond-precision timestamps -/// -/// # Example: -/// -/// ```rust -/// # use chrono::{NaiveDate, NaiveDateTime}; -/// # use serde_derive::{Deserialize, Serialize}; -/// use chrono::naive::serde::ts_nanoseconds; -/// #[derive(Deserialize, Serialize)] -/// struct S { -/// #[serde(with = "ts_nanoseconds")] -/// time: NaiveDateTime -/// } -/// -/// let time = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap(); -/// let my_s = S { -/// time: time.clone(), -/// }; -/// -/// let as_string = serde_json::to_string(&my_s)?; -/// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; -/// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) -/// ``` -pub mod ts_nanoseconds { - use core::fmt; - use serde::{de, ser}; - - use super::ne_timestamp; - use crate::NaiveDateTime; - - /// Serialize a datetime into an integer number of nanoseconds since the epoch - /// - /// Intended for use with `serde`s `serialize_with` attribute. - /// - /// # Errors - /// - /// An `i64` with nanosecond precision can span a range of ~584 years. This function returns an - /// error on an out of range `DateTime`. - /// - /// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:44.0 and - /// 2262-04-11T23:47:16.854775804. - /// - /// # Example: - /// - /// ```rust - /// # use chrono::{NaiveDate, NaiveDateTime}; - /// # use serde_derive::Serialize; - /// use chrono::naive::serde::ts_nanoseconds::serialize as to_nano_ts; - /// #[derive(Serialize)] - /// struct S { - /// #[serde(serialize_with = "to_nano_ts")] - /// time: NaiveDateTime - /// } - /// - /// let my_s = S { - /// time: NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap(), - /// }; - /// let as_string = serde_json::to_string(&my_s)?; - /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); - /// # Ok::<(), serde_json::Error>(()) - /// ``` - pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result - where - S: ser::Serializer, - { - serializer.serialize_i64(dt.timestamp_nanos_opt().ok_or(ser::Error::custom( - "value out of range for a timestamp with nanosecond precision", - ))?) - } - - /// Deserialize a `NaiveDateTime` from a nanoseconds timestamp - /// - /// Intended for use with `serde`s `deserialize_with` attribute. - /// - /// # Example: - /// - /// ```rust - /// # use chrono::NaiveDateTime; - /// # use serde_derive::Deserialize; - /// use chrono::naive::serde::ts_nanoseconds::deserialize as from_nano_ts; - /// #[derive(Debug, PartialEq, Deserialize)] - /// struct S { - /// #[serde(deserialize_with = "from_nano_ts")] - /// time: NaiveDateTime - /// } - /// - /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; - /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918355733).unwrap() }); - /// - /// let my_s: S = serde_json::from_str(r#"{ "time": -1 }"#)?; - /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(-1, 999_999_999).unwrap() }); - /// # Ok::<(), serde_json::Error>(()) - /// ``` - pub fn deserialize<'de, D>(d: D) -> Result - where - D: de::Deserializer<'de>, - { - d.deserialize_i64(NanoSecondsTimestampVisitor) - } +struct NanoSecondsTimestampVisitor; - pub(super) struct NanoSecondsTimestampVisitor; +serde_module! { + type: NaiveDateTime, + module: ts_nanoseconds, + module_opt: ts_nanoseconds_option, + doc: r##" +# Errors - impl<'de> de::Visitor<'de> for NanoSecondsTimestampVisitor { - type Value = NaiveDateTime; +An `i64` with nanosecond precision can span a range of ~584 years. Serializing a `NaiveDateTime` +beyond that range returns an error. - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a unix timestamp") - } +The dates that can be represented as nanoseconds are between 1677-09-21T00:12:44.0 and +2262-04-11T23:47:16.854775804. - fn visit_i64(self, value: i64) -> Result - where - E: de::Error, - { - NaiveDateTime::from_timestamp_opt( - value.div_euclid(1_000_000_000), - (value.rem_euclid(1_000_000_000)) as u32, - ) - .ok_or_else(|| E::custom(ne_timestamp(value))) - } +# Example - fn visit_u64(self, value: u64) -> Result - where - E: de::Error, - { - NaiveDateTime::from_timestamp_opt( - (value / 1_000_000_000) as i64, - (value % 1_000_000_000) as u32, - ) - .ok_or_else(|| E::custom(ne_timestamp(value))) - } - } +```rust +# use chrono::{NaiveDate, NaiveDateTime}; +# use serde_derive::{Deserialize, Serialize}; +use chrono::naive::serde::ts_nanoseconds; +#[derive(Deserialize, Serialize)] +struct S { + #[serde(with = "ts_nanoseconds")] + time: NaiveDateTime } -/// Ser/de to/from optional timestamps in nanoseconds -/// -/// Intended for use with `serde`'s `with` attribute. -/// -/// # Example: -/// -/// ```rust -/// # use chrono::naive::{NaiveDate, NaiveDateTime}; -/// # use serde_derive::{Deserialize, Serialize}; -/// use chrono::naive::serde::ts_nanoseconds_option; -/// #[derive(Deserialize, Serialize)] -/// struct S { -/// #[serde(with = "ts_nanoseconds_option")] -/// time: Option -/// } -/// -/// let time = Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap()); -/// let my_s = S { -/// time: time.clone(), -/// }; -/// -/// let as_string = serde_json::to_string(&my_s)?; -/// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; -/// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) -/// ``` -pub mod ts_nanoseconds_option { - use core::fmt; - use serde::{de, ser}; - - use super::ts_nanoseconds::NanoSecondsTimestampVisitor; - use crate::NaiveDateTime; - - /// Serialize a datetime into an integer number of nanoseconds since the epoch or none - /// - /// Intended for use with `serde`s `serialize_with` attribute. - /// - /// # Errors - /// - /// An `i64` with nanosecond precision can span a range of ~584 years. This function returns an - /// error on an out of range `DateTime`. - /// - /// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:44.0 and - /// 2262-04-11T23:47:16.854775804. - /// - /// # Example: - /// - /// ```rust - /// # use chrono::naive::{NaiveDate, NaiveDateTime}; - /// # use serde_derive::Serialize; - /// use chrono::naive::serde::ts_nanoseconds_option::serialize as to_nano_tsopt; - /// #[derive(Serialize)] - /// struct S { - /// #[serde(serialize_with = "to_nano_tsopt")] - /// time: Option - /// } - /// - /// let my_s = S { - /// time: Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap()), - /// }; - /// let as_string = serde_json::to_string(&my_s)?; - /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); - /// # Ok::<(), serde_json::Error>(()) - /// ``` - pub fn serialize(opt: &Option, serializer: S) -> Result - where - S: ser::Serializer, - { - match *opt { - Some(ref dt) => serializer.serialize_some(&dt.timestamp_nanos_opt().ok_or( - ser::Error::custom("value out of range for a timestamp with nanosecond precision"), - )?), - None => serializer.serialize_none(), - } - } - - /// Deserialize a `NaiveDateTime` from a nanosecond timestamp or none - /// - /// Intended for use with `serde`s `deserialize_with` attribute. - /// - /// # Example: - /// - /// ```rust - /// # use chrono::naive::NaiveDateTime; - /// # use serde_derive::Deserialize; - /// use chrono::naive::serde::ts_nanoseconds_option::deserialize as from_nano_tsopt; - /// #[derive(Debug, PartialEq, Deserialize)] - /// struct S { - /// #[serde(deserialize_with = "from_nano_tsopt")] - /// time: Option - /// } - /// - /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; - /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918355733) }); - /// - /// let my_s: S = serde_json::from_str(r#"{ "time": -1 }"#)?; - /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(-1, 999_999_999) }); - /// # Ok::<(), serde_json::Error>(()) - /// ``` - pub fn deserialize<'de, D>(d: D) -> Result, D::Error> - where - D: de::Deserializer<'de>, - { - d.deserialize_option(OptionNanoSecondsTimestampVisitor) - } - - struct OptionNanoSecondsTimestampVisitor; - - impl<'de> de::Visitor<'de> for OptionNanoSecondsTimestampVisitor { - type Value = Option; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a unix timestamp in nanoseconds or none") - } - - /// Deserialize a timestamp in nanoseconds since the epoch - fn visit_some(self, d: D) -> Result - where - D: de::Deserializer<'de>, - { - d.deserialize_i64(NanoSecondsTimestampVisitor).map(Some) - } - - /// Deserialize a timestamp in nanoseconds since the epoch - fn visit_none(self) -> Result - where - E: de::Error, - { - Ok(None) - } - - /// Deserialize a timestamp in nanoseconds since the epoch - fn visit_unit(self) -> Result - where - E: de::Error, - { - Ok(None) - } - } +let time = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap(); +let my_s = S { + time: time.clone(), +}; + +let as_string = serde_json::to_string(&my_s)?; +assert_eq!(as_string, r#"{"time":1526522699918355733}"#); +let my_s: S = serde_json::from_str(&as_string)?; +assert_eq!(my_s.time, time); +# Ok::<(), serde_json::Error>(()) +```"##, + serialize_i64: |dt| NaiveDateTime::timestamp_nanos_opt(dt) + .ok_or("value out of range for a timestamp with nanosecond precision"), + deserialize_i64: NanoSecondsTimestampVisitor, + expecting: "a unix timestamp in nanoseconds", + visit_i64(i64): |value: i64| NaiveDateTime::from_timestamp_opt( + value.div_euclid(1_000_000_000), + (value.rem_euclid(1_000_000_000)) as u32, + ).ok_or_else(|| E::custom(ne_timestamp(value))), + visit_u64(u64): |value: u64| NaiveDateTime::from_timestamp_opt( + (value / 1_000_000_000) as i64, + (value % 1_000_000_000) as u32, + ).ok_or_else(|| E::custom(ne_timestamp(value))), } -/// Used to serialize/deserialize from microsecond-precision timestamps -/// -/// # Example: -/// -/// ```rust -/// # use chrono::{NaiveDate, NaiveDateTime}; -/// # use serde_derive::{Deserialize, Serialize}; -/// use chrono::naive::serde::ts_microseconds; -/// #[derive(Deserialize, Serialize)] -/// struct S { -/// #[serde(with = "ts_microseconds")] -/// time: NaiveDateTime -/// } -/// -/// let time = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap(); -/// let my_s = S { -/// time: time.clone(), -/// }; -/// -/// let as_string = serde_json::to_string(&my_s)?; -/// assert_eq!(as_string, r#"{"time":1526522699918355}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; -/// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) -/// ``` -pub mod ts_microseconds { - use core::fmt; - use serde::{de, ser}; - - use super::ne_timestamp; - use crate::NaiveDateTime; - - /// Serialize a datetime into an integer number of microseconds since the epoch - /// - /// Intended for use with `serde`s `serialize_with` attribute. - /// - /// # Example: - /// - /// ```rust - /// # use chrono::{NaiveDate, NaiveDateTime}; - /// # use serde_derive::Serialize; - /// use chrono::naive::serde::ts_microseconds::serialize as to_micro_ts; - /// #[derive(Serialize)] - /// struct S { - /// #[serde(serialize_with = "to_micro_ts")] - /// time: NaiveDateTime - /// } - /// - /// let my_s = S { - /// time: NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap(), - /// }; - /// let as_string = serde_json::to_string(&my_s)?; - /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); - /// # Ok::<(), serde_json::Error>(()) - /// ``` - pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result - where - S: ser::Serializer, - { - serializer.serialize_i64(dt.timestamp_micros()) - } - - /// Deserialize a `NaiveDateTime` from a microseconds timestamp - /// - /// Intended for use with `serde`s `deserialize_with` attribute. - /// - /// # Example: - /// - /// ```rust - /// # use chrono::NaiveDateTime; - /// # use serde_derive::Deserialize; - /// use chrono::naive::serde::ts_microseconds::deserialize as from_micro_ts; - /// #[derive(Debug, PartialEq, Deserialize)] - /// struct S { - /// #[serde(deserialize_with = "from_micro_ts")] - /// time: NaiveDateTime - /// } - /// - /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; - /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918355000).unwrap() }); - /// - /// let my_s: S = serde_json::from_str(r#"{ "time": -1 }"#)?; - /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(-1, 999_999_000).unwrap() }); - /// # Ok::<(), serde_json::Error>(()) - /// ``` - pub fn deserialize<'de, D>(d: D) -> Result - where - D: de::Deserializer<'de>, - { - d.deserialize_i64(MicroSecondsTimestampVisitor) - } - - pub(super) struct MicroSecondsTimestampVisitor; - - impl<'de> de::Visitor<'de> for MicroSecondsTimestampVisitor { - type Value = NaiveDateTime; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a unix timestamp") - } - - fn visit_i64(self, value: i64) -> Result - where - E: de::Error, - { - NaiveDateTime::from_timestamp_micros(value) - .ok_or_else(|| E::custom(ne_timestamp(value))) - } - - fn visit_u64(self, value: u64) -> Result - where - E: de::Error, - { - NaiveDateTime::from_timestamp_opt( - (value / 1_000_000) as i64, - ((value % 1_000_000) * 1_000) as u32, - ) - .ok_or_else(|| E::custom(ne_timestamp(value))) - } - } +struct MicroSecondsTimestampVisitor; + +serde_module! { + type: NaiveDateTime, + module: ts_microseconds, + module_opt: ts_microseconds_option, + doc: r##" +# Example + +```rust +# use chrono::{NaiveDate, NaiveDateTime}; +# use serde_derive::{Deserialize, Serialize}; +use chrono::naive::serde::ts_microseconds; +#[derive(Deserialize, Serialize)] +struct S { + #[serde(with = "ts_microseconds")] + time: NaiveDateTime } -/// Ser/de to/from optional timestamps in microseconds -/// -/// Intended for use with `serde`'s `with` attribute. -/// -/// # Example: -/// -/// ```rust -/// # use chrono::naive::{NaiveDate, NaiveDateTime}; -/// # use serde_derive::{Deserialize, Serialize}; -/// use chrono::naive::serde::ts_microseconds_option; -/// #[derive(Deserialize, Serialize)] -/// struct S { -/// #[serde(with = "ts_microseconds_option")] -/// time: Option -/// } -/// -/// let time = Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap()); -/// let my_s = S { -/// time: time.clone(), -/// }; -/// -/// let as_string = serde_json::to_string(&my_s)?; -/// assert_eq!(as_string, r#"{"time":1526522699918355}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; -/// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) -/// ``` -pub mod ts_microseconds_option { - use core::fmt; - use serde::{de, ser}; - - use super::ts_microseconds::MicroSecondsTimestampVisitor; - use crate::NaiveDateTime; - - /// Serialize a datetime into an integer number of microseconds since the epoch or none - /// - /// Intended for use with `serde`s `serialize_with` attribute. - /// - /// # Example: - /// - /// ```rust - /// # use chrono::naive::{NaiveDate, NaiveDateTime}; - /// # use serde_derive::Serialize; - /// use chrono::naive::serde::ts_microseconds_option::serialize as to_micro_tsopt; - /// #[derive(Serialize)] - /// struct S { - /// #[serde(serialize_with = "to_micro_tsopt")] - /// time: Option - /// } - /// - /// let my_s = S { - /// time: Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap()), - /// }; - /// let as_string = serde_json::to_string(&my_s)?; - /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); - /// # Ok::<(), serde_json::Error>(()) - /// ``` - pub fn serialize(opt: &Option, serializer: S) -> Result - where - S: ser::Serializer, - { - match *opt { - Some(ref dt) => serializer.serialize_some(&dt.timestamp_micros()), - None => serializer.serialize_none(), - } - } - - /// Deserialize a `NaiveDateTime` from a nanosecond timestamp or none - /// - /// Intended for use with `serde`s `deserialize_with` attribute. - /// - /// # Example: - /// - /// ```rust - /// # use chrono::naive::NaiveDateTime; - /// # use serde_derive::Deserialize; - /// use chrono::naive::serde::ts_microseconds_option::deserialize as from_micro_tsopt; - /// #[derive(Debug, PartialEq, Deserialize)] - /// struct S { - /// #[serde(deserialize_with = "from_micro_tsopt")] - /// time: Option - /// } - /// - /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; - /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918355000) }); - /// - /// let my_s: S = serde_json::from_str(r#"{ "time": -1 }"#)?; - /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(-1, 999_999_000) }); - /// # Ok::<(), serde_json::Error>(()) - /// ``` - pub fn deserialize<'de, D>(d: D) -> Result, D::Error> - where - D: de::Deserializer<'de>, - { - d.deserialize_option(OptionMicroSecondsTimestampVisitor) - } - - struct OptionMicroSecondsTimestampVisitor; - - impl<'de> de::Visitor<'de> for OptionMicroSecondsTimestampVisitor { - type Value = Option; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a unix timestamp in microseconds or none") - } - - /// Deserialize a timestamp in microseconds since the epoch - fn visit_some(self, d: D) -> Result - where - D: de::Deserializer<'de>, - { - d.deserialize_i64(MicroSecondsTimestampVisitor).map(Some) - } - - /// Deserialize a timestamp in microseconds since the epoch - fn visit_none(self) -> Result - where - E: de::Error, - { - Ok(None) - } - - /// Deserialize a timestamp in microseconds since the epoch - fn visit_unit(self) -> Result - where - E: de::Error, - { - Ok(None) - } - } +let time = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap(); +let my_s = S { + time: time.clone(), +}; + +let as_string = serde_json::to_string(&my_s)?; +assert_eq!(as_string, r#"{"time":1526522699918355}"#); +let my_s: S = serde_json::from_str(&as_string)?; +assert_eq!(my_s.time, time); +# Ok::<(), serde_json::Error>(()) +```"##, + serialize_i64: infallible!(NaiveDateTime::timestamp_micros), + deserialize_i64: MicroSecondsTimestampVisitor, + expecting: "a unix timestamp in microseconds", + visit_i64(i64): |value: i64| NaiveDateTime::from_timestamp_micros(value) + .ok_or_else(|| E::custom(ne_timestamp(value))), + visit_u64(u64): |value: u64| NaiveDateTime::from_timestamp_opt( + (value / 1_000_000) as i64, + ((value % 1_000_000) * 1_000) as u32, + ).ok_or_else(|| E::custom(ne_timestamp(value))), } -/// Used to serialize/deserialize from millisecond-precision timestamps -/// -/// # Example: -/// -/// ```rust -/// # use chrono::{NaiveDate, NaiveDateTime}; -/// # use serde_derive::{Deserialize, Serialize}; -/// use chrono::naive::serde::ts_milliseconds; -/// #[derive(Deserialize, Serialize)] -/// struct S { -/// #[serde(with = "ts_milliseconds")] -/// time: NaiveDateTime -/// } -/// -/// let time = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap(); -/// let my_s = S { -/// time: time.clone(), -/// }; -/// -/// let as_string = serde_json::to_string(&my_s)?; -/// assert_eq!(as_string, r#"{"time":1526522699918}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; -/// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) -/// ``` -pub mod ts_milliseconds { - use core::fmt; - use serde::{de, ser}; - - use super::ne_timestamp; - use crate::NaiveDateTime; - - /// Serialize a datetime into an integer number of milliseconds since the epoch - /// - /// Intended for use with `serde`s `serialize_with` attribute. - /// - /// # Example: - /// - /// ```rust - /// # use chrono::{NaiveDate, NaiveDateTime}; - /// # use serde_derive::Serialize; - /// use chrono::naive::serde::ts_milliseconds::serialize as to_milli_ts; - /// #[derive(Serialize)] - /// struct S { - /// #[serde(serialize_with = "to_milli_ts")] - /// time: NaiveDateTime - /// } - /// - /// let my_s = S { - /// time: NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap(), - /// }; - /// let as_string = serde_json::to_string(&my_s)?; - /// assert_eq!(as_string, r#"{"time":1526522699918}"#); - /// # Ok::<(), serde_json::Error>(()) - /// ``` - pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result - where - S: ser::Serializer, - { - serializer.serialize_i64(dt.timestamp_millis()) - } - - /// Deserialize a `NaiveDateTime` from a milliseconds timestamp - /// - /// Intended for use with `serde`s `deserialize_with` attribute. - /// - /// # Example: - /// - /// ```rust - /// # use chrono::NaiveDateTime; - /// # use serde_derive::Deserialize; - /// use chrono::naive::serde::ts_milliseconds::deserialize as from_milli_ts; - /// #[derive(Debug, PartialEq, Deserialize)] - /// struct S { - /// #[serde(deserialize_with = "from_milli_ts")] - /// time: NaiveDateTime - /// } - /// - /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?; - /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918000000).unwrap() }); - /// - /// let my_s: S = serde_json::from_str(r#"{ "time": -1 }"#)?; - /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(-1, 999_000_000).unwrap() }); - /// # Ok::<(), serde_json::Error>(()) - /// ``` - pub fn deserialize<'de, D>(d: D) -> Result - where - D: de::Deserializer<'de>, - { - d.deserialize_i64(MilliSecondsTimestampVisitor) - } - - pub(super) struct MilliSecondsTimestampVisitor; - - impl<'de> de::Visitor<'de> for MilliSecondsTimestampVisitor { - type Value = NaiveDateTime; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a unix timestamp") - } - - fn visit_i64(self, value: i64) -> Result - where - E: de::Error, - { - NaiveDateTime::from_timestamp_millis(value) - .ok_or_else(|| E::custom(ne_timestamp(value))) - } - - fn visit_u64(self, value: u64) -> Result - where - E: de::Error, - { - NaiveDateTime::from_timestamp_opt( - (value / 1000) as i64, - ((value % 1000) * 1_000_000) as u32, - ) - .ok_or_else(|| E::custom(ne_timestamp(value))) - } - } +struct MilliSecondsTimestampVisitor; + +serde_module! { + type: NaiveDateTime, + module: ts_milliseconds, + module_opt: ts_milliseconds_option, + doc: r##" +# Example + +```rust +# use chrono::{NaiveDate, NaiveDateTime}; +# use serde_derive::{Deserialize, Serialize}; +use chrono::naive::serde::ts_milliseconds; +#[derive(Deserialize, Serialize)] +struct S { + #[serde(with = "ts_milliseconds")] + time: NaiveDateTime } -/// Ser/de to/from optional timestamps in milliseconds -/// -/// Intended for use with `serde`'s `with` attribute. -/// -/// # Example: -/// -/// ```rust -/// # use chrono::naive::{NaiveDate, NaiveDateTime}; -/// # use serde_derive::{Deserialize, Serialize}; -/// use chrono::naive::serde::ts_milliseconds_option; -/// #[derive(Deserialize, Serialize)] -/// struct S { -/// #[serde(with = "ts_milliseconds_option")] -/// time: Option -/// } -/// -/// let time = Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap()); -/// let my_s = S { -/// time: time.clone(), -/// }; -/// -/// let as_string = serde_json::to_string(&my_s)?; -/// assert_eq!(as_string, r#"{"time":1526522699918}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; -/// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) -/// ``` -pub mod ts_milliseconds_option { - use core::fmt; - use serde::{de, ser}; - - use super::ts_milliseconds::MilliSecondsTimestampVisitor; - use crate::NaiveDateTime; - - /// Serialize a datetime into an integer number of milliseconds since the epoch or none - /// - /// Intended for use with `serde`s `serialize_with` attribute. - /// - /// # Example: - /// - /// ```rust - /// # use chrono::naive::{NaiveDate, NaiveDateTime}; - /// # use serde_derive::Serialize; - /// use chrono::naive::serde::ts_milliseconds_option::serialize as to_milli_tsopt; - /// #[derive(Serialize)] - /// struct S { - /// #[serde(serialize_with = "to_milli_tsopt")] - /// time: Option - /// } - /// - /// let my_s = S { - /// time: Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap()), - /// }; - /// let as_string = serde_json::to_string(&my_s)?; - /// assert_eq!(as_string, r#"{"time":1526522699918}"#); - /// # Ok::<(), serde_json::Error>(()) - /// ``` - pub fn serialize(opt: &Option, serializer: S) -> Result - where - S: ser::Serializer, - { - match *opt { - Some(ref dt) => serializer.serialize_some(&dt.timestamp_millis()), - None => serializer.serialize_none(), - } - } - - /// Deserialize a `NaiveDateTime` from a millisecond timestamp or none - /// - /// Intended for use with `serde`s `deserialize_with` attribute. - /// - /// # Example: - /// - /// ```rust - /// # use chrono::naive::NaiveDateTime; - /// # use serde_derive::Deserialize; - /// use chrono::naive::serde::ts_milliseconds_option::deserialize as from_milli_tsopt; - /// #[derive(Debug, PartialEq, Deserialize)] - /// struct S { - /// #[serde(deserialize_with = "from_milli_tsopt")] - /// time: Option - /// } - /// - /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?; - /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918000000) }); - /// - /// let my_s: S = serde_json::from_str(r#"{ "time": -1 }"#)?; - /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(-1, 999_000_000) }); - /// # Ok::<(), serde_json::Error>(()) - /// ``` - pub fn deserialize<'de, D>(d: D) -> Result, D::Error> - where - D: de::Deserializer<'de>, - { - d.deserialize_option(OptionMilliSecondsTimestampVisitor) - } - - struct OptionMilliSecondsTimestampVisitor; - - impl<'de> de::Visitor<'de> for OptionMilliSecondsTimestampVisitor { - type Value = Option; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a unix timestamp in milliseconds or none") - } - - /// Deserialize a timestamp in milliseconds since the epoch - fn visit_some(self, d: D) -> Result - where - D: de::Deserializer<'de>, - { - d.deserialize_i64(MilliSecondsTimestampVisitor).map(Some) - } - - /// Deserialize a timestamp in milliseconds since the epoch - fn visit_none(self) -> Result - where - E: de::Error, - { - Ok(None) - } - - /// Deserialize a timestamp in milliseconds since the epoch - fn visit_unit(self) -> Result - where - E: de::Error, - { - Ok(None) - } - } +let time = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap(); +let my_s = S { + time: time.clone(), +}; + +let as_string = serde_json::to_string(&my_s)?; +assert_eq!(as_string, r#"{"time":1526522699918}"#); +let my_s: S = serde_json::from_str(&as_string)?; +assert_eq!(my_s.time, time); +# Ok::<(), serde_json::Error>(()) +```"##, + serialize_i64: infallible!(NaiveDateTime::timestamp_millis), + deserialize_i64: MilliSecondsTimestampVisitor, + expecting: "a unix timestamp in milliseconds", + visit_i64(i64): |value: i64| NaiveDateTime::from_timestamp_millis(value) + .ok_or_else(|| E::custom(ne_timestamp(value))), + visit_u64(u64): |value: u64| NaiveDateTime::from_timestamp_opt( + (value / 1_000) as i64, + ((value % 1_000) * 1_000_000) as u32, + ).ok_or_else(|| E::custom(ne_timestamp(value))), } -/// Used to serialize/deserialize from second-precision timestamps -/// -/// # Example: -/// -/// ```rust -/// # use chrono::{NaiveDate, NaiveDateTime}; -/// # use serde_derive::{Deserialize, Serialize}; -/// use chrono::naive::serde::ts_seconds; -/// #[derive(Deserialize, Serialize)] -/// struct S { -/// #[serde(with = "ts_seconds")] -/// time: NaiveDateTime -/// } -/// -/// let time = NaiveDate::from_ymd_opt(2015, 5, 15).unwrap().and_hms_opt(10, 0, 0).unwrap(); -/// let my_s = S { -/// time: time.clone(), -/// }; -/// -/// let as_string = serde_json::to_string(&my_s)?; -/// assert_eq!(as_string, r#"{"time":1431684000}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; -/// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) -/// ``` -pub mod ts_seconds { - use core::fmt; - use serde::{de, ser}; - - use super::ne_timestamp; - use crate::NaiveDateTime; - - /// Serialize a datetime into an integer number of seconds since the epoch - /// - /// Intended for use with `serde`s `serialize_with` attribute. - /// - /// # Example: - /// - /// ```rust - /// # use chrono::{NaiveDate, NaiveDateTime}; - /// # use serde_derive::Serialize; - /// use chrono::naive::serde::ts_seconds::serialize as to_ts; - /// #[derive(Serialize)] - /// struct S { - /// #[serde(serialize_with = "to_ts")] - /// time: NaiveDateTime - /// } - /// - /// let my_s = S { - /// time: NaiveDate::from_ymd_opt(2015, 5, 15).unwrap().and_hms_opt(10, 0, 0).unwrap(), - /// }; - /// let as_string = serde_json::to_string(&my_s)?; - /// assert_eq!(as_string, r#"{"time":1431684000}"#); - /// # Ok::<(), serde_json::Error>(()) - /// ``` - pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result - where - S: ser::Serializer, - { - serializer.serialize_i64(dt.timestamp()) - } - - /// Deserialize a `NaiveDateTime` from a seconds timestamp - /// - /// Intended for use with `serde`s `deserialize_with` attribute. - /// - /// # Example: - /// - /// ```rust - /// # use chrono::NaiveDateTime; - /// # use serde_derive::Deserialize; - /// use chrono::naive::serde::ts_seconds::deserialize as from_ts; - /// #[derive(Debug, PartialEq, Deserialize)] - /// struct S { - /// #[serde(deserialize_with = "from_ts")] - /// time: NaiveDateTime - /// } - /// - /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; - /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1431684000, 0).unwrap() }); - /// # Ok::<(), serde_json::Error>(()) - /// ``` - pub fn deserialize<'de, D>(d: D) -> Result - where - D: de::Deserializer<'de>, - { - d.deserialize_i64(SecondsTimestampVisitor) - } - - pub(super) struct SecondsTimestampVisitor; - - impl<'de> de::Visitor<'de> for SecondsTimestampVisitor { - type Value = NaiveDateTime; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a unix timestamp") - } - - fn visit_i64(self, value: i64) -> Result - where - E: de::Error, - { - NaiveDateTime::from_timestamp_opt(value, 0) - .ok_or_else(|| E::custom(ne_timestamp(value))) - } - - fn visit_u64(self, value: u64) -> Result - where - E: de::Error, - { - NaiveDateTime::from_timestamp_opt(value as i64, 0) - .ok_or_else(|| E::custom(ne_timestamp(value))) - } - } +struct SecondsTimestampVisitor; + +serde_module! { + type: NaiveDateTime, + module: ts_seconds, + module_opt: ts_seconds_option, + doc: r##" +# Example + +```rust +# use chrono::{NaiveDate, NaiveDateTime}; +# use serde_derive::{Deserialize, Serialize}; +use chrono::naive::serde::ts_seconds; +#[derive(Deserialize, Serialize)] +struct S { + #[serde(with = "ts_seconds")] + time: NaiveDateTime } -/// Ser/de to/from optional timestamps in seconds -/// -/// Intended for use with `serde`'s `with` attribute. -/// -/// # Example: -/// -/// ```rust -/// # use chrono::naive::{NaiveDate, NaiveDateTime}; -/// # use serde_derive::{Deserialize, Serialize}; -/// use chrono::naive::serde::ts_seconds_option; -/// #[derive(Deserialize, Serialize)] -/// struct S { -/// #[serde(with = "ts_seconds_option")] -/// time: Option -/// } -/// -/// let time = Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_opt(02, 04, 59).unwrap()); -/// let my_s = S { -/// time: time.clone(), -/// }; -/// -/// let as_string = serde_json::to_string(&my_s)?; -/// assert_eq!(as_string, r#"{"time":1526522699}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; -/// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) -/// ``` -pub mod ts_seconds_option { - use core::fmt; - use serde::{de, ser}; - - use super::ts_seconds::SecondsTimestampVisitor; - use crate::NaiveDateTime; - - /// Serialize a datetime into an integer number of seconds since the epoch or none - /// - /// Intended for use with `serde`s `serialize_with` attribute. - /// - /// # Example: - /// - /// ```rust - /// # use chrono::naive::{NaiveDate, NaiveDateTime}; - /// # use serde_derive::Serialize; - /// use chrono::naive::serde::ts_seconds_option::serialize as to_tsopt; - /// #[derive(Serialize)] - /// struct S { - /// #[serde(serialize_with = "to_tsopt")] - /// time: Option - /// } - /// - /// let my_s = S { - /// time: Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_opt(02, 04, 59).unwrap()), - /// }; - /// let as_string = serde_json::to_string(&my_s)?; - /// assert_eq!(as_string, r#"{"time":1526522699}"#); - /// # Ok::<(), serde_json::Error>(()) - /// ``` - pub fn serialize(opt: &Option, serializer: S) -> Result - where - S: ser::Serializer, - { - match *opt { - Some(ref dt) => serializer.serialize_some(&dt.timestamp()), - None => serializer.serialize_none(), - } - } - - /// Deserialize a `NaiveDateTime` from a second timestamp or none - /// - /// Intended for use with `serde`s `deserialize_with` attribute. - /// - /// # Example: - /// - /// ```rust - /// # use chrono::naive::NaiveDateTime; - /// # use serde_derive::Deserialize; - /// use chrono::naive::serde::ts_seconds_option::deserialize as from_tsopt; - /// #[derive(Debug, PartialEq, Deserialize)] - /// struct S { - /// #[serde(deserialize_with = "from_tsopt")] - /// time: Option - /// } - /// - /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; - /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1431684000, 0) }); - /// # Ok::<(), serde_json::Error>(()) - /// ``` - pub fn deserialize<'de, D>(d: D) -> Result, D::Error> - where - D: de::Deserializer<'de>, - { - d.deserialize_option(OptionSecondsTimestampVisitor) - } - - struct OptionSecondsTimestampVisitor; - - impl<'de> de::Visitor<'de> for OptionSecondsTimestampVisitor { - type Value = Option; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a unix timestamp in seconds or none") - } - - /// Deserialize a timestamp in seconds since the epoch - fn visit_some(self, d: D) -> Result - where - D: de::Deserializer<'de>, - { - d.deserialize_i64(SecondsTimestampVisitor).map(Some) - } - - /// Deserialize a timestamp in seconds since the epoch - fn visit_none(self) -> Result - where - E: de::Error, - { - Ok(None) - } - - /// Deserialize a timestamp in seconds since the epoch - fn visit_unit(self) -> Result - where - E: de::Error, - { - Ok(None) - } - } +let time = NaiveDate::from_ymd_opt(2015, 5, 15).unwrap().and_hms_opt(10, 0, 0).unwrap(); +let my_s = S { + time: time.clone(), +}; + +let as_string = serde_json::to_string(&my_s)?; +assert_eq!(as_string, r#"{"time":1431684000}"#); +let my_s: S = serde_json::from_str(&as_string)?; +assert_eq!(my_s.time, time); +# Ok::<(), serde_json::Error>(()) +```"##, + serialize_i64: infallible!(NaiveDateTime::timestamp), + deserialize_i64: SecondsTimestampVisitor, + expecting: "a unix timestamp", + visit_i64(i64): |value: i64| NaiveDateTime::from_timestamp_opt(value, 0) + .ok_or_else(|| E::custom(ne_timestamp(value))), + visit_u64(u64): |value: u64| NaiveDateTime::from_timestamp_opt(value as i64, 0) + .ok_or_else(|| E::custom(ne_timestamp(value))), } #[cfg(test)]