Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make DelayedFormat hold a generic offset #1559

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@
#[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 @@
#[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 @@
&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 @@
&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
118 changes: 76 additions & 42 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 @@
#[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 @@
/// 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,28 +46,17 @@
}

#[cfg(feature = "alloc")]
impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
impl<'a, I, B> DelayedFormat<I>
where
I: Iterator<Item = B> + Clone,
B: Borrow<Item<'a>>,
{
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a note: DelayedFormat::{new, new_with_locale} are in an impl block without a generic offset parameter. Because they don't take an offset as argument it would fail during type inference otherwise.

new_with_offset is in an impl block with the new generic offset parameter.

/// 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> {
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>(
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() }
}

/// Makes a new `DelayedFormat` value out of local date and time and locale.
#[cfg(feature = "unstable-locales")]
#[must_use]
Expand All @@ -79,22 +68,40 @@
) -> DelayedFormat<I> {
DelayedFormat { date, time, off: None, items, locale }
}
}

#[cfg(feature = "alloc")]
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 and UTC offset.
#[must_use]
pub fn new_with_offset(
date: Option<NaiveDate>,
time: Option<NaiveTime>,
offset: &Off,
items: I,
) -> 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, 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 +198,7 @@
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 +272,50 @@
(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 313 in src/format/formatting.rs

View check run for this annotation

Codecov / codecov/patch

src/format/formatting.rs#L312-L313

Added lines #L312 - L313 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 +325,12 @@
}

#[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 +356,7 @@
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 359 in src/format/formatting.rs

View check run for this annotation

Codecov / codecov/patch

src/format/formatting.rs#L359

Added line #L359 was not covered by tests
items,
locale: default_locale(),
}
Expand All @@ -364,13 +376,35 @@
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 379 in src/format/formatting.rs

View check run for this annotation

Codecov / codecov/patch

src/format/formatting.rs#L379

Added line #L379 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 398 in src/format/formatting.rs

View check run for this annotation

Codecov / codecov/patch

src/format/formatting.rs#L396-L398

Added lines #L396 - L398 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 405 in src/format/formatting.rs

View check run for this annotation

Codecov / codecov/patch

src/format/formatting.rs#L403-L405

Added lines #L403 - L405 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