Skip to content

Commit 3552fcf

Browse files
chrisrandersonpitdicker
authored andcommitted
Add RFC 2822 serde module
1 parent cf17f7a commit 3552fcf

File tree

3 files changed

+90
-4
lines changed

3 files changed

+90
-4
lines changed

src/datetime/serde.rs

+86
Original file line numberDiff line numberDiff line change
@@ -1168,6 +1168,92 @@ pub mod ts_seconds_option {
11681168
}
11691169
}
11701170

1171+
/// Ser/de to/from RFC 2822 strings
1172+
///
1173+
/// Intended for use with `serde`'s `with` attribute.
1174+
///
1175+
/// # Example:
1176+
///
1177+
/// ```rust
1178+
/// use chrono::{DateTime, NaiveDate, FixedOffset, TimeZone};
1179+
/// use serde_derive::{Deserialize, Serialize};
1180+
///
1181+
/// #[derive(Deserialize, Serialize)]
1182+
/// struct Example {
1183+
/// #[serde(with = "chrono::serde::rfc2822")]
1184+
/// time: DateTime<FixedOffset>
1185+
/// }
1186+
/// let offset = 3600;
1187+
/// let actual_time = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap()
1188+
/// .and_hms_opt(02, 04, 59).unwrap()
1189+
/// .and_local_timezone(TimeZone::from_offset(&FixedOffset::east_opt(offset).unwrap())).unwrap();
1190+
/// let to_serialize = Example {
1191+
/// time: actual_time.clone(),
1192+
/// };
1193+
///
1194+
/// let serialized = serde_json::to_string(&to_serialize).unwrap();
1195+
/// assert_eq!(serialized, r#"{"time":"Thu, 17 May 2018 02:04:59 +0100"}"#);
1196+
///
1197+
/// let deserialized: Example = serde_json::from_str(&serialized).unwrap();
1198+
/// assert_eq!(deserialized.time, actual_time);
1199+
/// ```
1200+
pub mod rfc2822 {
1201+
use crate::{DateTime, FixedOffset, Offset, TimeZone};
1202+
use crate::format::write_rfc2822;
1203+
use core::fmt;
1204+
use serde::{de, ser};
1205+
1206+
/// Serialize a datetime into an RFC 2822 formatted string, e.g. "01 Jun 2016 14:31:46 -0700"
1207+
///
1208+
/// Intended for use with `serde`s `serialize_with` attribute.
1209+
pub fn serialize<S>(dt: &DateTime<FixedOffset>, serializer: S) -> Result<S::Ok, S::Error>
1210+
where
1211+
S: ser::Serializer,
1212+
{
1213+
struct FormatRfc2822<'a, Tz: TimeZone> {
1214+
inner: &'a DateTime<Tz>,
1215+
}
1216+
1217+
impl<'a, Tz: TimeZone> fmt::Display for FormatRfc2822<'a, Tz> {
1218+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1219+
let naive = self.inner.naive_local();
1220+
let offset = self.inner.offset.fix();
1221+
write_rfc2822(f, naive, offset)
1222+
}
1223+
}
1224+
1225+
serializer.collect_str(&FormatRfc2822 { inner: dt })
1226+
}
1227+
1228+
#[derive(Debug)]
1229+
struct Rfc2822Visitor;
1230+
1231+
/// Deserialize a [`DateTime`] from an RFC 2822 datetime
1232+
///
1233+
/// Intended for use with `serde`s `deserialize_with` attribute.
1234+
pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTime<FixedOffset>, D::Error>
1235+
where
1236+
D: de::Deserializer<'de>,
1237+
{
1238+
deserializer.deserialize_str(Rfc2822Visitor)
1239+
}
1240+
1241+
impl<'de> de::Visitor<'de> for Rfc2822Visitor {
1242+
type Value = DateTime<FixedOffset>;
1243+
1244+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1245+
formatter.write_str("an RFC 2822 formatted datetime string")
1246+
}
1247+
1248+
fn visit_str<E>(self, date_string: &str) -> Result<Self::Value, E>
1249+
where
1250+
E: de::Error,
1251+
{
1252+
DateTime::parse_from_rfc2822(date_string).map_err(E::custom)
1253+
}
1254+
}
1255+
}
1256+
11711257
#[cfg(test)]
11721258
mod tests {
11731259
#[cfg(feature = "clock")]

src/format/formatting.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ use crate::{Datelike, FixedOffset, NaiveDateTime, Timelike};
1818
#[cfg(feature = "alloc")]
1919
use crate::{NaiveDate, NaiveTime, Weekday};
2020

21-
#[cfg(feature = "alloc")]
21+
#[cfg(any(feature = "alloc", feature = "serde"))]
2222
use super::locales;
2323
#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
2424
use super::Locale;
2525
#[cfg(any(feature = "alloc", feature = "serde", feature = "rustc-serialize"))]
2626
use super::{Colons, OffsetFormat, OffsetPrecision, Pad};
2727
#[cfg(feature = "alloc")]
2828
use super::{Fixed, InternalFixed, InternalInternal, Item, Numeric};
29-
#[cfg(feature = "alloc")]
29+
#[cfg(any(feature = "alloc", feature = "serde"))]
3030
use locales::*;
3131

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

598-
#[cfg(feature = "alloc")]
598+
#[cfg(any(feature = "alloc", feature = "serde"))]
599599
/// write datetimes like `Tue, 1 Jul 2003 10:52:37 +0200`, same as `%a, %d %b %Y %H:%M:%S %z`
600600
pub(crate) fn write_rfc2822(
601601
w: &mut impl Write,

src/format/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ pub mod strftime;
5454
pub(crate) mod locales;
5555

5656
pub(crate) use formatting::write_hundreds;
57-
#[cfg(feature = "alloc")]
57+
#[cfg(any(feature = "alloc", feature = "serde"))]
5858
pub(crate) use formatting::write_rfc2822;
5959
#[cfg(any(feature = "alloc", feature = "serde", feature = "rustc-serialize"))]
6060
pub(crate) use formatting::write_rfc3339;

0 commit comments

Comments
 (0)