diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index ac9ef511d0..9d4e1c3861 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -624,6 +624,34 @@ impl DateTime { NaiveDateTime::from_timestamp_opt(secs, nsecs).as_ref().map(NaiveDateTime::and_utc) } + /// Makes a new [`DateTime`] from the number of non-leap milliseconds + /// since January 1, 1970 0:00:00.000 UTC (aka "UNIX timestamp"). + /// + /// This is guaranteed to round-trip with regard to [`timestamp_millis`](DateTime::timestamp_millis). + /// + /// If you need to create a `DateTime` with a [`TimeZone`] different from [`Utc`], use + /// [`TimeZone::timestamp_millis_opt`] or [`DateTime::with_timezone`]. + /// + /// # Errors + /// + /// Returns `None` on out-of-range number of milliseconds, otherwise returns `Some(DateTime {...})`. + /// + /// # Example + /// + /// ``` + /// use chrono::{DateTime, Utc}; + /// + /// let dt: DateTime = DateTime::::from_timestamp_millis(947638923004).expect("invalid timestamp"); + /// + /// assert_eq!(dt.to_string(), "2000-01-12 01:02:03.004 UTC"); + /// assert_eq!(DateTime::from_timestamp_millis(dt.timestamp_millis()).unwrap(), dt); + /// ``` + #[inline] + #[must_use] + pub fn from_timestamp_millis(millis: i64) -> Option { + NaiveDateTime::from_timestamp_millis(millis).as_ref().map(NaiveDateTime::and_utc) + } + // FIXME: remove when our MSRV is 1.61+ // This method is used by `NaiveDateTime::and_utc` because `DateTime::from_naive_utc_and_offset` // can't be made const yet. diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 3df11e78d4..3e96e227fa 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -1253,6 +1253,18 @@ fn test_datetime_from_local() { assert_eq!(datetime_west, datetime_utc.with_timezone(&timezone_west)); } +#[test] +fn test_datetime_from_timestamp_millis() { + // 2000-01-12T01:02:03:004Z + let naive_dt = + NaiveDate::from_ymd_opt(2000, 1, 12).unwrap().and_hms_milli_opt(1, 2, 3, 4).unwrap(); + let datetime_utc = DateTime::::from_naive_utc_and_offset(naive_dt, Utc); + assert_eq!( + datetime_utc, + DateTime::::from_timestamp_millis(datetime_utc.timestamp_millis()).unwrap() + ); +} + #[test] #[cfg(feature = "clock")] fn test_years_elapsed() {