Skip to content

Commit

Permalink
Make DelayedFormat hold a generic offset
Browse files Browse the repository at this point in the history
  • Loading branch information
pitdicker committed Apr 6, 2024
1 parent 0cfc405 commit cc6580c
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 44 deletions.
8 changes: 4 additions & 4 deletions src/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ where
#[cfg(feature = "alloc")]
#[inline]
#[must_use]
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I, Tz::Offset>

Check warning on line 337 in src/date.rs

View check run for this annotation

Codecov / codecov/patch

src/date.rs#L337

Added line #L337 was not covered by tests
where
I: Iterator<Item = B> + Clone,
B: Borrow<Item<'a>>,
Expand All @@ -348,7 +348,7 @@ where
#[cfg(feature = "alloc")]
#[inline]
#[must_use]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>, Tz::Offset> {

Check warning on line 351 in src/date.rs

View check run for this annotation

Codecov / codecov/patch

src/date.rs#L351

Added line #L351 was not covered by tests
self.format_with_items(StrftimeItems::new(fmt))
}

Expand All @@ -360,7 +360,7 @@ where
&self,
items: I,
locale: Locale,
) -> DelayedFormat<I>
) -> DelayedFormat<I, Tz::Offset>

Check warning on line 363 in src/date.rs

View check run for this annotation

Codecov / codecov/patch

src/date.rs#L363

Added line #L363 was not covered by tests
where
I: Iterator<Item = B> + Clone,
B: Borrow<Item<'a>>,
Expand All @@ -384,7 +384,7 @@ where
&self,
fmt: &'a str,
locale: Locale,
) -> DelayedFormat<StrftimeItems<'a>> {
) -> DelayedFormat<StrftimeItems<'a>, Tz::Offset> {

Check warning on line 387 in src/date.rs

View check run for this annotation

Codecov / codecov/patch

src/date.rs#L387

Added line #L387 was not covered by tests
self.format_localized_with_items(StrftimeItems::new_with_locale(fmt, locale), locale)
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/datetime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1101,7 +1101,7 @@ where
#[cfg(feature = "alloc")]
#[inline]
#[must_use]
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I, Tz::Offset>
where
I: Iterator<Item = B> + Clone,
B: Borrow<Item<'a>>,
Expand All @@ -1125,7 +1125,7 @@ where
#[cfg(feature = "alloc")]
#[inline]
#[must_use]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>, Tz::Offset> {
self.format_with_items(StrftimeItems::new(fmt))
}

Expand All @@ -1137,7 +1137,7 @@ where
&self,
items: I,
locale: Locale,
) -> DelayedFormat<I>
) -> DelayedFormat<I, Tz::Offset>
where
I: Iterator<Item = B> + Clone,
B: Borrow<Item<'a>>,
Expand All @@ -1164,7 +1164,7 @@ where
&self,
fmt: &'a str,
locale: Locale,
) -> DelayedFormat<StrftimeItems<'a>> {
) -> DelayedFormat<StrftimeItems<'a>, Tz::Offset> {
self.format_localized_with_items(StrftimeItems::new_with_locale(fmt, locale), locale)
}
}
Expand Down
103 changes: 67 additions & 36 deletions src/format/formatting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand All @@ -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;
Expand All @@ -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<I> {
pub struct DelayedFormat<I, Off = Utc> {
/// The date view, if any.
date: Option<NaiveDate>,
/// The time view, if any.
time: Option<NaiveTime>,
/// 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<Off>,
/// An iterator returning formatting items.
items: I,
/// Locale used for text.
Expand All @@ -46,26 +46,31 @@ pub struct DelayedFormat<I> {
}

#[cfg(feature = "alloc")]
impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
impl<'a, I, B, Off> DelayedFormat<I, Off>
where
I: Iterator<Item = B> + Clone,
B: Borrow<Item<'a>>,
Off: Offset + Display,
{
/// Makes a new `DelayedFormat` value out of local date and time.
#[must_use]
pub fn new(date: Option<NaiveDate>, time: Option<NaiveTime>, items: I) -> DelayedFormat<I> {
pub fn new(
date: Option<NaiveDate>,
time: Option<NaiveTime>,
items: I,
) -> DelayedFormat<I, Off> {
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<Off>(
pub fn new_with_offset(
date: Option<NaiveDate>,
time: Option<NaiveTime>,
offset: &Off,
items: I,
) -> DelayedFormat<I>
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() }
) -> DelayedFormat<I, Off> {
DelayedFormat { date, time, off: Some(offset.clone()), items, locale: default_locale() }
}

/// Makes a new `DelayedFormat` value out of local date and time and locale.
Expand All @@ -76,25 +81,24 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
time: Option<NaiveTime>,
items: I,
locale: Locale,
) -> DelayedFormat<I> {
) -> DelayedFormat<I, Off> {
DelayedFormat { date, time, off: None, items, 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<Off>(
pub fn new_with_offset_and_locale(
date: Option<NaiveDate>,
time: Option<NaiveTime>,
offset: &Off,
items: I,
locale: Locale,
) -> DelayedFormat<I>
) -> DelayedFormat<I, Off>
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 {
Expand Down Expand Up @@ -191,7 +195,7 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
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)
}
Expand Down Expand Up @@ -265,50 +269,50 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
(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())

Check warning on line 310 in src/format/formatting.rs

View check run for this annotation

Codecov / codecov/patch

src/format/formatting.rs#L309-L310

Added lines #L309 - L310 were not covered by tests
}
(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,
),
Expand All @@ -318,7 +322,12 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
}

#[cfg(feature = "alloc")]
impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> Display for DelayedFormat<I> {
impl<'a, I, B, Off> Display for DelayedFormat<I, Off>
where
I: Iterator<Item = B> + Clone,
B: Borrow<Item<'a>>,
Off: Offset + Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut result = String::new();
self.format(&mut result)?;
Expand All @@ -344,7 +353,7 @@ where
DelayedFormat {
date: date.copied(),
time: time.copied(),
off: off.cloned(),
off: off.cloned().map(|(tz_name, offset)| OffsetWrapper { offset, tz_name }),

Check warning on line 356 in src/format/formatting.rs

View check run for this annotation

Codecov / codecov/patch

src/format/formatting.rs#L356

Added line #L356 was not covered by tests
items,
locale: default_locale(),
}
Expand All @@ -364,13 +373,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 }),

Check warning on line 376 in src/format/formatting.rs

View check run for this annotation

Codecov / codecov/patch

src/format/formatting.rs#L376

Added line #L376 was not covered by tests
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
}

Check warning on line 395 in src/format/formatting.rs

View check run for this annotation

Codecov / codecov/patch

src/format/formatting.rs#L393-L395

Added lines #L393 - L395 were not covered by tests
}

#[cfg(feature = "alloc")]
impl Display for OffsetWrapper {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.tz_name)
}

Check warning on line 402 in src/format/formatting.rs

View check run for this annotation

Codecov / codecov/patch

src/format/formatting.rs#L400-L402

Added lines #L400 - L402 were not covered by tests
}

#[cfg(any(feature = "alloc", feature = "serde"))]
impl OffsetFormat {
/// Writes an offset from UTC with the format defined by `self`.
Expand Down

0 comments on commit cc6580c

Please sign in to comment.