Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions src/datetime/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1213,6 +1213,92 @@ pub mod ts_seconds_option {
}
}

/// Ser/de to/from RFC 2822 strings
///
/// Intended for use with `serde`'s `with` attribute.
///
/// # Example:
///
/// ```rust
/// use chrono::{DateTime, NaiveDate, FixedOffset, TimeZone};
/// use serde_derive::{Deserialize, Serialize};
///
/// #[derive(Deserialize, Serialize)]
/// struct Example {
/// #[serde(with = "chrono::serde::rfc2822")]
/// time: DateTime<FixedOffset>
/// }
/// let offset = 3600;
/// let actual_time = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap()
/// .and_hms_opt(02, 04, 59).unwrap()
/// .and_local_timezone(TimeZone::from_offset(&FixedOffset::east_opt(offset).unwrap())).unwrap();
/// let to_serialize = Example {
/// time: actual_time.clone(),
/// };
///
/// let serialized = serde_json::to_string(&to_serialize).unwrap();
/// assert_eq!(serialized, r#"{"time":"Thu, 17 May 2018 02:04:59 +0100"}"#);
///
/// let deserialized: Example = serde_json::from_str(&serialized).unwrap();
/// assert_eq!(deserialized.time, actual_time);
/// ```
pub mod rfc2822 {
use crate::format::write_rfc2822;
use crate::{DateTime, FixedOffset, Offset, TimeZone};
use core::fmt;
use serde::{de, ser};

/// Serialize a datetime into an RFC 2822 formatted string, e.g. "01 Jun 2016 14:31:46 -0700"
///
/// Intended for use with `serde`s `serialize_with` attribute.
pub fn serialize<S>(dt: &DateTime<FixedOffset>, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
struct FormatRfc2822<'a, Tz: TimeZone> {
inner: &'a DateTime<Tz>,
}

impl<'a, Tz: TimeZone> fmt::Display for FormatRfc2822<'a, Tz> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let naive = self.inner.naive_local();
let offset = self.inner.offset.fix();
write_rfc2822(f, naive, offset)
}
}

serializer.collect_str(&FormatRfc2822 { inner: dt })
}

#[derive(Debug)]
struct Rfc2822Visitor;

/// Deserialize a [`DateTime`] from an RFC 2822 datetime
///
/// Intended for use with `serde`s `deserialize_with` attribute.
pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTime<FixedOffset>, D::Error>
where
D: de::Deserializer<'de>,
{
deserializer.deserialize_str(Rfc2822Visitor)
}

impl<'de> de::Visitor<'de> for Rfc2822Visitor {
type Value = DateTime<FixedOffset>;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an RFC 2822 formatted datetime string")
}

fn visit_str<E>(self, date_string: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
DateTime::parse_from_rfc2822(date_string).map_err(E::custom)
}
}
}

#[cfg(test)]
mod tests {
#[cfg(feature = "clock")]
Expand Down
6 changes: 3 additions & 3 deletions src/format/formatting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ use crate::{Datelike, FixedOffset, NaiveDateTime, Timelike};
#[cfg(feature = "alloc")]
use crate::{NaiveDate, NaiveTime, Weekday};

#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", feature = "serde"))]
use super::locales;
#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
use super::Locale;
#[cfg(any(feature = "alloc", feature = "serde", feature = "rustc-serialize"))]
use super::{Colons, OffsetFormat, OffsetPrecision, Pad};
#[cfg(feature = "alloc")]
use super::{Fixed, InternalFixed, InternalInternal, Item, Numeric};
#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", feature = "serde"))]
use locales::*;

/// A *temporary* object which can be used as an argument to `format!` or others.
Expand Down Expand Up @@ -595,7 +595,7 @@ pub(crate) fn write_rfc3339(
.format(w, off)
}

#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", feature = "serde"))]
/// write datetimes like `Tue, 1 Jul 2003 10:52:37 +0200`, same as `%a, %d %b %Y %H:%M:%S %z`
pub(crate) fn write_rfc2822(
w: &mut impl Write,
Expand Down
2 changes: 1 addition & 1 deletion src/format/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ pub mod strftime;
pub(crate) mod locales;

pub(crate) use formatting::write_hundreds;
#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", feature = "serde"))]
pub(crate) use formatting::write_rfc2822;
#[cfg(any(feature = "alloc", feature = "serde", feature = "rustc-serialize"))]
pub(crate) use formatting::write_rfc3339;
Expand Down