mirror of
https://github.com/chronotope/chrono.git
synced 2025-10-02 23:36:17 +00:00
Add from_timestamp_micros function
This commit is contained in:
parent
918003e7ee
commit
a1591e91f3
@ -87,6 +87,32 @@ pub struct NaiveDateTime {
|
|||||||
time: NaiveTime,
|
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 {
|
impl NaiveDateTime {
|
||||||
/// Makes a new `NaiveDateTime` from date and time components.
|
/// Makes a new `NaiveDateTime` from date and time components.
|
||||||
/// Equivalent to [`date.and_time(time)`](./struct.NaiveDate.html#method.and_time)
|
/// Equivalent to [`date.and_time(time)`](./struct.NaiveDate.html#method.and_time)
|
||||||
@ -152,28 +178,33 @@ impl NaiveDateTime {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_timestamp_millis(millis: i64) -> Option<NaiveDateTime> {
|
pub fn from_timestamp_millis(millis: i64) -> Option<NaiveDateTime> {
|
||||||
let (secs, subsec_millis) = (millis / 1000, millis % 1000);
|
Self::from_timestamp_unit(millis, TimestampUnit::Millis)
|
||||||
|
}
|
||||||
|
|
||||||
match subsec_millis.cmp(&0) {
|
/// Creates a new [NaiveDateTime] from microseconds since the UNIX epoch.
|
||||||
Ordering::Less => {
|
///
|
||||||
// in the case where our subsec part is negative, then we are actually in the earlier second
|
/// The UNIX epoch starts on midnight, January 1, 1970, UTC.
|
||||||
// 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
|
/// Returns `None` on an out-of-range number of microseconds.
|
||||||
// the absolute value of the subsec nanos from a whole second worth of nanos
|
///
|
||||||
let nsecs = u32::try_from(subsec_millis.abs()).ok()? * NANOS_IN_MILLISECOND;
|
/// # Example
|
||||||
NaiveDateTime::from_timestamp_opt(
|
///
|
||||||
secs.checked_sub(1)?,
|
/// ```
|
||||||
NANOS_IN_SECOND.checked_sub(nsecs)?,
|
/// use chrono::NaiveDateTime;
|
||||||
)
|
/// let timestamp_micros: i64 = 1662921288000000; //Sunday, September 11, 2022 6:34:48 PM
|
||||||
}
|
/// let naive_datetime = NaiveDateTime::from_timestamp_micros(timestamp_micros);
|
||||||
Ordering::Equal => NaiveDateTime::from_timestamp_opt(secs, 0),
|
/// assert!(naive_datetime.is_some());
|
||||||
Ordering::Greater => {
|
/// assert_eq!(timestamp_micros, naive_datetime.unwrap().timestamp_micros());
|
||||||
// convert the subsec millis into nanosecond scale so they can be supplied
|
///
|
||||||
// as the nanoseconds parameter
|
/// // Negative timestamps (before the UNIX epoch) are supported as well.
|
||||||
let nsecs = u32::try_from(subsec_millis).ok()? * NANOS_IN_MILLISECOND;
|
/// let timestamp_micros: i64 = -2208936075000000; //Mon Jan 01 1900 14:38:45 GMT+0000
|
||||||
NaiveDateTime::from_timestamp_opt(secs, nsecs)
|
/// let naive_datetime = NaiveDateTime::from_timestamp_micros(timestamp_micros);
|
||||||
}
|
/// assert!(naive_datetime.is_some());
|
||||||
}
|
/// assert_eq!(timestamp_micros, naive_datetime.unwrap().timestamp_micros());
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn from_timestamp_micros(micros: i64) -> Option<NaiveDateTime> {
|
||||||
|
Self::from_timestamp_unit(micros, TimestampUnit::Micros)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a new `NaiveDateTime` corresponding to a UTC date and time,
|
/// Makes a new `NaiveDateTime` corresponding to a UTC date and time,
|
||||||
@ -866,6 +897,36 @@ impl NaiveDateTime {
|
|||||||
pub const MIN: Self = Self { date: NaiveDate::MIN, time: NaiveTime::MIN };
|
pub const MIN: Self = Self { date: NaiveDate::MIN, time: NaiveTime::MIN };
|
||||||
/// The maximum possible `NaiveDateTime`.
|
/// The maximum possible `NaiveDateTime`.
|
||||||
pub const MAX: Self = Self { date: NaiveDate::MAX, time: NaiveTime::MAX };
|
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 {
|
impl Datelike for NaiveDateTime {
|
||||||
|
@ -17,7 +17,7 @@ fn test_datetime_from_timestamp_millis() {
|
|||||||
(2034061609000, "2034-06-16 09:06:49.000000000"),
|
(2034061609000, "2034-06-16 09:06:49.000000000"),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (timestamp_millis, formatted) in valid_map.iter().cloned() {
|
for (timestamp_millis, formatted) in valid_map.iter().copied() {
|
||||||
let naive_datetime = NaiveDateTime::from_timestamp_millis(timestamp_millis);
|
let naive_datetime = NaiveDateTime::from_timestamp_millis(timestamp_millis);
|
||||||
assert_eq!(timestamp_millis, naive_datetime.unwrap().timestamp_millis());
|
assert_eq!(timestamp_millis, naive_datetime.unwrap().timestamp_millis());
|
||||||
assert_eq!(naive_datetime.unwrap().format("%F %T%.9f").to_string(), formatted);
|
assert_eq!(naive_datetime.unwrap().format("%F %T%.9f").to_string(), formatted);
|
||||||
@ -25,7 +25,7 @@ fn test_datetime_from_timestamp_millis() {
|
|||||||
|
|
||||||
let invalid = [i64::MAX, i64::MIN];
|
let invalid = [i64::MAX, i64::MIN];
|
||||||
|
|
||||||
for timestamp_millis in invalid.iter().cloned() {
|
for timestamp_millis in invalid.iter().copied() {
|
||||||
let naive_datetime = NaiveDateTime::from_timestamp_millis(timestamp_millis);
|
let naive_datetime = NaiveDateTime::from_timestamp_millis(timestamp_millis);
|
||||||
assert!(naive_datetime.is_none());
|
assert!(naive_datetime.is_none());
|
||||||
}
|
}
|
||||||
@ -41,6 +41,43 @@ fn test_datetime_from_timestamp_millis() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_datetime_from_timestamp_micros() {
|
||||||
|
let valid_map = [
|
||||||
|
(1662921288000000, "2022-09-11 18:34:48.000000000"),
|
||||||
|
(1662921288123456, "2022-09-11 18:34:48.123456000"),
|
||||||
|
(1662921287890000, "2022-09-11 18:34:47.890000000"),
|
||||||
|
(-2208936075000000, "1900-01-01 14:38:45.000000000"),
|
||||||
|
(0, "1970-01-01 00:00:00.000000000"),
|
||||||
|
(119731017000000, "1973-10-17 18:36:57.000000000"),
|
||||||
|
(1234567890000000, "2009-02-13 23:31:30.000000000"),
|
||||||
|
(2034061609000000, "2034-06-16 09:06:49.000000000"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (timestamp_micros, formatted) in valid_map.iter().copied() {
|
||||||
|
let naive_datetime = NaiveDateTime::from_timestamp_micros(timestamp_micros);
|
||||||
|
assert_eq!(timestamp_micros, naive_datetime.unwrap().timestamp_micros());
|
||||||
|
assert_eq!(naive_datetime.unwrap().format("%F %T%.9f").to_string(), formatted);
|
||||||
|
}
|
||||||
|
|
||||||
|
let invalid = [i64::MAX, i64::MIN];
|
||||||
|
|
||||||
|
for timestamp_micros in invalid.iter().copied() {
|
||||||
|
let naive_datetime = NaiveDateTime::from_timestamp_micros(timestamp_micros);
|
||||||
|
assert!(naive_datetime.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that the result of `from_timestamp_micros` compares equal to
|
||||||
|
// that of `from_timestamp_opt`.
|
||||||
|
let secs_test = [0, 1, 2, 1000, 1234, 12345678, -1, -2, -1000, -12345678];
|
||||||
|
for secs in secs_test.iter().copied() {
|
||||||
|
assert_eq!(
|
||||||
|
NaiveDateTime::from_timestamp_micros(secs * 1_000_000),
|
||||||
|
NaiveDateTime::from_timestamp_opt(secs, 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_datetime_from_timestamp() {
|
fn test_datetime_from_timestamp() {
|
||||||
let from_timestamp = |secs| NaiveDateTime::from_timestamp_opt(secs, 0);
|
let from_timestamp = |secs| NaiveDateTime::from_timestamp_opt(secs, 0);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user