Skip to content

Commit dff44e8

Browse files
chrisrandersonpitdicker
authored andcommitted
Add RFC 2822 serde module
1 parent 0aa46dd commit dff44e8

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
@@ -1213,6 +1213,92 @@ pub mod ts_seconds_option {
12131213
}
12141214
}
12151215

1216+
/// Ser/de to/from RFC 2822 strings
1217+
///
1218+
/// Intended for use with `serde`'s `with` attribute.
1219+
///
1220+
/// # Example:
1221+
///
1222+
/// ```rust
1223+
/// use chrono::{DateTime, NaiveDate, FixedOffset, TimeZone};
1224+
/// use serde_derive::{Deserialize, Serialize};
1225+
///
1226+
/// #[derive(Deserialize, Serialize)]
1227+
/// struct Example {
1228+
/// #[serde(with = "chrono::serde::rfc2822")]
1229+
/// time: DateTime<FixedOffset>
1230+
/// }
1231+
/// let offset = 3600;
1232+
/// let actual_time = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap()
1233+
/// .and_hms_opt(02, 04, 59).unwrap()
1234+
/// .and_local_timezone(TimeZone::from_offset(&FixedOffset::east_opt(offset).unwrap())).unwrap();
1235+
/// let to_serialize = Example {
1236+
/// time: actual_time.clone(),
1237+
/// };
1238+
///
1239+
/// let serialized = serde_json::to_string(&to_serialize).unwrap();
1240+
/// assert_eq!(serialized, r#"{"time":"Thu, 17 May 2018 02:04:59 +0100"}"#);
1241+
///
1242+
/// let deserialized: Example = serde_json::from_str(&serialized).unwrap();
1243+
/// assert_eq!(deserialized.time, actual_time);
1244+
/// ```
1245+
pub mod rfc2822 {
1246+
use crate::{DateTime, FixedOffset, Offset, TimeZone};
1247+
use crate::format::write_rfc2822;
1248+
use core::fmt;
1249+
use serde::{de, ser};
1250+
1251+
/// Serialize a datetime into an RFC 2822 formatted string, e.g. "01 Jun 2016 14:31:46 -0700"
1252+
///
1253+
/// Intended for use with `serde`s `serialize_with` attribute.
1254+
pub fn serialize<S>(dt: &DateTime<FixedOffset>, serializer: S) -> Result<S::Ok, S::Error>
1255+
where
1256+
S: ser::Serializer,
1257+
{
1258+
struct FormatRfc2822<'a, Tz: TimeZone> {
1259+
inner: &'a DateTime<Tz>,
1260+
}
1261+
1262+
impl<'a, Tz: TimeZone> fmt::Display for FormatRfc2822<'a, Tz> {
1263+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1264+
let naive = self.inner.naive_local();
1265+
let offset = self.inner.offset.fix();
1266+
write_rfc2822(f, naive, offset)
1267+
}
1268+
}
1269+
1270+
serializer.collect_str(&FormatRfc2822 { inner: dt })
1271+
}
1272+
1273+
#[derive(Debug)]
1274+
struct Rfc2822Visitor;
1275+
1276+
/// Deserialize a [`DateTime`] from an RFC 2822 datetime
1277+
///
1278+
/// Intended for use with `serde`s `deserialize_with` attribute.
1279+
pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTime<FixedOffset>, D::Error>
1280+
where
1281+
D: de::Deserializer<'de>,
1282+
{
1283+
deserializer.deserialize_str(Rfc2822Visitor)
1284+
}
1285+
1286+
impl<'de> de::Visitor<'de> for Rfc2822Visitor {
1287+
type Value = DateTime<FixedOffset>;
1288+
1289+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1290+
formatter.write_str("an RFC 2822 formatted datetime string")
1291+
}
1292+
1293+
fn visit_str<E>(self, date_string: &str) -> Result<Self::Value, E>
1294+
where
1295+
E: de::Error,
1296+
{
1297+
DateTime::parse_from_rfc2822(date_string).map_err(E::custom)
1298+
}
1299+
}
1300+
}
1301+
12161302
#[cfg(test)]
12171303
mod tests {
12181304
#[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)