Skip to content

Commit

Permalink
Simplify from_timestamp_millis, from_timestamp_micros
Browse files Browse the repository at this point in the history
  • Loading branch information
pitdicker committed May 1, 2023
1 parent 1e1c0f9 commit bddfbf8
Showing 1 changed file with 6 additions and 65 deletions.
71 changes: 6 additions & 65 deletions src/naive/datetime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

#[cfg(any(feature = "alloc", feature = "std", test))]
use core::borrow::Borrow;
use core::convert::TryFrom;
use core::fmt::Write;
use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::{fmt, str};
Expand All @@ -22,7 +21,6 @@ use crate::format::{Fixed, Item, Numeric, Pad};
use crate::naive::{Days, IsoWeek, NaiveDate, NaiveTime};
use crate::oldtime::Duration as OldDuration;
use crate::{DateTime, Datelike, LocalResult, Months, TimeZone, Timelike, Weekday};
use core::cmp::Ordering;

#[cfg(feature = "rustc-serialize")]
pub(super) mod rustc_serialize;
Expand All @@ -42,11 +40,6 @@ 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 @@ -87,32 +80,6 @@ pub struct NaiveDateTime {
time: NaiveTime,
}

/// The unit of a timestamp expressed in fractions of a second.
/// Currently either milliseconds or microseconds.
///
/// This is a private type, used in the implementation of
/// [NaiveDateTime::from_timestamp_millis] and [NaiveDateTime::from_timestamp_micros].
#[derive(Clone, Copy, Debug)]
enum TimestampUnit {
Millis,
Micros,
}

impl TimestampUnit {
fn per_second(self) -> u32 {
match self {
TimestampUnit::Millis => 1_000,
TimestampUnit::Micros => 1_000_000,
}
}
fn nanos_per(self) -> u32 {
match self {
TimestampUnit::Millis => 1_000_000,
TimestampUnit::Micros => 1_000,
}
}
}

impl NaiveDateTime {
/// Makes a new `NaiveDateTime` from date and time components.
/// Equivalent to [`date.and_time(time)`](./struct.NaiveDate.html#method.and_time)
Expand Down Expand Up @@ -180,7 +147,9 @@ impl NaiveDateTime {
#[inline]
#[must_use]
pub fn from_timestamp_millis(millis: i64) -> Option<NaiveDateTime> {
Self::from_timestamp_unit(millis, TimestampUnit::Millis)
let secs = millis.div_euclid(1000);
let nsecs = millis.rem_euclid(1000) as u32 * 1_000_000;
NaiveDateTime::from_timestamp_opt(secs, nsecs)
}

/// Creates a new [NaiveDateTime] from microseconds since the UNIX epoch.
Expand All @@ -207,7 +176,9 @@ impl NaiveDateTime {
#[inline]
#[must_use]
pub fn from_timestamp_micros(micros: i64) -> Option<NaiveDateTime> {
Self::from_timestamp_unit(micros, TimestampUnit::Micros)
let secs = micros.div_euclid(1_000_000);
let nsecs = micros.rem_euclid(1_000_000) as u32 * 1000;
NaiveDateTime::from_timestamp_opt(secs, nsecs)
}

/// Makes a new `NaiveDateTime` corresponding to a UTC date and time,
Expand Down Expand Up @@ -950,36 +921,6 @@ impl NaiveDateTime {
pub const MIN: Self = Self { date: NaiveDate::MIN, time: NaiveTime::MIN };
/// The maximum possible `NaiveDateTime`.
pub const MAX: Self = Self { date: NaiveDate::MAX, time: NaiveTime::MAX };

/// Creates a new [NaiveDateTime] from milliseconds or microseconds since the UNIX epoch.
///
/// This is a private function used by [from_timestamp_millis] and [from_timestamp_micros].
#[inline]
fn from_timestamp_unit(value: i64, unit: TimestampUnit) -> Option<NaiveDateTime> {
let (secs, subsecs) =
(value / i64::from(unit.per_second()), value % i64::from(unit.per_second()));

match subsecs.cmp(&0) {
Ordering::Less => {
// in the case where our subsec part is negative, then we are actually in the earlier second
// hence we subtract one from the seconds part, and we then add a whole second worth of nanos
// to our nanos part. Due to the use of u32 datatype, it is more convenient to subtract
// the absolute value of the subsec nanos from a whole second worth of nanos
let nsecs = u32::try_from(subsecs.abs()).ok()? * unit.nanos_per();
NaiveDateTime::from_timestamp_opt(
secs.checked_sub(1)?,
NANOS_IN_SECOND.checked_sub(nsecs)?,
)
}
Ordering::Equal => NaiveDateTime::from_timestamp_opt(secs, 0),
Ordering::Greater => {
// convert the subsec millis into nanosecond scale so they can be supplied
// as the nanoseconds parameter
let nsecs = u32::try_from(subsecs).ok()? * unit.nanos_per();
NaiveDateTime::from_timestamp_opt(secs, nsecs)
}
}
}
}

impl Datelike for NaiveDateTime {
Expand Down

0 comments on commit bddfbf8

Please sign in to comment.