From 4c42ee5cebf9c26ea902e7ca3f0f21156261a76d Mon Sep 17 00:00:00 2001 From: Steven Tang Date: Tue, 21 Jan 2025 14:21:02 -0500 Subject: [PATCH] Expose `write_to` for `DelayedFormat` Request for #1649 - renamed format to write-to and made it public. - added unittests - added benchmarks to compare and show `Display` is slower than `write_to` in that specific use case. --- bench/benches/chrono.rs | 20 +++++++++++++++++ src/format/formatting.rs | 48 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 4 deletions(-) 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..a0e156c130 100644 --- a/src/format/formatting.rs +++ b/src/format/formatting.rs @@ -97,7 +97,19 @@ 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); + /// ``` + 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 +333,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 +341,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")] pub fn format<'a, I, B>( w: &mut fmt::Formatter, date: Option<&NaiveDate>, @@ -353,7 +365,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 +623,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() {