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

Add DateTime::try_to_rfc2822, deprecate DateTime::to_rfc2822 #1330

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion bench/benches/chrono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ fn bench_datetime_to_rfc2822(c: &mut Criterion) {
.unwrap(),
)
.unwrap();
c.bench_function("bench_datetime_to_rfc2822", |b| b.iter(|| black_box(dt).to_rfc2822()));
c.bench_function("bench_datetime_to_rfc2822", |b| {
b.iter(|| black_box(dt).try_to_rfc2822().unwrap())
});
}

fn bench_datetime_to_rfc3339(c: &mut Criterion) {
Expand Down
35 changes: 30 additions & 5 deletions src/datetime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,15 +619,40 @@ impl<Tz: TimeZone> DateTime<Tz> {
///
/// # Panics
///
/// Panics if the date can not be represented in this format: the year may not be negative and
/// can not have more than 4 digits.
/// RFC 2822 is only defined on years 0 through 9999, and this method panics on dates outside
/// of that range.
#[cfg(feature = "alloc")]
#[must_use]
#[deprecated(
since = "0.4.36",
note = "Can panic on years outside of the range 0..=9999. Use `try_to_rfc2822()` instead."
)]
pub fn to_rfc2822(&self) -> String {
self.try_to_rfc2822().expect("date outside of defined range for rfc2822")
}

/// Returns an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`.
///
/// # Errors
///
/// RFC 2822 is only defined on years 0 through 9999, and this method returns an error on dates
/// outside of that range.
///
/// # Example
///
/// ```rust
/// # use chrono::{TimeZone, Utc};
/// let dt = Utc.with_ymd_and_hms(2023, 6, 10, 9, 18, 25).unwrap();
/// assert_eq!(dt.try_to_rfc2822(), Some("Sat, 10 Jun 2023 09:18:25 +0000".to_owned()));
///
/// let dt = Utc.with_ymd_and_hms(10_000, 1, 1, 0, 0, 0).unwrap();
/// assert_eq!(dt.try_to_rfc2822(), None);
/// ```
#[cfg(feature = "alloc")]
pub fn try_to_rfc2822(&self) -> Option<String> {
let mut result = String::with_capacity(32);
write_rfc2822(&mut result, self.overflowing_naive_local(), self.offset.fix())
.expect("writing rfc2822 datetime to string should never fail");
result
write_rfc2822(&mut result, self.overflowing_naive_local(), self.offset.fix()).ok()?;
Some(result)
}

/// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`.
Expand Down
56 changes: 42 additions & 14 deletions src/datetime/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,17 +640,18 @@ fn test_datetime_with_timezone() {

#[test]
#[cfg(feature = "alloc")]
#[allow(deprecated)]
fn test_datetime_rfc2822() {
let edt = FixedOffset::east_opt(5 * 60 * 60).unwrap();

// timezone 0
assert_eq!(
Utc.with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap().to_rfc2822(),
"Wed, 18 Feb 2015 23:16:09 +0000"
Utc.with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap().try_to_rfc2822().as_deref(),
Some("Wed, 18 Feb 2015 23:16:09 +0000")
);
assert_eq!(
Utc.with_ymd_and_hms(2015, 2, 1, 23, 16, 9).unwrap().to_rfc2822(),
"Sun, 1 Feb 2015 23:16:09 +0000"
Utc.with_ymd_and_hms(2015, 2, 1, 23, 16, 9).unwrap().try_to_rfc2822().as_deref(),
Some("Sun, 1 Feb 2015 23:16:09 +0000")
);
// timezone +05
assert_eq!(
Expand All @@ -661,8 +662,9 @@ fn test_datetime_rfc2822() {
.unwrap()
)
.unwrap()
.to_rfc2822(),
"Wed, 18 Feb 2015 23:16:09 +0500"
.try_to_rfc2822()
.as_deref(),
Some("Wed, 18 Feb 2015 23:16:09 +0500")
);
assert_eq!(
DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:60 +0500"),
Expand Down Expand Up @@ -696,8 +698,9 @@ fn test_datetime_rfc2822() {
.unwrap()
)
.unwrap()
.to_rfc2822(),
"Wed, 18 Feb 2015 23:59:60 +0500"
.try_to_rfc2822()
.as_deref(),
Some("Wed, 18 Feb 2015 23:59:60 +0500")
);

assert_eq!(
Expand All @@ -709,8 +712,8 @@ fn test_datetime_rfc2822() {
Ok(FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap())
);
assert_eq!(
ymdhms_micro(&edt, 2015, 2, 18, 23, 59, 59, 1_234_567).to_rfc2822(),
"Wed, 18 Feb 2015 23:59:60 +0500"
ymdhms_micro(&edt, 2015, 2, 18, 23, 59, 59, 1_234_567).try_to_rfc2822().as_deref(),
Some("Wed, 18 Feb 2015 23:59:60 +0500")
);
assert_eq!(
DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:58 +0500"),
Expand Down Expand Up @@ -762,6 +765,31 @@ fn test_datetime_rfc2822() {
assert!(DateTime::parse_from_rfc2822("Wed. 18 Feb 2015 23:16:09 +0000").is_err());
// *trailing* space causes failure
assert!(DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 +0000 ").is_err());

const RFC_2822_YEAR_MAX: i32 = 9999;
const RFC_2822_YEAR_MIN: i32 = 0;

let dt = Utc.with_ymd_and_hms(RFC_2822_YEAR_MAX, 1, 2, 3, 4, 5).unwrap();
assert_eq!(dt.to_rfc2822(), "Sat, 2 Jan 9999 03:04:05 +0000");

let dt = Utc.with_ymd_and_hms(RFC_2822_YEAR_MIN, 1, 2, 3, 4, 5).unwrap();
assert_eq!(dt.to_rfc2822(), "Sun, 2 Jan 0000 03:04:05 +0000");
}

#[test]
#[should_panic]
#[cfg(feature = "alloc")]
#[allow(deprecated)]
fn test_rfc_2822_year_range_panic_high() {
let _ = Utc.with_ymd_and_hms(10000, 1, 2, 3, 4, 5).unwrap().to_rfc2822();
}

#[test]
#[should_panic]
#[cfg(feature = "alloc")]
#[allow(deprecated)]
fn test_rfc_2822_year_range_panic_low() {
let _ = Utc.with_ymd_and_hms(-1, 1, 2, 3, 4, 5).unwrap().to_rfc2822();
}

#[test]
Expand Down Expand Up @@ -1535,8 +1563,8 @@ fn test_min_max_getters() {
let beyond_max = offset_max.from_utc_datetime(&NaiveDateTime::MAX);

assert_eq!(format!("{:?}", beyond_min), "-262144-12-31T22:00:00-02:00");
// RFC 2822 doesn't support years with more than 4 digits.
// assert_eq!(beyond_min.to_rfc2822(), "");
#[cfg(feature = "alloc")]
assert_eq!(beyond_min.try_to_rfc2822(), None); // doesn't support years with more than 4 digits.
#[cfg(feature = "alloc")]
assert_eq!(beyond_min.to_rfc3339(), "-262144-12-31T22:00:00-02:00");
#[cfg(feature = "alloc")]
Expand All @@ -1560,8 +1588,8 @@ fn test_min_max_getters() {
assert_eq!(beyond_min.nanosecond(), 0);

assert_eq!(format!("{:?}", beyond_max), "+262143-01-01T01:59:59.999999999+02:00");
// RFC 2822 doesn't support years with more than 4 digits.
// assert_eq!(beyond_max.to_rfc2822(), "");
#[cfg(feature = "alloc")]
assert_eq!(beyond_max.try_to_rfc2822(), None); // doesn't support years with more than 4 digits.
#[cfg(feature = "alloc")]
assert_eq!(beyond_max.to_rfc3339(), "+262143-01-01T01:59:59.999999999+02:00");
#[cfg(feature = "alloc")]
Expand Down
7 changes: 6 additions & 1 deletion src/format/formatting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,8 +595,13 @@ pub(crate) fn write_rfc3339(
.format(w, off)
}

/// Write datetimes like `Tue, 1 Jul 2003 10:52:37 +0200`, same as `%a, %d %b %Y %H:%M:%S %z`
///
/// # Errors
///
/// RFC 2822 is only defined on years 0 through 9999, and this function returns an error on dates
/// outside that range.
#[cfg(feature = "alloc")]
/// 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,
dt: NaiveDateTime,
Expand Down
4 changes: 2 additions & 2 deletions src/format/parsed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ use crate::{DateTime, Datelike, TimeDelta, Timelike, Weekday};
/// parsed.set_second(40)?;
/// parsed.set_offset(0)?;
/// let dt = parsed.to_datetime()?;
/// assert_eq!(dt.to_rfc2822(), "Wed, 31 Dec 2014 04:26:40 +0000");
/// assert_eq!(dt.try_to_rfc2822().unwrap(), "Wed, 31 Dec 2014 04:26:40 +0000");
///
/// let mut parsed = Parsed::new();
/// parsed.set_weekday(Weekday::Thu)?; // changed to the wrong day
Expand Down Expand Up @@ -109,7 +109,7 @@ use crate::{DateTime, Datelike, TimeDelta, Timelike, Weekday};
/// parse(&mut parsed, "Wed, 31 Dec 2014 04:26:40 +0000", rfc_2822.iter())?;
/// let dt = parsed.to_datetime()?;
///
/// assert_eq!(dt.to_rfc2822(), "Wed, 31 Dec 2014 04:26:40 +0000");
/// assert_eq!(dt.try_to_rfc2822().unwrap(), "Wed, 31 Dec 2014 04:26:40 +0000");
///
/// let mut parsed = Parsed::new();
/// parse(&mut parsed, "Thu, 31 Dec 2014 04:26:40 +0000", rfc_2822.iter())?;
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@
//!
//! assert_eq!(dt.format("%a %b %e %T %Y").to_string(), dt.format("%c").to_string());
//! assert_eq!(dt.to_string(), "2014-11-28 12:00:09 UTC");
//! assert_eq!(dt.to_rfc2822(), "Fri, 28 Nov 2014 12:00:09 +0000");
//! assert_eq!(dt.try_to_rfc2822().unwrap(), "Fri, 28 Nov 2014 12:00:09 +0000");
//! assert_eq!(dt.to_rfc3339(), "2014-11-28T12:00:09+00:00");
//! assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z");
//!
Expand Down Expand Up @@ -396,7 +396,7 @@
//!
//! // Construct a datetime from epoch:
//! let dt: DateTime<Utc> = DateTime::from_timestamp(1_500_000_000, 0).unwrap();
//! assert_eq!(dt.to_rfc2822(), "Fri, 14 Jul 2017 02:40:00 +0000");
//! assert_eq!(dt.try_to_rfc2822(), Some("Fri, 14 Jul 2017 02:40:00 +0000".to_owned()));
//!
//! // Get epoch value from a datetime:
//! let dt = DateTime::parse_from_rfc2822("Fri, 14 Jul 2017 02:40:00 +0000").unwrap();
Expand Down