Skip to content

Commit

Permalink
Add DateTime::<Utc>::from_timestamp
Browse files Browse the repository at this point in the history
This commit adds the new constructor `from_timestamp` to build a `DateTime<Utc>` from a UNIX timestamp.

Figuring out how to convert a timestamp into a `DateTime<Utc>` was a common issue:
- chronotope#88
- chronotope#200
- chronotope#832

This commit should make `DateTime<Utc>` creation more discoverable and intuitive.

This commit respects the current convention of preferring fallible functions. It avoids however the `_opt` suffix as there is no panicking variant. See [this issue](chronotope#815) for discussion about error handling and panics.

Closes chronotope#832
  • Loading branch information
demurgos committed Sep 10, 2023
1 parent 2960f2c commit 449d907
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 7 deletions.
43 changes: 43 additions & 0 deletions src/datetime/mod.rs
Expand Up @@ -209,6 +209,18 @@ impl<Tz: TimeZone> DateTime<Tz> {

/// Returns the number of non-leap seconds since January 1, 1970 0:00:00 UTC
/// (aka "UNIX timestamp").
///
/// The reverse operation of creating a [`DateTime`] from a timestamp can be performed
/// using [`from_timestamp`](DateTime::from_timestamp) or [`TimeZone::timestamp_opt`].
///
/// ```
/// use chrono::{DateTime, TimeZone, Utc};
///
/// let dt: DateTime<Utc> = Utc.with_ymd_and_hms(2015, 5, 15, 0, 0, 0).unwrap();
/// assert_eq!(dt.timestamp(), 1431648000);
///
/// assert_eq!(DateTime::from_timestamp(dt.timestamp(), dt.timestamp_subsec_nanos()).unwrap(), dt);
/// ```
#[inline]
#[must_use]
pub fn timestamp(&self) -> i64 {
Expand Down Expand Up @@ -559,6 +571,37 @@ impl<Tz: TimeZone> DateTime<Tz> {
pub const MAX_UTC: DateTime<Utc> = DateTime { datetime: NaiveDateTime::MAX, offset: Utc };
}

impl DateTime<Utc> {
/// Makes a new [`DateTime<Utc>`] from the number of non-leap seconds
/// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp")
/// and the number of nanoseconds since the last whole non-leap second.
///
/// This is guaranteed to round-trip with regard to [`timestamp`](DateTime::timestamp) and
/// [`timestamp_subsec_nanos`](DateTime::timestamp_subsec_nanos).
///
/// Returns `None` on out-of-range number of seconds and/or
/// invalid nanosecond, otherwise returns `Some(DateTime {...})`.
///
/// If you need to create a `DateTime` with a [`TimeZone`] different from [`Utc`], use
/// [`TimeZone::timestamp_opt`] or [`DateTime::with_timezone`].
///
/// # Example
///
/// ```
/// use chrono::{DateTime, Utc};
///
/// let dt: DateTime<Utc> = DateTime::<Utc>::from_timestamp(1431648000, 0).expect("invalid timestamp");
///
/// assert_eq!(dt.to_string(), "2015-05-15 00:00:00 UTC");
/// assert_eq!(DateTime::from_timestamp(dt.timestamp(), dt.timestamp_subsec_nanos()).unwrap(), dt);
/// ```
#[inline]
#[must_use]
pub fn from_timestamp(secs: i64, nsecs: u32) -> Option<Self> {
NaiveDateTime::from_timestamp_opt(secs, nsecs).as_ref().map(NaiveDateTime::and_utc)
}
}

impl Default for DateTime<Utc> {
fn default() -> Self {
Utc.from_utc_datetime(&NaiveDateTime::default())
Expand Down
14 changes: 7 additions & 7 deletions src/lib.rs
Expand Up @@ -309,22 +309,22 @@
//!
//! ### Conversion from and to EPOCH timestamps
//!
//! Use [`Utc.timestamp(seconds, nanoseconds)`](./offset/trait.TimeZone.html#method.timestamp)
//! to construct a [`DateTime<Utc>`](./struct.DateTime.html) from a UNIX timestamp
//! Use [`DateTime::from_timestamp(seconds, nanoseconds)`](DateTime::from_timestamp)
//! to construct a [`DateTime<Utc>`] from a UNIX timestamp
//! (seconds, nanoseconds that passed since January 1st 1970).
//!
//! Use [`DateTime.timestamp`](./struct.DateTime.html#method.timestamp) to get the timestamp (in seconds)
//! from a [`DateTime`](./struct.DateTime.html). Additionally, you can use
//! [`DateTime.timestamp_subsec_nanos`](./struct.DateTime.html#method.timestamp_subsec_nanos)
//! Use [`DateTime.timestamp`](DateTime::timestamp) to get the timestamp (in seconds)
//! from a [`DateTime`]. Additionally, you can use
//! [`DateTime.timestamp_subsec_nanos`](DateTime::timestamp_subsec_nanos)
//! to get the number of additional number of nanoseconds.
//!
#![cfg_attr(not(feature = "std"), doc = "```ignore")]
#![cfg_attr(feature = "std", doc = "```rust")]
//! // We need the trait in scope to use Utc::timestamp().
//! use chrono::{DateTime, TimeZone, Utc};
//! use chrono::{DateTime, Utc};
//!
//! // Construct a datetime from epoch:
//! let dt = Utc.timestamp_opt(1_500_000_000, 0).unwrap();
//! let dt: DateTime<Utc> = DateTime::from_timestamp(1_500_000_000, 0).unwrap();
//! assert_eq!(dt.to_rfc2822(), "Fri, 14 Jul 2017 02:40:00 +0000");
//!
//! // Get epoch value from a datetime:
Expand Down

0 comments on commit 449d907

Please sign in to comment.