From c92544923d5702fb554aaa84763e33551dc55502 Mon Sep 17 00:00:00 2001 From: jean-airoldie <25088801+jean-airoldie@users.noreply.github.com> Date: Wed, 6 Mar 2019 10:32:40 -0500 Subject: [PATCH 1/4] Add timestamp_nanos generated method for TimeZone --- src/offset/mod.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/offset/mod.rs b/src/offset/mod.rs index 0ea0dc2..be1e593 100644 --- a/src/offset/mod.rs +++ b/src/offset/mod.rs @@ -381,6 +381,28 @@ pub trait TimeZone: Sized + Clone { self.timestamp_opt(secs, millis as u32 * 1_000_000) } + /// Makes a new `DateTime` from the number of non-leap nanoseconds + /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp"). + /// + /// Unlike [`timestamp_millis`](#method.timestamp_millis), this never + /// panics. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{Utc, TimeZone}; + /// + /// assert_eq!(Utc.timestamp_nanos(1431648000000000).timestamp(), 1431648); + /// ~~~~ + fn timestamp_nanos(&self, nanos: i64) -> DateTime { + let (mut secs, mut nanos) = (nanos / 1_000_000_000, nanos % 1_000_000_000); + if nanos < 0 { + secs -= 1; + nanos += 1_000_000_000; + } + self.timestamp_opt(secs, nanos as u32).unwrap() + } + /// Parses a string with the specified format string and /// returns a `DateTime` with the current offset. /// See the [`format::strftime` module](../format/strftime/index.html) @@ -466,4 +488,25 @@ mod tests { let dt = Utc.timestamp_millis(-3600000); assert_eq!(dt.to_string(), "1969-12-31 23:00:00 UTC"); } + + #[test] + fn test_negative_nanos() { + let dt = Utc.timestamp_nanos(-1_000_000_000); + assert_eq!(dt.to_string(), "1969-12-31 23:59:59 UTC"); + let dt = Utc.timestamp_nanos(-999_999_999); + assert_eq!(dt.to_string(), "1969-12-31 23:59:59.000000001 UTC"); + let dt = Utc.timestamp_nanos(-1); + assert_eq!(dt.to_string(), "1969-12-31 23:59:59.999999999 UTC"); + let dt = Utc.timestamp_nanos(-60_000_000_000); + assert_eq!(dt.to_string(), "1969-12-31 23:59:00 UTC"); + let dt = Utc.timestamp_nanos(-3_600_000_000_000); + assert_eq!(dt.to_string(), "1969-12-31 23:00:00 UTC"); + } + + #[test] + fn test_nanos_never_panics() { + Utc.timestamp_nanos(i64::max_value()); + Utc.timestamp_nanos(i64::default()); + Utc.timestamp_nanos(i64::min_value()); + } } From 33800c876bfb1ddf4db7a2c76ad4628557f2c6a6 Mon Sep 17 00:00:00 2001 From: Brandon W Maister Date: Sat, 23 Mar 2019 20:47:47 -0400 Subject: [PATCH 2/4] Add docs around panic behavior around timestamp_nanos Document panic behavior that should have been documented better. Resolves #310 --- src/naive/datetime.rs | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/naive/datetime.rs b/src/naive/datetime.rs index d228a54..bb9ff8d 100644 --- a/src/naive/datetime.rs +++ b/src/naive/datetime.rs @@ -305,21 +305,33 @@ impl NaiveDateTime { /// Note that this does *not* account for the timezone! /// The true "UNIX timestamp" would count seconds since the midnight *UTC* on the epoch. /// + /// # Panics + /// /// Note also that this does reduce the number of years that can be - /// represented from ~584 Billion to ~584. (If this is a problem, - /// please file an issue to let me know what domain needs nanosecond - /// precision over millenia, I'm curious.) + /// represented from ~584 Billion to ~584 years. The dates that can be + /// represented as nanoseconds are between 1677-09-21T00:12:44.0 and + /// 2262-04-11T23:47:16.854775804. + /// + /// (If this is a problem, please file an issue to let me know what domain + /// needs nanosecond precision over millenia, I'm curious.) /// /// # Example /// /// ~~~~ - /// use chrono::NaiveDate; + /// use chrono::{NaiveDate, NaiveDateTime}; /// /// let dt = NaiveDate::from_ymd(1970, 1, 1).and_hms_nano(0, 0, 1, 444); /// assert_eq!(dt.timestamp_nanos(), 1_000_000_444); /// /// let dt = NaiveDate::from_ymd(2001, 9, 9).and_hms_nano(1, 46, 40, 555); - /// assert_eq!(dt.timestamp_nanos(), 1_000_000_000_000_000_555); + /// + /// const A_BILLION: i64 = 1_000_000_000; + /// let nanos = dt.timestamp_nanos(); + /// assert_eq!(nanos, 1_000_000_000_000_000_555); + /// assert_eq!( + /// dt, + /// NaiveDateTime::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32) + /// ); /// ~~~~ #[inline] pub fn timestamp_nanos(&self) -> i64 { @@ -2348,4 +2360,24 @@ mod tests { let time = base + Duration::microseconds(t); assert_eq!(t, time.signed_duration_since(base).num_microseconds().unwrap()); } + + #[test] + fn test_nanosecond_range() { + const A_BILLION: i64 = 1_000_000_000; + let maximum = "2262-04-11T23:47:16.854775804"; + let parsed: NaiveDateTime = maximum.parse().unwrap(); + let nanos = parsed.timestamp_nanos(); + assert_eq!( + parsed, + NaiveDateTime::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32) + ); + + let minimum = "1677-09-21T00:12:44.000000000"; + let parsed: NaiveDateTime = minimum.parse().unwrap(); + let nanos = parsed.timestamp_nanos(); + assert_eq!( + parsed, + NaiveDateTime::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32) + ); + } } From 855a894393d9675be104988ac0a1424c9c5a41eb Mon Sep 17 00:00:00 2001 From: Brandon W Maister Date: Sat, 23 Mar 2019 20:49:05 -0400 Subject: [PATCH 3/4] Don't warn on deprecated trim functions --- src/format/parse.rs | 2 ++ src/format/scan.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/format/parse.rs b/src/format/parse.rs index 88c32d1..6810f69 100644 --- a/src/format/parse.rs +++ b/src/format/parse.rs @@ -4,6 +4,8 @@ //! Date and time parsing routines. +#![allow(deprecated)] + use std::usize; use Weekday; diff --git a/src/format/scan.rs b/src/format/scan.rs index f2f97d9..c311175 100644 --- a/src/format/scan.rs +++ b/src/format/scan.rs @@ -5,6 +5,8 @@ * Various scanning routines for the parser. */ +#![allow(deprecated)] + use Weekday; use super::{ParseResult, TOO_SHORT, INVALID, OUT_OF_RANGE}; From 95bf861cebcd9b33bb9009cf97ee2a6fc6227005 Mon Sep 17 00:00:00 2001 From: Brandon W Maister Date: Sun, 24 Mar 2019 12:04:06 -0400 Subject: [PATCH 4/4] Disable libc default features so it builds on rust 1.13 --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 71fac86..1536077 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ default = ["clock"] clock = ["time"] [dependencies] +libc = { version = "0.2", default-features = false } time = { version = "0.1.39", optional = true } num-integer = { version = "0.1.36", default-features = false } num-traits = { version = "0.2", default-features = false }