From c7dc848141bbf1525e61d433d62abbe32650d368 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Fri, 7 Jul 2023 07:11:12 +0200 Subject: [PATCH 1/3] Add `DateTime::from_naive_utc_and_offset` --- src/datetime/mod.rs | 29 ++++++++++++++++++++++------- src/offset/mod.rs | 4 ++-- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 3e9e8eb096..3911aca6b4 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -94,19 +94,34 @@ pub const MIN_DATETIME: DateTime = DateTime::::MIN_UTC; pub const MAX_DATETIME: DateTime = DateTime::::MAX_UTC; impl DateTime { - /// Makes a new `DateTime` with given *UTC* datetime and offset. - /// The local datetime should be constructed via the `TimeZone` trait. + /// Makes a new `DateTime` from its components: a `NaiveDateTime` in UTC and an `Offset`. /// - /// # Example + /// This is a low-level method, intended for use cases such as deserializing a `DateTime` or + /// passing it through FFI. /// - /// ``` - /// use chrono::{DateTime, TimeZone, NaiveDateTime, Utc}; + /// For regular use you will probably want to use a method such as + /// [`TimeZone::from_local_datetime`] or [`NaiveDateTime::and_local_timezone`] instead. + /// + /// # Example /// - /// let dt = DateTime::::from_utc(NaiveDateTime::from_timestamp_opt(61, 0).unwrap(), Utc); - /// assert_eq!(Utc.timestamp_opt(61, 0).unwrap(), dt); + #[cfg_attr(not(feature = "clock"), doc = "```ignore")] + #[cfg_attr(feature = "clock", doc = "```rust")] + /// use chrono::{Local, DateTime}; + /// + /// let dt = Local::now(); + /// // Get components + /// let naive_utc = dt.naive_utc(); + /// let offset = dt.offset().clone(); + /// // Serialize, pass through FFI... and recreate the `DateTime`: + /// let dt_new = DateTime::::from_naive_utc_and_offset(naive_utc, offset); + /// assert_eq!(dt, dt_new); /// ``` #[inline] #[must_use] + pub fn from_naive_utc_and_offset(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime { + DateTime { datetime, offset } + } + pub fn from_utc(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime { DateTime { datetime, offset } } diff --git a/src/offset/mod.rs b/src/offset/mod.rs index ee1fe7e233..ea53915309 100644 --- a/src/offset/mod.rs +++ b/src/offset/mod.rs @@ -474,7 +474,7 @@ pub trait TimeZone: Sized + Clone { #[allow(clippy::wrong_self_convention)] fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult> { self.offset_from_local_datetime(local) - .map(|offset| DateTime::from_utc(*local - offset.fix(), offset)) + .map(|offset| DateTime::from_naive_utc_and_offset(*local - offset.fix(), offset)) } /// Creates the offset for given UTC `NaiveDate`. This cannot fail. @@ -496,7 +496,7 @@ pub trait TimeZone: Sized + Clone { /// The UTC is continuous and thus this cannot fail (but can give the duplicate local time). #[allow(clippy::wrong_self_convention)] fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime { - DateTime::from_utc(*utc, self.offset_from_utc_datetime(utc)) + DateTime::from_naive_utc_and_offset(*utc, self.offset_from_utc_datetime(utc)) } } From e970169a8f5ca8ae63b7413eb27a05c1cf2bdac3 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Fri, 7 Jul 2023 08:53:48 +0200 Subject: [PATCH 2/3] Deprecate `DateTime::{from_local, from_utc}` --- src/datetime/mod.rs | 36 ++++++++++++------------------------ src/datetime/tests.rs | 7 ++++--- src/offset/utc.rs | 6 +++--- 3 files changed, 19 insertions(+), 30 deletions(-) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 3911aca6b4..8cf3814a82 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -122,12 +122,18 @@ impl DateTime { DateTime { datetime, offset } } + /// Makes a new `DateTime` from its components: a `NaiveDateTime` in UTC and an `Offset`. + #[inline] + #[must_use] + #[deprecated( + since = "0.4.27", + note = "Use TimeZone::from_utc_datetime() or DateTime::from_naive_utc_and_offset instead" + )] pub fn from_utc(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime { DateTime { datetime, offset } } - /// Makes a new `DateTime` with given **local** datetime and offset that - /// presents local timezone. + /// Makes a new `DateTime` from a `NaiveDateTime` in *local* time and an `Offset`. /// /// # Panics /// @@ -135,30 +141,12 @@ impl DateTime { /// /// This can happen if `datetime` is near the end of the representable range of `NaiveDateTime`, /// and the offset from UTC pushes it beyond that. - /// - /// # Example - /// - /// ``` - /// use chrono::DateTime; - /// use chrono::naive::NaiveDate; - /// use chrono::offset::{Utc, FixedOffset}; - /// - /// let naivedatetime_utc = NaiveDate::from_ymd_opt(2000, 1, 12).unwrap().and_hms_opt(2, 0, 0).unwrap(); - /// let datetime_utc = DateTime::::from_utc(naivedatetime_utc, Utc); - /// - /// let timezone_east = FixedOffset::east_opt(8 * 60 * 60).unwrap(); - /// let naivedatetime_east = NaiveDate::from_ymd_opt(2000, 1, 12).unwrap().and_hms_opt(10, 0, 0).unwrap(); - /// let datetime_east = DateTime::::from_local(naivedatetime_east, timezone_east); - /// - /// let timezone_west = FixedOffset::west_opt(7 * 60 * 60).unwrap(); - /// let naivedatetime_west = NaiveDate::from_ymd_opt(2000, 1, 11).unwrap().and_hms_opt(19, 0, 0).unwrap(); - /// let datetime_west = DateTime::::from_local(naivedatetime_west, timezone_west); - - /// assert_eq!(datetime_east, datetime_utc.with_timezone(&timezone_east)); - /// assert_eq!(datetime_west, datetime_utc.with_timezone(&timezone_west)); - /// ``` #[inline] #[must_use] + #[deprecated( + since = "0.4.27", + note = "Use TimeZone::from_local_datetime() or NaiveDateTime::and_local_timezone instead" + )] pub fn from_local(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime { let datetime_utc = datetime - offset.fix(); diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 9c73232885..b16f6ff22a 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -674,7 +674,7 @@ fn test_rfc3339_opts() { assert_eq!(dt.to_rfc3339_opts(Nanos, false), "2018-01-11T10:05:13.084660000+08:00"); assert_eq!(dt.to_rfc3339_opts(AutoSi, false), "2018-01-11T10:05:13.084660+08:00"); - let ut = DateTime::::from_utc(dt.naive_utc(), Utc); + let ut = dt.naive_utc().and_utc(); assert_eq!(ut.to_rfc3339_opts(Secs, false), "2018-01-11T02:05:13+00:00"); assert_eq!(ut.to_rfc3339_opts(Secs, true), "2018-01-11T02:05:13Z"); assert_eq!(ut.to_rfc3339_opts(Millis, false), "2018-01-11T02:05:13.084+00:00"); @@ -1276,6 +1276,7 @@ fn test_datetime_format_alignment() { } #[test] +#[allow(deprecated)] fn test_datetime_from_local() { // 2000-01-12T02:00:00Z let naivedatetime_utc = @@ -1321,7 +1322,7 @@ fn test_years_elapsed() { #[test] fn test_datetime_add_assign() { let naivedatetime = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap(); - let datetime = DateTime::::from_utc(naivedatetime, Utc); + let datetime = naivedatetime.and_utc(); let mut datetime_add = datetime; datetime_add += Duration::seconds(60); @@ -1358,7 +1359,7 @@ fn test_datetime_add_assign_local() { #[test] fn test_datetime_sub_assign() { let naivedatetime = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap().and_hms_opt(12, 0, 0).unwrap(); - let datetime = DateTime::::from_utc(naivedatetime, Utc); + let datetime = naivedatetime.and_utc(); let mut datetime_sub = datetime; datetime_sub -= Duration::minutes(90); diff --git a/src/offset/utc.rs b/src/offset/utc.rs index dbcb8eecbb..f531bcae67 100644 --- a/src/offset/utc.rs +++ b/src/offset/utc.rs @@ -33,9 +33,9 @@ use crate::{Date, DateTime}; /// # Example /// /// ``` -/// use chrono::{DateTime, TimeZone, NaiveDateTime, Utc}; +/// use chrono::{TimeZone, NaiveDateTime, Utc}; /// -/// let dt = DateTime::::from_utc(NaiveDateTime::from_timestamp_opt(61, 0).unwrap(), Utc); +/// let dt = Utc.from_utc_datetime(&NaiveDateTime::from_timestamp_opt(61, 0).unwrap()); /// /// assert_eq!(Utc.timestamp_opt(61, 0).unwrap(), dt); /// assert_eq!(Utc.with_ymd_and_hms(1970, 1, 1, 0, 1, 1).unwrap(), dt); @@ -71,7 +71,7 @@ impl Utc { SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch"); let naive = NaiveDateTime::from_timestamp_opt(now.as_secs() as i64, now.subsec_nanos()).unwrap(); - DateTime::from_utc(naive, Utc) + Utc.from_utc_datetime(&naive) } /// Returns a `DateTime` which corresponds to the current date and time. From ac1b5d3ece42c84c9e6c64a53e3b3e26d2bfd880 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Mon, 24 Jul 2023 13:05:38 +0200 Subject: [PATCH 3/3] Add test for deprecated methods --- src/datetime/tests.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index b16f6ff22a..e82484635e 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -1481,3 +1481,16 @@ fn test_auto_conversion() { let utc_dt2: DateTime = cdt_dt.into(); assert_eq!(utc_dt, utc_dt2); } + +#[test] +#[cfg(feature = "clock")] +#[allow(deprecated)] +fn test_test_deprecated_from_offset() { + let now = Local::now(); + let naive = now.naive_local(); + let utc = now.naive_utc(); + let offset: FixedOffset = *now.offset(); + + assert_eq!(DateTime::::from_local(naive, offset), now); + assert_eq!(DateTime::::from_utc(utc, offset), now); +}