Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serde rfc 2822 #1412

Closed
wants to merge 3 commits into from
Closed
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
75 changes: 75 additions & 0 deletions src/datetime/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
#[derive(Debug)]
pub struct MilliSecondsTimestampVisitor;

#[doc(hidden)]
#[derive(Debug)]
pub struct Rfc2822Visitor;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you can make this private. The others are public for backwards compatibility.


/// Serialize into an ISO 8601 formatted string.
///
/// See [the `serde` module](./serde/index.html) for alternate
Expand Down Expand Up @@ -1168,6 +1172,77 @@
}
}

/// 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::serde::Rfc2822Visitor;
use crate::{DateTime, FixedOffset};
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,
{
serializer.serialize_str(&dt.to_rfc2822())
Copy link
Collaborator

@pitdicker pitdicker Feb 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In format/formatting.rs there is a write_rfc2822 function that works without allocating. Using that will make this serializer work on no_std targets like the others (and make the CI pass).

You will have to adjust its #[cfg(feature = "alloc")] to also enable it with the serde feature.

}

/// 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 (email) formatted datetime string")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I would remove (email) .

}

Check warning on line 1235 in src/datetime/serde.rs

View check run for this annotation

Codecov / codecov/patch

src/datetime/serde.rs#L1233-L1235

Added lines #L1233 - L1235 were not covered by tests

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
Loading