From 30735ee687e12f0973aa993580ef60c43e6f844d Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Sat, 6 Apr 2024 14:24:53 +0200 Subject: [PATCH] Make `DelayedFormat` hold a generic offset --- src/date.rs | 8 +-- src/datetime/mod.rs | 8 +-- src/format/formatting.rs | 118 +++++++++++++++++++++++++-------------- 3 files changed, 84 insertions(+), 50 deletions(-) diff --git a/src/date.rs b/src/date.rs index a66882cecc..3cffe1a5e6 100644 --- a/src/date.rs +++ b/src/date.rs @@ -334,7 +334,7 @@ where #[cfg(feature = "alloc")] #[inline] #[must_use] - pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat + pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat where I: Iterator + Clone, B: Borrow>, @@ -348,7 +348,7 @@ where #[cfg(feature = "alloc")] #[inline] #[must_use] - pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat> { + pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat, Tz::Offset> { self.format_with_items(StrftimeItems::new(fmt)) } @@ -360,7 +360,7 @@ where &self, items: I, locale: Locale, - ) -> DelayedFormat + ) -> DelayedFormat where I: Iterator + Clone, B: Borrow>, @@ -384,7 +384,7 @@ where &self, fmt: &'a str, locale: Locale, - ) -> DelayedFormat> { + ) -> DelayedFormat, Tz::Offset> { self.format_localized_with_items(StrftimeItems::new_with_locale(fmt, locale), locale) } } diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 366bbe6ad7..171689ca19 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -1101,7 +1101,7 @@ where #[cfg(feature = "alloc")] #[inline] #[must_use] - pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat + pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat where I: Iterator + Clone, B: Borrow>, @@ -1125,7 +1125,7 @@ where #[cfg(feature = "alloc")] #[inline] #[must_use] - pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat> { + pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat, Tz::Offset> { self.format_with_items(StrftimeItems::new(fmt)) } @@ -1137,7 +1137,7 @@ where &self, items: I, locale: Locale, - ) -> DelayedFormat + ) -> DelayedFormat where I: Iterator + Clone, B: Borrow>, @@ -1164,7 +1164,7 @@ where &self, fmt: &'a str, locale: Locale, - ) -> DelayedFormat> { + ) -> DelayedFormat, Tz::Offset> { self.format_localized_with_items(StrftimeItems::new_with_locale(fmt, locale), locale) } } diff --git a/src/format/formatting.rs b/src/format/formatting.rs index 967f2d3a68..ae492a52cc 100644 --- a/src/format/formatting.rs +++ b/src/format/formatting.rs @@ -4,7 +4,7 @@ //! Date and time formatting routines. #[cfg(all(feature = "alloc", not(feature = "std"), not(test)))] -use alloc::string::{String, ToString}; +use alloc::string::String; #[cfg(feature = "alloc")] use core::borrow::Borrow; #[cfg(feature = "alloc")] @@ -16,7 +16,7 @@ use crate::offset::Offset; #[cfg(any(feature = "alloc", feature = "serde"))] use crate::{Datelike, FixedOffset, NaiveDateTime, Timelike}; #[cfg(feature = "alloc")] -use crate::{NaiveDate, NaiveTime, Weekday}; +use crate::{NaiveDate, NaiveTime, Utc, Weekday}; #[cfg(feature = "alloc")] use super::locales; @@ -31,13 +31,13 @@ use locales::*; /// This is normally constructed via `format` methods of each date and time type. #[cfg(feature = "alloc")] #[derive(Debug)] -pub struct DelayedFormat { +pub struct DelayedFormat { /// The date view, if any. date: Option, /// The time view, if any. time: Option, - /// The name and local-to-UTC difference for the offset (timezone), if any. - off: Option<(String, FixedOffset)>, + /// The offset from UTC, if any + off: Option, /// An iterator returning formatting items. items: I, /// Locale used for text. @@ -46,28 +46,17 @@ pub struct DelayedFormat { } #[cfg(feature = "alloc")] -impl<'a, I: Iterator + Clone, B: Borrow>> DelayedFormat { +impl<'a, I, B> DelayedFormat +where + I: Iterator + Clone, + B: Borrow>, +{ /// Makes a new `DelayedFormat` value out of local date and time. #[must_use] pub fn new(date: Option, time: Option, items: I) -> DelayedFormat { DelayedFormat { date, time, off: None, items, locale: default_locale() } } - /// Makes a new `DelayedFormat` value out of local date and time and UTC offset. - #[must_use] - pub fn new_with_offset( - date: Option, - time: Option, - offset: &Off, - items: I, - ) -> DelayedFormat - where - Off: Offset + Display, - { - let name_and_diff = (offset.to_string(), offset.fix()); - DelayedFormat { date, time, off: Some(name_and_diff), items, locale: default_locale() } - } - /// Makes a new `DelayedFormat` value out of local date and time and locale. #[cfg(feature = "unstable-locales")] #[must_use] @@ -79,22 +68,40 @@ impl<'a, I: Iterator + Clone, B: Borrow>> DelayedFormat { ) -> DelayedFormat { DelayedFormat { date, time, off: None, items, locale } } +} + +#[cfg(feature = "alloc")] +impl<'a, I, B, Off> DelayedFormat +where + I: Iterator + Clone, + B: Borrow>, + Off: Offset + Display, +{ + /// Makes a new `DelayedFormat` value out of local date and time and UTC offset. + #[must_use] + pub fn new_with_offset( + date: Option, + time: Option, + offset: &Off, + items: I, + ) -> DelayedFormat { + DelayedFormat { date, time, off: Some(offset.clone()), items, locale: default_locale() } + } /// Makes a new `DelayedFormat` value out of local date and time, UTC offset and locale. #[cfg(feature = "unstable-locales")] #[must_use] - pub fn new_with_offset_and_locale( + pub fn new_with_offset_and_locale( date: Option, time: Option, offset: &Off, items: I, locale: Locale, - ) -> DelayedFormat + ) -> DelayedFormat where Off: Offset + Display, { - let name_and_diff = (offset.to_string(), offset.fix()); - DelayedFormat { date, time, off: Some(name_and_diff), items, locale } + DelayedFormat { date, time, off: Some(offset.clone()), items, locale } } fn format(&self, w: &mut impl Write) -> fmt::Result { @@ -191,7 +198,7 @@ impl<'a, I: Iterator + Clone, B: Borrow>> DelayedFormat { write_n(w, 9, (t.nanosecond() % 1_000_000_000) as i64, pad, false) } (Timestamp, Some(d), Some(t)) => { - let offset = self.off.as_ref().map(|(_, o)| i64::from(o.local_minus_utc())); + let offset = self.off.as_ref().map(|o| i64::from(o.fix().local_minus_utc())); let timestamp = d.and_time(t).and_utc().timestamp() - offset.unwrap_or(0); write_n(w, 9, timestamp, pad, false) } @@ -265,50 +272,50 @@ impl<'a, I: Iterator + Clone, B: Borrow>> DelayedFormat { (Internal(InternalFixed { val: Nanosecond9NoDot }), _, Some(t), _) => { write!(w, "{:09}", t.nanosecond() % 1_000_000_000) } - (TimezoneName, _, _, Some((tz_name, _))) => write!(w, "{}", tz_name), - (TimezoneOffset | TimezoneOffsetZ, _, _, Some((_, off))) => { + (TimezoneName, _, _, Some(off)) => write!(w, "{}", off), + (TimezoneOffset | TimezoneOffsetZ, _, _, Some(off)) => { let offset_format = OffsetFormat { precision: OffsetPrecision::Minutes, colons: Colons::Maybe, allow_zulu: *spec == TimezoneOffsetZ, padding: Pad::Zero, }; - offset_format.format(w, *off) + offset_format.format(w, off.fix()) } - (TimezoneOffsetColon | TimezoneOffsetColonZ, _, _, Some((_, off))) => { + (TimezoneOffsetColon | TimezoneOffsetColonZ, _, _, Some(off)) => { let offset_format = OffsetFormat { precision: OffsetPrecision::Minutes, colons: Colons::Colon, allow_zulu: *spec == TimezoneOffsetColonZ, padding: Pad::Zero, }; - offset_format.format(w, *off) + offset_format.format(w, off.fix()) } - (TimezoneOffsetDoubleColon, _, _, Some((_, off))) => { + (TimezoneOffsetDoubleColon, _, _, Some(off)) => { let offset_format = OffsetFormat { precision: OffsetPrecision::Seconds, colons: Colons::Colon, allow_zulu: false, padding: Pad::Zero, }; - offset_format.format(w, *off) + offset_format.format(w, off.fix()) } - (TimezoneOffsetTripleColon, _, _, Some((_, off))) => { + (TimezoneOffsetTripleColon, _, _, Some(off)) => { let offset_format = OffsetFormat { precision: OffsetPrecision::Hours, colons: Colons::None, allow_zulu: false, padding: Pad::Zero, }; - offset_format.format(w, *off) + offset_format.format(w, off.fix()) } - (RFC2822, Some(d), Some(t), Some((_, off))) => { - write_rfc2822(w, crate::NaiveDateTime::new(d, t), *off) + (RFC2822, Some(d), Some(t), Some(off)) => { + write_rfc2822(w, crate::NaiveDateTime::new(d, t), off.fix()) } - (RFC3339, Some(d), Some(t), Some((_, off))) => write_rfc3339( + (RFC3339, Some(d), Some(t), Some(off)) => write_rfc3339( w, crate::NaiveDateTime::new(d, t), - *off, + off.fix(), SecondsFormat::AutoSi, false, ), @@ -318,7 +325,12 @@ impl<'a, I: Iterator + Clone, B: Borrow>> DelayedFormat { } #[cfg(feature = "alloc")] -impl<'a, I: Iterator + Clone, B: Borrow>> Display for DelayedFormat { +impl<'a, I, B, Off> Display for DelayedFormat +where + I: Iterator + Clone, + B: Borrow>, + Off: Offset + Display, +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut result = String::new(); self.format(&mut result)?; @@ -344,7 +356,7 @@ where DelayedFormat { date: date.copied(), time: time.copied(), - off: off.cloned(), + off: off.cloned().map(|(tz_name, offset)| OffsetWrapper { offset, tz_name }), items, locale: default_locale(), } @@ -364,13 +376,35 @@ pub fn format_item( DelayedFormat { date: date.copied(), time: time.copied(), - off: off.cloned(), + off: off.cloned().map(|(tz_name, offset)| OffsetWrapper { offset, tz_name }), items: [item].into_iter(), locale: default_locale(), } .fmt(w) } +/// Only used by the deprecated `format` and `format_item` functions. +#[cfg(feature = "alloc")] +#[derive(Clone, Debug)] +struct OffsetWrapper { + offset: FixedOffset, + tz_name: String, +} + +#[cfg(feature = "alloc")] +impl Offset for OffsetWrapper { + fn fix(&self) -> FixedOffset { + self.offset + } +} + +#[cfg(feature = "alloc")] +impl Display for OffsetWrapper { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.tz_name) + } +} + #[cfg(any(feature = "alloc", feature = "serde"))] impl OffsetFormat { /// Writes an offset from UTC with the format defined by `self`.