Skip to content

Commit

Permalink
Add DateTime::to_timezone and FromOffset trait
Browse files Browse the repository at this point in the history
  • Loading branch information
pitdicker committed Apr 12, 2024
1 parent f8cecbe commit 2a8af8b
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 5 deletions.
22 changes: 19 additions & 3 deletions src/datetime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::format::{write_rfc2822, write_rfc3339, DelayedFormat, SecondsFormat};
use crate::naive::{Days, IsoWeek, NaiveDate, NaiveDateTime, NaiveTime};
#[cfg(feature = "clock")]
use crate::offset::Local;
use crate::offset::{FixedOffset, LocalResult, Offset, TimeZone, Utc};
use crate::offset::{FixedOffset, FromOffset, LocalResult, Offset, TimeZone, Utc};
#[allow(deprecated)]
use crate::Date;
use crate::{expect, try_opt};
Expand Down Expand Up @@ -405,14 +405,30 @@ impl<Tz: TimeZone> DateTime<Tz> {
}

/// Changes the associated time zone.
/// The returned `DateTime` references the same instant of time from the perspective of the
/// provided time zone.
///
/// The returned `DateTime` references the same instant of time in UTC but with the offset of
/// the target time zone.
#[inline]
#[must_use]
pub fn with_timezone<Tz2: TimeZone>(&self, tz: &Tz2) -> DateTime<Tz2> {
tz.from_utc_datetime(&self.datetime)
}

/// Changes the associated `TimeZone` type.
///
/// The returned `DateTime` references the same instant of time in UTC but with another
/// [`TimeZone`] type. A best effort is made to convert the value of the associated [`Offset`]
/// type to the `Offset` type of the target `TimeZone`.
#[inline]
#[must_use]
pub fn to_timezone<Tz2: TimeZone>(&self) -> DateTime<Tz2>
where
<Tz2 as TimeZone>::Offset: FromOffset<<Tz as TimeZone>::Offset>,
{
let new_offset = <Tz2 as TimeZone>::Offset::from_offset(self.offset());
DateTime { datetime: self.datetime, offset: new_offset }
}

/// Fix the offset from UTC to its current value, dropping the associated timezone information.
/// This it useful for converting a generic `DateTime<Tz: Timezone>` to `DateTime<FixedOffset>`.
#[inline]
Expand Down
17 changes: 17 additions & 0 deletions src/datetime/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,23 @@ fn test_datetime_with_timezone() {
assert_eq!(local_now, local_now2);
}

#[test]
#[cfg(feature = "clock")]
fn test_datetime_to_timezone() {
let dt = Local::now();

let fixed: DateTime<FixedOffset> = dt.to_timezone();
assert_eq!(fixed, dt);
assert_eq!(fixed.offset().fix(), dt.offset().fix());

let utc: DateTime<Utc> = dt.to_timezone();
assert_eq!(utc, dt);

let local: DateTime<Local> = fixed.to_timezone();
assert_eq!(local, fixed);
assert_eq!(local.offset().fix(), fixed.offset().fix());
}

#[test]
#[cfg(feature = "alloc")]
fn test_datetime_rfc2822() {
Expand Down
8 changes: 7 additions & 1 deletion src/offset/fixed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use core::str::FromStr;
#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
use rkyv::{Archive, Deserialize, Serialize};

use super::{MappedLocalTime, Offset, TimeZone};
use super::{FromOffset, MappedLocalTime, Offset, TimeZone};
use crate::format::{scan, ParseError, OUT_OF_RANGE};
use crate::naive::{NaiveDate, NaiveDateTime};

Expand Down Expand Up @@ -152,6 +152,12 @@ impl Offset for FixedOffset {
}
}

impl<Off: Offset> FromOffset<Off> for FixedOffset {
fn from_offset(offset: &Off) -> Self {
offset.fix()
}
}

impl fmt::Debug for FixedOffset {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let offset = self.local_minus_utc;
Expand Down
6 changes: 6 additions & 0 deletions src/offset/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,12 @@ pub trait TimeZone: Sized + Clone {
}
}

/// Trait to create one `Offset` type from another `Offset` type.
pub trait FromOffset<Off> {
/// Converts to this type from the input type.
fn from_offset(offset: &Off) -> Self;
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
8 changes: 7 additions & 1 deletion src/offset/utc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
use rkyv::{Archive, Deserialize, Serialize};

use super::{FixedOffset, MappedLocalTime, Offset, TimeZone};
use super::{FixedOffset, FromOffset, MappedLocalTime, Offset, TimeZone};
use crate::naive::{NaiveDate, NaiveDateTime};
#[cfg(feature = "now")]
#[allow(deprecated)]
Expand Down Expand Up @@ -139,6 +139,12 @@ impl Offset for Utc {
}
}

impl<Off: Offset> FromOffset<Off> for Utc {
fn from_offset(_offset: &Off) -> Self {
Utc
}
}

impl fmt::Debug for Utc {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Z")
Expand Down

0 comments on commit 2a8af8b

Please sign in to comment.