Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 2a8af8b

Browse files
committedApr 12, 2024·
Add DateTime::to_timezone and FromOffset trait
1 parent f8cecbe commit 2a8af8b

File tree

5 files changed

+56
-5
lines changed

5 files changed

+56
-5
lines changed
 

‎src/datetime/mod.rs

+19-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use crate::format::{write_rfc2822, write_rfc3339, DelayedFormat, SecondsFormat};
2525
use crate::naive::{Days, IsoWeek, NaiveDate, NaiveDateTime, NaiveTime};
2626
#[cfg(feature = "clock")]
2727
use crate::offset::Local;
28-
use crate::offset::{FixedOffset, LocalResult, Offset, TimeZone, Utc};
28+
use crate::offset::{FixedOffset, FromOffset, LocalResult, Offset, TimeZone, Utc};
2929
#[allow(deprecated)]
3030
use crate::Date;
3131
use crate::{expect, try_opt};
@@ -405,14 +405,30 @@ impl<Tz: TimeZone> DateTime<Tz> {
405405
}
406406

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

417+
/// Changes the associated `TimeZone` type.
418+
///
419+
/// The returned `DateTime` references the same instant of time in UTC but with another
420+
/// [`TimeZone`] type. A best effort is made to convert the value of the associated [`Offset`]
421+
/// type to the `Offset` type of the target `TimeZone`.
422+
#[inline]
423+
#[must_use]
424+
pub fn to_timezone<Tz2: TimeZone>(&self) -> DateTime<Tz2>
425+
where
426+
<Tz2 as TimeZone>::Offset: FromOffset<<Tz as TimeZone>::Offset>,
427+
{
428+
let new_offset = <Tz2 as TimeZone>::Offset::from_offset(self.offset());
429+
DateTime { datetime: self.datetime, offset: new_offset }
430+
}
431+
416432
/// Fix the offset from UTC to its current value, dropping the associated timezone information.
417433
/// This it useful for converting a generic `DateTime<Tz: Timezone>` to `DateTime<FixedOffset>`.
418434
#[inline]

‎src/datetime/tests.rs

+17
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,23 @@ fn test_datetime_with_timezone() {
638638
assert_eq!(local_now, local_now2);
639639
}
640640

641+
#[test]
642+
#[cfg(feature = "clock")]
643+
fn test_datetime_to_timezone() {
644+
let dt = Local::now();
645+
646+
let fixed: DateTime<FixedOffset> = dt.to_timezone();
647+
assert_eq!(fixed, dt);
648+
assert_eq!(fixed.offset().fix(), dt.offset().fix());
649+
650+
let utc: DateTime<Utc> = dt.to_timezone();
651+
assert_eq!(utc, dt);
652+
653+
let local: DateTime<Local> = fixed.to_timezone();
654+
assert_eq!(local, fixed);
655+
assert_eq!(local.offset().fix(), fixed.offset().fix());
656+
}
657+
641658
#[test]
642659
#[cfg(feature = "alloc")]
643660
fn test_datetime_rfc2822() {

‎src/offset/fixed.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use core::str::FromStr;
99
#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
1010
use rkyv::{Archive, Deserialize, Serialize};
1111

12-
use super::{MappedLocalTime, Offset, TimeZone};
12+
use super::{FromOffset, MappedLocalTime, Offset, TimeZone};
1313
use crate::format::{scan, ParseError, OUT_OF_RANGE};
1414
use crate::naive::{NaiveDate, NaiveDateTime};
1515

@@ -152,6 +152,12 @@ impl Offset for FixedOffset {
152152
}
153153
}
154154

155+
impl<Off: Offset> FromOffset<Off> for FixedOffset {
156+
fn from_offset(offset: &Off) -> Self {
157+
offset.fix()
158+
}
159+
}
160+
155161
impl fmt::Debug for FixedOffset {
156162
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
157163
let offset = self.local_minus_utc;

‎src/offset/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,12 @@ pub trait TimeZone: Sized + Clone {
595595
}
596596
}
597597

598+
/// Trait to create one `Offset` type from another `Offset` type.
599+
pub trait FromOffset<Off> {
600+
/// Converts to this type from the input type.
601+
fn from_offset(offset: &Off) -> Self;
602+
}
603+
598604
#[cfg(test)]
599605
mod tests {
600606
use super::*;

‎src/offset/utc.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
1717
#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
1818
use rkyv::{Archive, Deserialize, Serialize};
1919

20-
use super::{FixedOffset, MappedLocalTime, Offset, TimeZone};
20+
use super::{FixedOffset, FromOffset, MappedLocalTime, Offset, TimeZone};
2121
use crate::naive::{NaiveDate, NaiveDateTime};
2222
#[cfg(feature = "now")]
2323
#[allow(deprecated)]
@@ -139,6 +139,12 @@ impl Offset for Utc {
139139
}
140140
}
141141

142+
impl<Off: Offset> FromOffset<Off> for Utc {
143+
fn from_offset(_offset: &Off) -> Self {
144+
Utc
145+
}
146+
}
147+
142148
impl fmt::Debug for Utc {
143149
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
144150
write!(f, "Z")

0 commit comments

Comments
 (0)
Please sign in to comment.