//! De/Serialization of [chrono] types //! //! This modules is only available if using the `chrono_0_4` feature of the crate. //! //! [chrono]: https://docs.rs/chrono/
// Serialization of large numbers can result in overflows // The time calculations are prone to this, so lint here extra // https://github.com/jonasbb/serde_with/issues/771 #![warn(clippy::as_conversions)]
usecrate::{
formats::{Flexible, Format, Strict, Strictness},
prelude::*,
}; #[cfg(feature = "std")] use ::chrono_0_4::Local; use ::chrono_0_4::{DateTime, Duration, NaiveDateTime, TimeZone, Utc};
/// Create a [`DateTime`] for the Unix Epoch using the [`Utc`] timezone fn unix_epoch_utc() -> DateTime<Utc> {
Utc.from_utc_datetime(&unix_epoch_naive())
}
/// Create a [`DateTime`] for the Unix Epoch using the [`Local`] timezone #[cfg(feature = "std")] fn unix_epoch_local() -> DateTime<Local> {
Local.from_utc_datetime(&unix_epoch_naive())
}
/// Create a [`NaiveDateTime`] for the Unix Epoch fn unix_epoch_naive() -> NaiveDateTime {
DateTime::from_timestamp(0, 0).unwrap().naive_utc()
}
/// Deserialize a Unix timestamp with optional sub-second precision into a `DateTime<Utc>`. /// /// The `DateTime<Utc>` can be serialized from an integer, a float, or a string representing a number. /// /// # Examples /// /// ``` /// # use chrono_0_4::{DateTime, Utc}; /// # use serde::Deserialize; /// # /// #[derive(Debug, Deserialize)] /// struct S { /// #[serde(with = "serde_with::chrono_0_4::datetime_utc_ts_seconds_from_any")] /// date: DateTime<Utc>, /// } /// /// // Deserializes integers /// assert!(serde_json::from_str::<S>(r#"{ "date": 1478563200 }"#).is_ok()); /// # // Ensure the date field is not dead code /// # assert_eq!(serde_json::from_str::<S>(r#"{ "date": 1478563200 }"#).unwrap().date.timestamp(), 1478563200); /// // floats /// assert!(serde_json::from_str::<S>(r#"{ "date": 1478563200.123 }"#).is_ok()); /// // and strings with numbers, for high-precision values /// assert!(serde_json::from_str::<S>(r#"{ "date": "1478563200.123" }"#).is_ok()); /// ``` // Requires float operations from std #[cfg(feature = "std")] pubmod datetime_utc_ts_seconds_from_any { usesuper::*;
/// Deserialize a Unix timestamp with optional subsecond precision into a `DateTime<Utc>`. pubfn deserialize<'de, D>(deserializer: D) -> Result<DateTime<Utc>, D::Error> where
D: Deserializer<'de>,
{ struct Helper; impl Visitor<'_> for Helper { type Value = DateTime<Utc>;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.write_str("an integer, float, or string with optional subsecond precision.")
}
fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> where
E: DeError,
{
DateTime::from_timestamp(value, 0).ok_or_else(|| {
DeError::custom(format_args!( "a timestamp which can be represented in a DateTime but received '{value}'"
))
})
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> where
E: DeError,
{ let value = i64::try_from(value).map_err(|_| {
DeError::custom(format_args!( "a timestamp which can be represented in a DateTime but received '{value}'"
))
})?;
DateTime::from_timestamp(value, 0).ok_or_else(|| {
DeError::custom(format_args!( "a timestamp which can be represented in a DateTime but received '{value}'"
))
})
}
// as conversions are necessary for floats #[allow(clippy::as_conversions)] fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E> where
E: DeError,
{ let seconds = value.trunc() as i64; let nsecs = (value.fract() * 1_000_000_000_f64).abs() as u32;
DateTime::from_timestamp(seconds, nsecs).ok_or_else(|| {
DeError::custom(format_args!( "a timestamp which can be represented in a DateTime but received '{value}'"
))
})
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where
E: DeError,
{ let parts: Vec<_> = value.split('.').collect();
match *parts.as_slice() {
[seconds] => { iflet Ok(seconds) = seconds.parse() {
DateTime::from_timestamp(seconds, 0).ok_or_else(|| {
DeError::custom(format_args!( "a timestamp which can be represented in a DateTime but received '{value}'"
))
})
} else {
Err(DeError::invalid_value(Unexpected::Str(value), &self))
}
}
[seconds, subseconds] => { iflet Ok(seconds) = seconds.parse() { let subseclen = match u32::try_from(subseconds.chars().count()) {
Ok(subseclen) if subseclen <= 9 => subseclen,
_ => return Err(DeError::custom(format_args!( "DateTimes only support nanosecond precision but '{value}' has more than 9 digits."
))),
};
iflet Ok(mut subseconds) = subseconds.parse() { // convert subseconds to nanoseconds (10^-9), require 9 places for nanoseconds
subseconds *= 10u32.pow(9 - subseclen);
DateTime::from_timestamp(seconds, subseconds).ok_or_else(|| {
DeError::custom(format_args!( "a timestamp which can be represented in a DateTime but received '{value}'"
))
})
} else {
Err(DeError::invalid_value(Unexpected::Str(value), &self))
}
} else {
Err(DeError::invalid_value(Unexpected::Str(value), &self))
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.