diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index a7bd7a9fa0..8686340e16 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -488,6 +488,103 @@ impl DateTime { } } + /// Returns an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`. + /// + /// # 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. + #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] + #[must_use] + pub fn to_rfc2822(&self) -> String { + let mut result = String::with_capacity(32); + crate::format::write_rfc2822(&mut result, self.naive_local(), self.offset.fix()) + .expect("writing rfc2822 datetime to string should never fail"); + result + } + + /// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`. + #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] + #[must_use] + pub fn to_rfc3339(&self) -> String { + let mut result = String::with_capacity(32); + crate::format::write_rfc3339(&mut result, self.naive_local(), self.offset.fix()) + .expect("writing rfc3339 datetime to string should never fail"); + result + } + + /// Return an RFC 3339 and ISO 8601 date and time string with subseconds + /// formatted as per `SecondsFormat`. + /// + /// If `use_z` is true and the timezone is UTC (offset 0), uses `Z` as + /// per [`Fixed::TimezoneOffsetColonZ`]. If `use_z` is false, uses + /// [`Fixed::TimezoneOffsetColon`] + /// + /// # Examples + /// + /// ```rust + /// # use chrono::{FixedOffset, SecondsFormat, TimeZone, Utc, NaiveDate}; + /// let dt = NaiveDate::from_ymd_opt(2018, 1, 26).unwrap().and_hms_micro_opt(18, 30, 9, 453_829).unwrap().and_local_timezone(Utc).unwrap(); + /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, false), + /// "2018-01-26T18:30:09.453+00:00"); + /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, true), + /// "2018-01-26T18:30:09.453Z"); + /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true), + /// "2018-01-26T18:30:09Z"); + /// + /// let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap(); + /// let dt = pst.from_local_datetime(&NaiveDate::from_ymd_opt(2018, 1, 26).unwrap().and_hms_micro_opt(10, 30, 9, 453_829).unwrap()).unwrap(); + /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true), + /// "2018-01-26T10:30:09+08:00"); + /// ``` + #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] + #[must_use] + pub fn to_rfc3339_opts(&self, secform: SecondsFormat, use_z: bool) -> String { + use crate::format::Numeric::*; + use crate::format::Pad::Zero; + use crate::SecondsFormat::*; + + debug_assert!(secform != __NonExhaustive, "Do not use __NonExhaustive!"); + + const PREFIX: &[Item<'static>] = &[ + Item::Numeric(Year, Zero), + Item::Literal("-"), + Item::Numeric(Month, Zero), + Item::Literal("-"), + Item::Numeric(Day, Zero), + Item::Literal("T"), + Item::Numeric(Hour, Zero), + Item::Literal(":"), + Item::Numeric(Minute, Zero), + Item::Literal(":"), + Item::Numeric(Second, Zero), + ]; + + let ssitem = match secform { + Secs => None, + Millis => Some(Item::Fixed(Fixed::Nanosecond3)), + Micros => Some(Item::Fixed(Fixed::Nanosecond6)), + Nanos => Some(Item::Fixed(Fixed::Nanosecond9)), + AutoSi => Some(Item::Fixed(Fixed::Nanosecond)), + __NonExhaustive => unreachable!(), + }; + + let tzitem = Item::Fixed(if use_z { + Fixed::TimezoneOffsetColonZ + } else { + Fixed::TimezoneOffsetColon + }); + + let dt = self.fixed_offset(); + match ssitem { + None => dt.format_with_items(PREFIX.iter().chain([tzitem].iter())).to_string(), + Some(s) => dt.format_with_items(PREFIX.iter().chain([s, tzitem].iter())).to_string(), + } + } + /// The minimum possible `DateTime`. pub const MIN_UTC: DateTime = DateTime { datetime: NaiveDateTime::MIN, offset: Utc }; /// The maximum possible `DateTime`. @@ -701,102 +798,6 @@ impl DateTime where Tz::Offset: fmt::Display, { - /// Returns an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`. - /// - /// # 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. - #[cfg(any(feature = "alloc", feature = "std"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] - #[must_use] - pub fn to_rfc2822(&self) -> String { - let mut result = String::with_capacity(32); - crate::format::write_rfc2822(&mut result, self.naive_local(), self.offset.fix()) - .expect("writing rfc2822 datetime to string should never fail"); - result - } - - /// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`. - #[cfg(any(feature = "alloc", feature = "std"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] - #[must_use] - pub fn to_rfc3339(&self) -> String { - let mut result = String::with_capacity(32); - crate::format::write_rfc3339(&mut result, self.naive_local(), self.offset.fix()) - .expect("writing rfc3339 datetime to string should never fail"); - result - } - - /// Return an RFC 3339 and ISO 8601 date and time string with subseconds - /// formatted as per `SecondsFormat`. - /// - /// If `use_z` is true and the timezone is UTC (offset 0), uses `Z` as - /// per [`Fixed::TimezoneOffsetColonZ`]. If `use_z` is false, uses - /// [`Fixed::TimezoneOffsetColon`] - /// - /// # Examples - /// - /// ```rust - /// # use chrono::{FixedOffset, SecondsFormat, TimeZone, Utc, NaiveDate}; - /// let dt = NaiveDate::from_ymd_opt(2018, 1, 26).unwrap().and_hms_micro_opt(18, 30, 9, 453_829).unwrap().and_local_timezone(Utc).unwrap(); - /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, false), - /// "2018-01-26T18:30:09.453+00:00"); - /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, true), - /// "2018-01-26T18:30:09.453Z"); - /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true), - /// "2018-01-26T18:30:09Z"); - /// - /// let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap(); - /// let dt = pst.from_local_datetime(&NaiveDate::from_ymd_opt(2018, 1, 26).unwrap().and_hms_micro_opt(10, 30, 9, 453_829).unwrap()).unwrap(); - /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true), - /// "2018-01-26T10:30:09+08:00"); - /// ``` - #[cfg(any(feature = "alloc", feature = "std"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] - #[must_use] - pub fn to_rfc3339_opts(&self, secform: SecondsFormat, use_z: bool) -> String { - use crate::format::Numeric::*; - use crate::format::Pad::Zero; - use crate::SecondsFormat::*; - - debug_assert!(secform != __NonExhaustive, "Do not use __NonExhaustive!"); - - const PREFIX: &[Item<'static>] = &[ - Item::Numeric(Year, Zero), - Item::Literal("-"), - Item::Numeric(Month, Zero), - Item::Literal("-"), - Item::Numeric(Day, Zero), - Item::Literal("T"), - Item::Numeric(Hour, Zero), - Item::Literal(":"), - Item::Numeric(Minute, Zero), - Item::Literal(":"), - Item::Numeric(Second, Zero), - ]; - - let ssitem = match secform { - Secs => None, - Millis => Some(Item::Fixed(Fixed::Nanosecond3)), - Micros => Some(Item::Fixed(Fixed::Nanosecond6)), - Nanos => Some(Item::Fixed(Fixed::Nanosecond9)), - AutoSi => Some(Item::Fixed(Fixed::Nanosecond)), - __NonExhaustive => unreachable!(), - }; - - let tzitem = Item::Fixed(if use_z { - Fixed::TimezoneOffsetColonZ - } else { - Fixed::TimezoneOffsetColon - }); - - match ssitem { - None => self.format_with_items(PREFIX.iter().chain([tzitem].iter())).to_string(), - Some(s) => self.format_with_items(PREFIX.iter().chain([s, tzitem].iter())).to_string(), - } - } - /// Formats the combined date and time with the specified formatting items. #[cfg(any(feature = "alloc", feature = "std"))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]