diff --git a/bench/benches/chrono.rs b/bench/benches/chrono.rs index 925c2939f1..91c4e45520 100644 --- a/bench/benches/chrono.rs +++ b/bench/benches/chrono.rs @@ -185,6 +185,25 @@ fn bench_format_with_items(c: &mut Criterion) { }); } +fn benches_delayed_format(c: &mut Criterion) { + let mut group = c.benchmark_group("delayed_format"); + let dt = Local::now(); + group.bench_function(BenchmarkId::new("with_display", dt), |b| { + b.iter_batched( + || dt.format("%Y-%m-%dT%H:%M:%S%.f%:z"), + |df| black_box(df).to_string(), + criterion::BatchSize::SmallInput, + ) + }); + group.bench_function(BenchmarkId::new("with_string_buffer", dt), |b| { + b.iter_batched( + || (dt.format("%Y-%m-%dT%H:%M:%S%.f%:z"), String::with_capacity(256)), + |(df, string)| black_box(df).write_to(&mut black_box(string)), + criterion::BatchSize::SmallInput, + ) + }); +} + fn bench_format_manual(c: &mut Criterion) { let dt = Local::now(); c.bench_function("bench_format_manual", |b| { @@ -237,6 +256,7 @@ criterion_group!( bench_format, bench_format_with_items, bench_format_manual, + benches_delayed_format, bench_naivedate_add_signed, bench_datetime_with, ); diff --git a/src/format/formatting.rs b/src/format/formatting.rs index 967f2d3a68..c5b9ad80b7 100644 --- a/src/format/formatting.rs +++ b/src/format/formatting.rs @@ -97,7 +97,38 @@ impl<'a, I: Iterator + Clone, B: Borrow>> DelayedFormat { DelayedFormat { date, time, off: Some(name_and_diff), items, locale } } - fn format(&self, w: &mut impl Write) -> fmt::Result { + /// Formats `DelayedFormat` into a `core::fmt::Write` instance. + /// # Errors + /// This function returns a `core::fmt::Error` if formatting into the `core::fmt::Write` instance fails. + /// + /// # Example + /// ### Writing to a String + /// ``` + /// let dt = chrono::DateTime::from_timestamp(1643723400, 123456789).unwrap(); + /// let df = dt.format("%Y-%m-%d %H:%M:%S%.9f"); + /// let mut buffer = String::new(); + /// let _ = df.write_to(&mut buffer); + /// ``` + /// ### Writing to a Vec + /// ``` + /// // wrapper to allow reuse of the existing string based + /// // writers + /// struct IoWriter { + /// writer: W, + /// } + /// impl std::fmt::Write for IoWriter { + /// #[inline] + /// fn write_str(&mut self, s: &str) -> std::fmt::Result { + /// self.writer.write_all(s.as_bytes()).map_err(|_| std::fmt::Error) + /// } + /// } + /// let dt = chrono::DateTime::from_timestamp(1643723400, 123456789).unwrap(); + /// let df = dt.format("%Y-%m-%d %H:%M:%S%.9f"); + /// let w: Vec = Vec::new(); + /// let mut writer = IoWriter { writer: w }; + /// let _ = df.write_to(&mut writer); + /// ``` + pub fn write_to(&self, w: &mut impl Write) -> fmt::Result { for item in self.items.clone() { match *item.borrow() { Item::Literal(s) | Item::Space(s) => w.write_str(s), @@ -321,7 +352,7 @@ impl<'a, I: Iterator + Clone, B: Borrow>> DelayedFormat { impl<'a, I: Iterator + Clone, B: Borrow>> Display for DelayedFormat { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut result = String::new(); - self.format(&mut result)?; + self.write_to(&mut result)?; f.pad(&result) } } @@ -329,7 +360,7 @@ impl<'a, I: Iterator + Clone, B: Borrow>> Display for Delayed /// Tries to format given arguments with given formatting items. /// Internally used by `DelayedFormat`. #[cfg(feature = "alloc")] -#[deprecated(since = "0.4.32", note = "Use DelayedFormat::fmt instead")] +#[deprecated(since = "0.4.32", note = "Use DelayedFormat::fmt or DelayedFormat::write_to instead instead")] pub fn format<'a, I, B>( w: &mut fmt::Formatter, date: Option<&NaiveDate>, @@ -353,7 +384,7 @@ where /// Formats single formatting item #[cfg(feature = "alloc")] -#[deprecated(since = "0.4.32", note = "Use DelayedFormat::fmt instead")] +#[deprecated(since = "0.4.32", note = "Use DelayedFormat::fmt or DelayedFormat::write_to instead")] pub fn format_item( w: &mut fmt::Formatter, date: Option<&NaiveDate>, @@ -611,6 +642,34 @@ mod tests { #[cfg(feature = "alloc")] use crate::{NaiveDate, NaiveTime, TimeZone, Timelike, Utc}; + #[cfg(feature = "alloc")] + #[test] + fn test_delayed_write_to() { + let dt = crate::DateTime::from_timestamp(1643723400, 123456789).unwrap(); + let df = dt.format("%Y-%m-%d %H:%M:%S%.9f"); + + let mut dt_str = String::new(); + + df.write_to(&mut dt_str).unwrap(); + assert_eq!(dt_str, "2022-02-01 13:50:00.123456789"); + } + + #[cfg(all(feature = "std", feature = "unstable-locales", feature = "alloc"))] + #[test] + fn test_with_locale_delayed_write_to() { + use crate::format::locales::Locale; + use crate::DateTime; + + let dt = DateTime::from_timestamp(1643723400, 123456789).unwrap(); + let df = dt.format_localized("%A, %B %d, %Y", Locale::ja_JP); + + let mut dt_str = String::new(); + + df.write_to(&mut dt_str).unwrap(); + + assert_eq!(dt_str, "火曜日, 2月 01, 2022"); + } + #[test] #[cfg(feature = "alloc")] fn test_date_format() {