Skip to content

Commit

Permalink
fix: Negative UNIX timestamps accepted by from_timestamp_millis
Browse files Browse the repository at this point in the history
  • Loading branch information
Pscheidl committed Sep 14, 2022
1 parent 63b26bb commit 559ade1
Showing 1 changed file with 22 additions and 4 deletions.
26 changes: 22 additions & 4 deletions src/naive/datetime/mod.rs
Expand Up @@ -35,6 +35,11 @@ mod tests;
/// touching that call when we are already sure that it WILL overflow...
const MAX_SECS_BITS: usize = 44;

/// Number of nanoseconds in a millisecond
const NANOS_IN_MILLISECOND: u32 = 1_000_000;
/// Number of nanoseconds in a second
const NANOS_IN_SECOND: u32 = 1000 * NANOS_IN_MILLISECOND;

/// The minimum possible `NaiveDateTime`.
#[deprecated(since = "0.4.20", note = "Use NaiveDateTime::MIN instead")]
pub const MIN_DATETIME: NaiveDateTime = NaiveDateTime::MIN;
Expand Down Expand Up @@ -126,7 +131,8 @@ impl NaiveDateTime {
let datetime = NaiveDateTime::from_timestamp_opt(secs, nsecs);
datetime.expect("invalid or out-of-range datetime")
}
/// Creates a new [NaiveDateTime] from milliseconds since the UNIX Epoch.

/// Creates a new [NaiveDateTime] from milliseconds since the UNIX epoch.
///
/// The UNIX epoch starts on midnight, January 1, 1970, UTC.
///
Expand All @@ -140,12 +146,24 @@ impl NaiveDateTime {
/// let naive_datetime = NaiveDateTime::from_timestamp_millis(timestamp_millis);
/// assert!(naive_datetime.is_some());
/// assert_eq!(timestamp_millis, naive_datetime.unwrap().timestamp_millis());
///
/// // Negative timestamps (before the UNIX epoch) are supported as well.
/// let timestamp_millis: i64 = -2208936075; //Mon Jan 01 1900 14:38:45 GMT+0000
/// let naive_datetime = NaiveDateTime::from_timestamp_millis(timestamp_millis);
/// assert!(naive_datetime.is_some());
/// assert_eq!(timestamp_millis, naive_datetime.unwrap().timestamp_millis());
/// ```
#[inline]
pub fn from_timestamp_millis(millis: i64) -> Option<NaiveDateTime> {
let secs = millis / 1000;
let nsecs = (millis % 1000) as u32 * 1_000_000;
NaiveDateTime::from_timestamp_opt(secs, nsecs)
if millis < 0 {
let secs = millis / 1000;
let nsecs = (millis % 1000).abs() as u32 * NANOS_IN_MILLISECOND;
NaiveDateTime::from_timestamp_opt(secs - 1, NANOS_IN_SECOND - nsecs)
} else {
let secs = millis / 1000;
let nsecs = (millis % 1000) as u32 * NANOS_IN_MILLISECOND;
NaiveDateTime::from_timestamp_opt(secs, nsecs)
}
}

/// Makes a new `NaiveDateTime` corresponding to a UTC date and time,
Expand Down

0 comments on commit 559ade1

Please sign in to comment.