From c8cf743853c094ea4487ad76d46a8970a73d82df Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Tue, 22 Sep 2020 23:39:09 -0400 Subject: [PATCH] Don't require time crate for `clock` feature Absorb just enough of the time crate that it is no longer required for the clock feature. v0.1 of the time crate is long deprecated, and v0.2 of the crate is a complete rewrite. Vendoring v0.1 allows chrono to control its own destiny. It also means that downstream users that have upgraded to the time v0.2 ecosystem do not wind up with both time v0.1 and v0.2 in the dependency tree. Even with this patch, the dependency on the old time crate remains by default for backwards compatibility. Specifically, the `chrono::Duration` type is a re-export of the `time::Duration` type when the `oldtime` feature is enabled, as it is by default. The intent is that the `oldtime` feature will be removed when chrono v0.5 is released. Supersedes #286. Fixes #400. --- CHANGELOG.md | 6 ++ Cargo.toml | 9 ++- README.md | 3 +- src/lib.rs | 18 ++++-- src/naive/date.rs | 30 ++++------ src/naive/datetime.rs | 70 +++++++++------------- src/naive/time.rs | 60 ++++++++----------- src/offset/local.rs | 19 +++--- src/offset/utc.rs | 13 +++-- src/sys.rs | 126 ++++++++++++++++++++++++++++++++++++++++ src/sys/unix.rs | 118 +++++++++++++++++++++++++++++++++++++ src/sys/wasm32.rs | 80 ++++++++++++++++++++++++++ src/sys/windows.rs | 131 ++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 564 insertions(+), 119 deletions(-) create mode 100644 src/sys.rs create mode 100644 src/sys/unix.rs create mode 100644 src/sys/wasm32.rs create mode 100644 src/sys/windows.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 7068bc963e..1cae3caec0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,12 @@ Versions with only mechanical changes will be omitted from the following list. * Add %Z specifier to the `FromStr`, similar to the glibc strptime (does not set the offset from the timezone name) +* Drop the dependency on time v0.1, which is deprecated, unless the `oldtime` + feature is active. This feature is active by default in v0.4.16 for backwards + compatibility, but will likely be removed in v0.5. Code that imports + `time::Duration` should be switched to import `chrono::Duration` instead to + avoid breakage. + ## 0.4.15 ### Fixes diff --git a/Cargo.toml b/Cargo.toml index 7160d7cb1c..7e62fa57bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,16 +24,18 @@ appveyor = { repository = "chronotope/chrono" } name = "chrono" [features] -default = ["clock", "std"] +default = ["clock", "std", "oldtime"] alloc = [] std = [] -clock = ["time", "std"] +clock = ["libc", "std", "winapi"] +oldtime = ["time"] wasmbind = ["wasm-bindgen", "js-sys"] unstable-locales = ["pure-rust-locales", "alloc"] __internal_bench = [] __doctest = [] [dependencies] +libc = { version = "0.2.69", optional = true } time = { version = "0.1.43", optional = true } num-integer = { version = "0.1.36", default-features = false } num-traits = { version = "0.2", default-features = false } @@ -45,6 +47,9 @@ pure-rust-locales = { version = "0.5.2", optional = true } wasm-bindgen = { version = "0.2", optional = true } js-sys = { version = "0.3", optional = true } # contains FFI bindings for the JS Date API +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3.0", features = ["std", "minwinbase", "minwindef", "timezoneapi"], optional = true } + [dev-dependencies] serde_json = { version = "1" } serde_derive = { version = "1", default-features = false } diff --git a/README.md b/README.md index 5f57c0fdc9..23bd952158 100644 --- a/README.md +++ b/README.md @@ -177,10 +177,9 @@ Addition and subtraction is also supported. The following illustrates most supported operations to the date and time: ```rust -extern crate time; use chrono::prelude::*; -use time::Duration; +use chrono::Duration; // assume this returned `2014-11-28T21:45:59.324310806+09:00`: let dt = FixedOffset::east(9*3600).ymd(2014, 11, 28).and_hms_nano(21, 45, 59, 324310806); diff --git a/src/lib.rs b/src/lib.rs index 38ca22c864..da25104e0c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -167,11 +167,10 @@ //! //! ```rust //! # extern crate chrono; -//! extern crate time; //! //! # fn main() { //! use chrono::prelude::*; -//! use time::Duration; +//! use chrono::Duration; //! //! // assume this returned `2014-11-28T21:45:59.324310806+09:00`: //! let dt = FixedOffset::east(9*3600).ymd(2014, 11, 28).and_hms_nano(21, 45, 59, 324310806); @@ -438,10 +437,21 @@ extern crate std as alloc; #[cfg(any(feature = "std", test))] extern crate std as core; -#[cfg(feature = "clock")] +#[cfg(feature = "oldtime")] extern crate time as oldtime; -#[cfg(not(feature = "clock"))] +#[cfg(not(feature = "oldtime"))] mod oldtime; + +#[cfg(feature = "clock")] +extern crate libc; +#[cfg(all(feature = "clock", windows))] +extern crate winapi; +#[cfg(all( + feature = "clock", + not(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind")) +))] +mod sys; + extern crate num_integer; extern crate num_traits; #[cfg(feature = "rustc-serialize")] diff --git a/src/naive/date.rs b/src/naive/date.rs index df7f70c34f..3e34e20741 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -874,10 +874,9 @@ impl NaiveDate { /// # Example /// /// ~~~~ - /// # extern crate chrono; extern crate time; fn main() { - /// use chrono::NaiveDate; + /// # extern crate chrono; fn main() { + /// use chrono::{Duration, NaiveDate}; /// use chrono::naive::MAX_DATE; - /// use time::Duration; /// /// let d = NaiveDate::from_ymd(2015, 9, 5); /// assert_eq!(d.checked_add_signed(Duration::days(40)), @@ -909,10 +908,9 @@ impl NaiveDate { /// # Example /// /// ~~~~ - /// # extern crate chrono; extern crate time; fn main() { - /// use chrono::NaiveDate; + /// # extern crate chrono; fn main() { + /// use chrono::{Duration, NaiveDate}; /// use chrono::naive::MIN_DATE; - /// use time::Duration; /// /// let d = NaiveDate::from_ymd(2015, 9, 5); /// assert_eq!(d.checked_sub_signed(Duration::days(40)), @@ -946,9 +944,8 @@ impl NaiveDate { /// # Example /// /// ~~~~ - /// # extern crate chrono; extern crate time; fn main() { - /// use chrono::NaiveDate; - /// use time::Duration; + /// # extern crate chrono; fn main() { + /// use chrono::{Duration, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// let since = NaiveDate::signed_duration_since; @@ -1453,9 +1450,8 @@ impl Datelike for NaiveDate { /// # Example /// /// ~~~~ -/// # extern crate chrono; extern crate time; fn main() { -/// use chrono::NaiveDate; -/// use time::Duration; +/// # extern crate chrono; fn main() { +/// use chrono::{Duration, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// @@ -1495,9 +1491,8 @@ impl AddAssign for NaiveDate { /// # Example /// /// ~~~~ -/// # extern crate chrono; extern crate time; fn main() { -/// use chrono::NaiveDate; -/// use time::Duration; +/// # extern crate chrono; fn main() { +/// use chrono::{Duration, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// @@ -1539,9 +1534,8 @@ impl SubAssign for NaiveDate { /// # Example /// /// ~~~~ -/// # extern crate chrono; extern crate time; fn main() { -/// use chrono::NaiveDate; -/// use time::Duration; +/// # extern crate chrono; fn main() { +/// use chrono::{Duration, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// diff --git a/src/naive/datetime.rs b/src/naive/datetime.rs index a768609cfc..5ab6ff2d4b 100644 --- a/src/naive/datetime.rs +++ b/src/naive/datetime.rs @@ -427,9 +427,8 @@ impl NaiveDateTime { /// # Example /// /// ~~~~ - /// # extern crate chrono; extern crate time; fn main() { - /// use chrono::NaiveDate; - /// use time::Duration; + /// # extern crate chrono; fn main() { + /// use chrono::{Duration, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// @@ -455,9 +454,8 @@ impl NaiveDateTime { /// Overflow returns `None`. /// /// ~~~~ - /// # extern crate chrono; extern crate time; fn main() { - /// # use chrono::NaiveDate; - /// # use time::Duration; + /// # extern crate chrono; fn main() { + /// # use chrono::{Duration, NaiveDate}; /// # let hms = |h, m, s| NaiveDate::from_ymd(2016, 7, 8).and_hms(h, m, s); /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::days(1_000_000_000)), None); /// # } @@ -467,9 +465,8 @@ impl NaiveDateTime { /// but the addition assumes that it is the only leap second happened. /// /// ~~~~ - /// # extern crate chrono; extern crate time; fn main() { - /// # use chrono::NaiveDate; - /// # use time::Duration; + /// # extern crate chrono; fn main() { + /// # use chrono::{Duration, NaiveDate}; /// # let from_ymd = NaiveDate::from_ymd; /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli(h, m, s, milli); /// let leap = hmsm(3, 5, 59, 1_300); @@ -513,9 +510,8 @@ impl NaiveDateTime { /// # Example /// /// ~~~~ - /// # extern crate chrono; extern crate time; fn main() { - /// use chrono::NaiveDate; - /// use time::Duration; + /// # extern crate chrono; fn main() { + /// use chrono::{Duration, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// @@ -541,9 +537,8 @@ impl NaiveDateTime { /// Overflow returns `None`. /// /// ~~~~ - /// # extern crate chrono; extern crate time; fn main() { - /// # use chrono::NaiveDate; - /// # use time::Duration; + /// # extern crate chrono; fn main() { + /// # use chrono::{Duration, NaiveDate}; /// # let hms = |h, m, s| NaiveDate::from_ymd(2016, 7, 8).and_hms(h, m, s); /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::days(1_000_000_000)), None); /// # } @@ -553,9 +548,8 @@ impl NaiveDateTime { /// but the subtraction assumes that it is the only leap second happened. /// /// ~~~~ - /// # extern crate chrono; extern crate time; fn main() { - /// # use chrono::NaiveDate; - /// # use time::Duration; + /// # extern crate chrono; fn main() { + /// # use chrono::{Duration, NaiveDate}; /// # let from_ymd = NaiveDate::from_ymd; /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli(h, m, s, milli); /// let leap = hmsm(3, 5, 59, 1_300); @@ -595,9 +589,8 @@ impl NaiveDateTime { /// # Example /// /// ~~~~ - /// # extern crate chrono; extern crate time; fn main() { - /// use chrono::NaiveDate; - /// use time::Duration; + /// # extern crate chrono; fn main() { + /// use chrono::{Duration, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// @@ -616,9 +609,8 @@ impl NaiveDateTime { /// there were no other leap seconds happened. /// /// ~~~~ - /// # extern crate chrono; extern crate time; fn main() { - /// # use chrono::NaiveDate; - /// # use time::Duration; + /// # extern crate chrono; fn main() { + /// # use chrono::{Duration, NaiveDate}; /// # let from_ymd = NaiveDate::from_ymd; /// let leap = from_ymd(2015, 6, 30).and_hms_milli(23, 59, 59, 1_500); /// assert_eq!(leap.signed_duration_since(from_ymd(2015, 6, 30).and_hms(23, 0, 0)), @@ -1217,9 +1209,8 @@ impl hash::Hash for NaiveDateTime { /// # Example /// /// ~~~~ -/// # extern crate chrono; extern crate time; fn main() { -/// use chrono::NaiveDate; -/// use time::Duration; +/// # extern crate chrono; fn main() { +/// use chrono::{Duration, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// @@ -1243,9 +1234,8 @@ impl hash::Hash for NaiveDateTime { /// but the addition assumes that it is the only leap second happened. /// /// ~~~~ -/// # extern crate chrono; extern crate time; fn main() { -/// # use chrono::NaiveDate; -/// # use time::Duration; +/// # extern crate chrono; fn main() { +/// # use chrono::{Duration, NaiveDate}; /// # let from_ymd = NaiveDate::from_ymd; /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli(h, m, s, milli); /// let leap = hmsm(3, 5, 59, 1_300); @@ -1289,9 +1279,8 @@ impl AddAssign for NaiveDateTime { /// # Example /// /// ~~~~ -/// # extern crate chrono; extern crate time; fn main() { -/// use chrono::NaiveDate; -/// use time::Duration; +/// # extern crate chrono; fn main() { +/// use chrono::{Duration, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// @@ -1315,9 +1304,8 @@ impl AddAssign for NaiveDateTime { /// but the subtraction assumes that it is the only leap second happened. /// /// ~~~~ -/// # extern crate chrono; extern crate time; fn main() { -/// # use chrono::NaiveDate; -/// # use time::Duration; +/// # extern crate chrono; fn main() { +/// # use chrono::{Duration, NaiveDate}; /// # let from_ymd = NaiveDate::from_ymd; /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli(h, m, s, milli); /// let leap = hmsm(3, 5, 59, 1_300); @@ -1360,9 +1348,8 @@ impl SubAssign for NaiveDateTime { /// # Example /// /// ~~~~ -/// # extern crate chrono; extern crate time; fn main() { -/// use chrono::NaiveDate; -/// use time::Duration; +/// # extern crate chrono; fn main() { +/// use chrono::{Duration, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// @@ -1380,9 +1367,8 @@ impl SubAssign for NaiveDateTime { /// there were no other leap seconds happened. /// /// ~~~~ -/// # extern crate chrono; extern crate time; fn main() { -/// # use chrono::NaiveDate; -/// # use time::Duration; +/// # extern crate chrono; fn main() { +/// # use chrono::{Duration, NaiveDate}; /// # let from_ymd = NaiveDate::from_ymd; /// let leap = from_ymd(2015, 6, 30).and_hms_milli(23, 59, 59, 1_500); /// assert_eq!(leap - from_ymd(2015, 6, 30).and_hms(23, 0, 0), diff --git a/src/naive/time.rs b/src/naive/time.rs index 71072cf9e6..1ddc9fbedc 100644 --- a/src/naive/time.rs +++ b/src/naive/time.rs @@ -515,9 +515,8 @@ impl NaiveTime { /// # Example /// /// ~~~~ - /// # extern crate chrono; extern crate time; fn main() { - /// use chrono::NaiveTime; - /// use time::Duration; + /// # extern crate chrono; fn main() { + /// use chrono::{Duration, NaiveTime}; /// /// let from_hms = NaiveTime::from_hms; /// @@ -601,9 +600,8 @@ impl NaiveTime { /// # Example /// /// ~~~~ - /// # extern crate chrono; extern crate time; fn main() { - /// use chrono::NaiveTime; - /// use time::Duration; + /// # extern crate chrono; fn main() { + /// use chrono::{Duration, NaiveTime}; /// /// let from_hms = NaiveTime::from_hms; /// @@ -634,9 +632,8 @@ impl NaiveTime { /// # Example /// /// ~~~~ - /// # extern crate chrono; extern crate time; fn main() { - /// use chrono::NaiveTime; - /// use time::Duration; + /// # extern crate chrono; fn main() { + /// use chrono::{Duration, NaiveTime}; /// /// let from_hmsm = NaiveTime::from_hms_milli; /// let since = NaiveTime::signed_duration_since; @@ -664,9 +661,8 @@ impl NaiveTime { /// there were no other leap seconds happened. /// /// ~~~~ - /// # extern crate chrono; extern crate time; fn main() { - /// # use chrono::NaiveTime; - /// # use time::Duration; + /// # extern crate chrono; fn main() { + /// # use chrono::{Duration, NaiveTime}; /// # let from_hmsm = NaiveTime::from_hms_milli; /// # let since = NaiveTime::signed_duration_since; /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000), from_hmsm(3, 0, 59, 0)), @@ -1035,9 +1031,8 @@ impl hash::Hash for NaiveTime { /// # Example /// /// ~~~~ -/// # extern crate chrono; extern crate time; fn main() { -/// use chrono::NaiveTime; -/// use time::Duration; +/// # extern crate chrono; fn main() { +/// use chrono::{Duration, NaiveTime}; /// /// let from_hmsm = NaiveTime::from_hms_milli; /// @@ -1055,9 +1050,8 @@ impl hash::Hash for NaiveTime { /// The addition wraps around. /// /// ~~~~ -/// # extern crate chrono; extern crate time; fn main() { -/// # use chrono::NaiveTime; -/// # use time::Duration; +/// # extern crate chrono; fn main() { +/// # use chrono::{Duration, NaiveTime}; /// # let from_hmsm = NaiveTime::from_hms_milli; /// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::seconds(22*60*60), from_hmsm(1, 5, 7, 0)); /// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::seconds(-8*60*60), from_hmsm(19, 5, 7, 0)); @@ -1068,9 +1062,8 @@ impl hash::Hash for NaiveTime { /// Leap seconds are handled, but the addition assumes that it is the only leap second happened. /// /// ~~~~ -/// # extern crate chrono; extern crate time; fn main() { -/// # use chrono::NaiveTime; -/// # use time::Duration; +/// # extern crate chrono; fn main() { +/// # use chrono::{Duration, NaiveTime}; /// # let from_hmsm = NaiveTime::from_hms_milli; /// let leap = from_hmsm(3, 5, 59, 1_300); /// assert_eq!(leap + Duration::zero(), from_hmsm(3, 5, 59, 1_300)); @@ -1110,9 +1103,8 @@ impl AddAssign for NaiveTime { /// # Example /// /// ~~~~ -/// # extern crate chrono; extern crate time; fn main() { -/// use chrono::NaiveTime; -/// use time::Duration; +/// # extern crate chrono; fn main() { +/// use chrono::{Duration, NaiveTime}; /// /// let from_hmsm = NaiveTime::from_hms_milli; /// @@ -1128,9 +1120,8 @@ impl AddAssign for NaiveTime { /// The subtraction wraps around. /// /// ~~~~ -/// # extern crate chrono; extern crate time; fn main() { -/// # use chrono::NaiveTime; -/// # use time::Duration; +/// # extern crate chrono; fn main() { +/// # use chrono::{Duration, NaiveTime}; /// # let from_hmsm = NaiveTime::from_hms_milli; /// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::seconds(8*60*60), from_hmsm(19, 5, 7, 0)); /// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::days(800), from_hmsm(3, 5, 7, 0)); @@ -1140,9 +1131,8 @@ impl AddAssign for NaiveTime { /// Leap seconds are handled, but the subtraction assumes that it is the only leap second happened. /// /// ~~~~ -/// # extern crate chrono; extern crate time; fn main() { -/// # use chrono::NaiveTime; -/// # use time::Duration; +/// # extern crate chrono; fn main() { +/// # use chrono::{Duration, NaiveTime}; /// # let from_hmsm = NaiveTime::from_hms_milli; /// let leap = from_hmsm(3, 5, 59, 1_300); /// assert_eq!(leap - Duration::zero(), from_hmsm(3, 5, 59, 1_300)); @@ -1184,9 +1174,8 @@ impl SubAssign for NaiveTime { /// # Example /// /// ~~~~ -/// # extern crate chrono; extern crate time; fn main() { -/// use chrono::NaiveTime; -/// use time::Duration; +/// # extern crate chrono; fn main() { +/// use chrono::{Duration, NaiveTime}; /// /// let from_hmsm = NaiveTime::from_hms_milli; /// @@ -1206,9 +1195,8 @@ impl SubAssign for NaiveTime { /// there were no other leap seconds happened. /// /// ~~~~ -/// # extern crate chrono; extern crate time; fn main() { -/// # use chrono::NaiveTime; -/// # use time::Duration; +/// # extern crate chrono; fn main() { +/// # use chrono::{Duration, NaiveTime}; /// # let from_hmsm = NaiveTime::from_hms_milli; /// assert_eq!(from_hmsm(3, 0, 59, 1_000) - from_hmsm(3, 0, 59, 0), Duration::seconds(1)); /// assert_eq!(from_hmsm(3, 0, 59, 1_500) - from_hmsm(3, 0, 59, 0), diff --git a/src/offset/local.rs b/src/offset/local.rs index 52a819f70e..9f13e76b04 100644 --- a/src/offset/local.rs +++ b/src/offset/local.rs @@ -3,7 +3,8 @@ //! The local (system) time zone. -use oldtime; +#[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind")))] +use sys::{self, Timespec}; use super::fixed::FixedOffset; use super::{LocalResult, TimeZone}; @@ -17,20 +18,20 @@ use {Datelike, Timelike}; /// Converts a `time::Tm` struct into the timezone-aware `DateTime`. /// This assumes that `time` is working correctly, i.e. any error is fatal. #[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind")))] -fn tm_to_datetime(mut tm: oldtime::Tm) -> DateTime { +fn tm_to_datetime(mut tm: sys::Tm) -> DateTime { if tm.tm_sec >= 60 { tm.tm_nsec += (tm.tm_sec - 59) * 1_000_000_000; tm.tm_sec = 59; } #[cfg(not(windows))] - fn tm_to_naive_date(tm: &oldtime::Tm) -> NaiveDate { + fn tm_to_naive_date(tm: &sys::Tm) -> NaiveDate { // from_yo is more efficient than from_ymd (since it's the internal representation). NaiveDate::from_yo(tm.tm_year + 1900, tm.tm_yday as u32 + 1) } #[cfg(windows)] - fn tm_to_naive_date(tm: &oldtime::Tm) -> NaiveDate { + fn tm_to_naive_date(tm: &sys::Tm) -> NaiveDate { // ...but tm_yday is broken in Windows (issue #85) NaiveDate::from_ymd(tm.tm_year + 1900, tm.tm_mon as u32 + 1, tm.tm_mday as u32) } @@ -48,13 +49,13 @@ fn tm_to_datetime(mut tm: oldtime::Tm) -> DateTime { /// Converts a local `NaiveDateTime` to the `time::Timespec`. #[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind")))] -fn datetime_to_timespec(d: &NaiveDateTime, local: bool) -> oldtime::Timespec { +fn datetime_to_timespec(d: &NaiveDateTime, local: bool) -> sys::Timespec { // well, this exploits an undocumented `Tm::to_timespec` behavior // to get the exact function we want (either `timegm` or `mktime`). // the number 1 is arbitrary but should be non-zero to trigger `mktime`. let tm_utcoff = if local { 1 } else { 0 }; - let tm = oldtime::Tm { + let tm = sys::Tm { tm_sec: d.second() as i32, tm_min: d.minute() as i32, tm_hour: d.hour() as i32, @@ -98,7 +99,7 @@ impl Local { /// Returns a `DateTime` which corresponds to the current date. #[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind")))] pub fn now() -> DateTime { - tm_to_datetime(oldtime::now()) + tm_to_datetime(Timespec::now().local()) } /// Returns a `DateTime` which corresponds to the current date. @@ -160,7 +161,7 @@ impl TimeZone for Local { let timespec = datetime_to_timespec(local, true); // datetime_to_timespec completely ignores leap seconds, so we need to adjust for them - let mut tm = oldtime::at(timespec); + let mut tm = timespec.local(); assert_eq!(tm.tm_nsec, 0); tm.tm_nsec = local.nanosecond() as i32; @@ -184,7 +185,7 @@ impl TimeZone for Local { let timespec = datetime_to_timespec(utc, false); // datetime_to_timespec completely ignores leap seconds, so we need to adjust for them - let mut tm = oldtime::at(timespec); + let mut tm = timespec.local(); assert_eq!(tm.tm_nsec, 0); tm.tm_nsec = utc.nanosecond() as i32; diff --git a/src/offset/utc.rs b/src/offset/utc.rs index de38594b77..aec6667b0d 100644 --- a/src/offset/utc.rs +++ b/src/offset/utc.rs @@ -4,14 +4,14 @@ //! The UTC (Coordinated Universal Time) time zone. use core::fmt; + +use super::{FixedOffset, LocalResult, Offset, TimeZone}; +use naive::{NaiveDate, NaiveDateTime}; #[cfg(all( feature = "clock", not(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind")) ))] -use oldtime; - -use super::{FixedOffset, LocalResult, Offset, TimeZone}; -use naive::{NaiveDate, NaiveDateTime}; +use std::time::{SystemTime, UNIX_EPOCH}; #[cfg(feature = "clock")] use {Date, DateTime}; @@ -45,8 +45,9 @@ impl Utc { /// Returns a `DateTime` which corresponds to the current date. #[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind")))] pub fn now() -> DateTime { - let spec = oldtime::get_time(); - let naive = NaiveDateTime::from_timestamp(spec.sec, spec.nsec as u32); + let now = + SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch"); + let naive = NaiveDateTime::from_timestamp(now.as_secs() as i64, now.subsec_nanos() as u32); DateTime::from_utc(naive, Utc) } diff --git a/src/sys.rs b/src/sys.rs new file mode 100644 index 0000000000..8e88774792 --- /dev/null +++ b/src/sys.rs @@ -0,0 +1,126 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Platform wrappers for converting UTC times to and from the local time zone. +//! +//! This code was rescued from v0.1 of the time crate, which is no longer +//! maintained. It has been substantially stripped down to the bare minimum +//! required by chrono. + +use std::time::{SystemTime, UNIX_EPOCH}; + +#[cfg(target_arch = "wasm32")] +#[path = "sys/wasm32.rs"] +mod inner; + +#[cfg(unix)] +#[path = "sys/unix.rs"] +mod inner; + +#[cfg(windows)] +#[path = "sys/windows.rs"] +mod inner; + +/// A record specifying a time value in seconds and nanoseconds, where +/// nanoseconds represent the offset from the given second. +/// +/// For example a timespec of 1.2 seconds after the beginning of the epoch would +/// be represented as {sec: 1, nsec: 200000000}. +pub struct Timespec { + pub sec: i64, + pub nsec: i32, +} + +impl Timespec { + /// Constructs a timespec representing the current time in UTC. + pub fn now() -> Timespec { + let st = + SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch"); + Timespec { sec: st.as_secs() as i64, nsec: st.subsec_nanos() as i32 } + } + + /// Converts this timespec into the system's local time. + pub fn local(self) -> Tm { + let mut tm = Tm { + tm_sec: 0, + tm_min: 0, + tm_hour: 0, + tm_mday: 0, + tm_mon: 0, + tm_year: 0, + tm_wday: 0, + tm_yday: 0, + tm_isdst: 0, + tm_utcoff: 0, + tm_nsec: 0, + }; + inner::time_to_local_tm(self.sec, &mut tm); + tm.tm_nsec = self.nsec; + tm + } +} + +/// Holds a calendar date and time broken down into its components (year, month, +/// day, and so on), also called a broken-down time value. +// FIXME: use c_int instead of i32? +#[cfg(feature = "clock")] +#[repr(C)] +pub struct Tm { + /// Seconds after the minute - [0, 60] + pub tm_sec: i32, + + /// Minutes after the hour - [0, 59] + pub tm_min: i32, + + /// Hours after midnight - [0, 23] + pub tm_hour: i32, + + /// Day of the month - [1, 31] + pub tm_mday: i32, + + /// Months since January - [0, 11] + pub tm_mon: i32, + + /// Years since 1900 + pub tm_year: i32, + + /// Days since Sunday - [0, 6]. 0 = Sunday, 1 = Monday, ..., 6 = Saturday. + pub tm_wday: i32, + + /// Days since January 1 - [0, 365] + pub tm_yday: i32, + + /// Daylight Saving Time flag. + /// + /// This value is positive if Daylight Saving Time is in effect, zero if + /// Daylight Saving Time is not in effect, and negative if this information + /// is not available. + pub tm_isdst: i32, + + /// Identifies the time zone that was used to compute this broken-down time + /// value, including any adjustment for Daylight Saving Time. This is the + /// number of seconds east of UTC. For example, for U.S. Pacific Daylight + /// Time, the value is `-7*60*60 = -25200`. + pub tm_utcoff: i32, + + /// Nanoseconds after the second - [0, 109 - 1] + pub tm_nsec: i32, +} + +impl Tm { + /// Convert time to the seconds from January 1, 1970 + pub fn to_timespec(&self) -> Timespec { + let sec = match self.tm_utcoff { + 0 => inner::utc_tm_to_time(self), + _ => inner::local_tm_to_time(self), + }; + Timespec { sec: sec, nsec: self.tm_nsec } + } +} diff --git a/src/sys/unix.rs b/src/sys/unix.rs new file mode 100644 index 0000000000..762e234054 --- /dev/null +++ b/src/sys/unix.rs @@ -0,0 +1,118 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::Tm; +use libc::{self, time_t}; +use std::io; +use std::mem; + +#[cfg(any(target_os = "solaris", target_os = "illumos"))] +extern "C" { + static timezone: time_t; + static altzone: time_t; +} + +fn rust_tm_to_tm(rust_tm: &Tm, tm: &mut libc::tm) { + tm.tm_sec = rust_tm.tm_sec; + tm.tm_min = rust_tm.tm_min; + tm.tm_hour = rust_tm.tm_hour; + tm.tm_mday = rust_tm.tm_mday; + tm.tm_mon = rust_tm.tm_mon; + tm.tm_year = rust_tm.tm_year; + tm.tm_wday = rust_tm.tm_wday; + tm.tm_yday = rust_tm.tm_yday; + tm.tm_isdst = rust_tm.tm_isdst; +} + +fn tm_to_rust_tm(tm: &libc::tm, utcoff: i32, rust_tm: &mut Tm) { + rust_tm.tm_sec = tm.tm_sec; + rust_tm.tm_min = tm.tm_min; + rust_tm.tm_hour = tm.tm_hour; + rust_tm.tm_mday = tm.tm_mday; + rust_tm.tm_mon = tm.tm_mon; + rust_tm.tm_year = tm.tm_year; + rust_tm.tm_wday = tm.tm_wday; + rust_tm.tm_yday = tm.tm_yday; + rust_tm.tm_isdst = tm.tm_isdst; + rust_tm.tm_utcoff = utcoff; +} + +#[cfg(any(target_os = "nacl", target_os = "solaris", target_os = "illumos"))] +unsafe fn timegm(tm: *mut libc::tm) -> time_t { + use std::env::{remove_var, set_var, var_os}; + extern "C" { + fn tzset(); + } + + let ret; + + let current_tz = var_os("TZ"); + set_var("TZ", "UTC"); + tzset(); + + ret = libc::mktime(tm); + + if let Some(tz) = current_tz { + set_var("TZ", tz); + } else { + remove_var("TZ"); + } + tzset(); + + ret +} + +pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { + unsafe { + let sec = sec as time_t; + let mut out = mem::zeroed(); + if libc::localtime_r(&sec, &mut out).is_null() { + panic!("localtime_r failed: {}", io::Error::last_os_error()); + } + #[cfg(any(target_os = "solaris", target_os = "illumos"))] + let gmtoff = { + ::tzset(); + // < 0 means we don't know; assume we're not in DST. + if out.tm_isdst == 0 { + // timezone is seconds west of UTC, tm_gmtoff is seconds east + -timezone + } else if out.tm_isdst > 0 { + -altzone + } else { + -timezone + } + }; + #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] + let gmtoff = out.tm_gmtoff; + tm_to_rust_tm(&out, gmtoff as i32, tm); + } +} + +pub fn utc_tm_to_time(rust_tm: &Tm) -> i64 { + #[cfg(not(any( + all(target_os = "android", target_pointer_width = "32"), + target_os = "nacl", + target_os = "solaris", + target_os = "illumos" + )))] + use libc::timegm; + #[cfg(all(target_os = "android", target_pointer_width = "32"))] + use libc::timegm64 as timegm; + + let mut tm = unsafe { mem::zeroed() }; + rust_tm_to_tm(rust_tm, &mut tm); + unsafe { timegm(&mut tm) as i64 } +} + +pub fn local_tm_to_time(rust_tm: &Tm) -> i64 { + let mut tm = unsafe { mem::zeroed() }; + rust_tm_to_tm(rust_tm, &mut tm); + unsafe { libc::mktime(&mut tm) as i64 } +} diff --git a/src/sys/wasm32.rs b/src/sys/wasm32.rs new file mode 100644 index 0000000000..9172a85223 --- /dev/null +++ b/src/sys/wasm32.rs @@ -0,0 +1,80 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::Tm; + +fn time_to_tm(ts: i64, tm: &mut Tm) { + let leapyear = |year| -> bool { year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) }; + + static YTAB: [[i64; 12]; 2] = [ + [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], + [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], + ]; + + let mut year = 1970; + + let dayclock = ts % 86400; + let mut dayno = ts / 86400; + + tm.tm_sec = (dayclock % 60) as i32; + tm.tm_min = ((dayclock % 3600) / 60) as i32; + tm.tm_hour = (dayclock / 3600) as i32; + tm.tm_wday = ((dayno + 4) % 7) as i32; + loop { + let yearsize = if leapyear(year) { 366 } else { 365 }; + if dayno >= yearsize { + dayno -= yearsize; + year += 1; + } else { + break; + } + } + tm.tm_year = (year - 1900) as i32; + tm.tm_yday = dayno as i32; + let mut mon = 0; + while dayno >= YTAB[if leapyear(year) { 1 } else { 0 }][mon] { + dayno -= YTAB[if leapyear(year) { 1 } else { 0 }][mon]; + mon += 1; + } + tm.tm_mon = mon as i32; + tm.tm_mday = dayno as i32 + 1; + tm.tm_isdst = 0; +} + +fn tm_to_time(tm: &Tm) -> i64 { + let mut y = tm.tm_year as i64 + 1900; + let mut m = tm.tm_mon as i64 + 1; + if m <= 2 { + y -= 1; + m += 12; + } + let d = tm.tm_mday as i64; + let h = tm.tm_hour as i64; + let mi = tm.tm_min as i64; + let s = tm.tm_sec as i64; + (365 * y + y / 4 - y / 100 + y / 400 + 3 * (m + 1) / 5 + 30 * m + d - 719561) * 86400 + + 3600 * h + + 60 * mi + + s +} + +pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { + // FIXME: Add timezone logic + time_to_tm(sec, tm); +} + +pub fn utc_tm_to_time(tm: &Tm) -> i64 { + tm_to_time(tm) +} + +pub fn local_tm_to_time(tm: &Tm) -> i64 { + // FIXME: Add timezone logic + tm_to_time(tm) +} diff --git a/src/sys/windows.rs b/src/sys/windows.rs new file mode 100644 index 0000000000..3f90338e41 --- /dev/null +++ b/src/sys/windows.rs @@ -0,0 +1,131 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::Tm; +use std::io; +use std::mem; + +use winapi::shared::minwindef::*; +use winapi::um::minwinbase::SYSTEMTIME; +use winapi::um::timezoneapi::*; + +const HECTONANOSECS_IN_SEC: i64 = 10_000_000; +const HECTONANOSEC_TO_UNIX_EPOCH: i64 = 11_644_473_600 * HECTONANOSECS_IN_SEC; + +fn time_to_file_time(sec: i64) -> FILETIME { + let t = ((sec * HECTONANOSECS_IN_SEC) + HECTONANOSEC_TO_UNIX_EPOCH) as u64; + FILETIME { dwLowDateTime: t as DWORD, dwHighDateTime: (t >> 32) as DWORD } +} + +fn file_time_as_u64(ft: &FILETIME) -> u64 { + ((ft.dwHighDateTime as u64) << 32) | (ft.dwLowDateTime as u64) +} + +fn file_time_to_unix_seconds(ft: &FILETIME) -> i64 { + let t = file_time_as_u64(ft) as i64; + ((t - HECTONANOSEC_TO_UNIX_EPOCH) / HECTONANOSECS_IN_SEC) as i64 +} + +fn system_time_to_file_time(sys: &SYSTEMTIME) -> FILETIME { + unsafe { + let mut ft = mem::zeroed(); + SystemTimeToFileTime(sys, &mut ft); + ft + } +} + +fn tm_to_system_time(tm: &Tm) -> SYSTEMTIME { + let mut sys: SYSTEMTIME = unsafe { mem::zeroed() }; + sys.wSecond = tm.tm_sec as WORD; + sys.wMinute = tm.tm_min as WORD; + sys.wHour = tm.tm_hour as WORD; + sys.wDay = tm.tm_mday as WORD; + sys.wDayOfWeek = tm.tm_wday as WORD; + sys.wMonth = (tm.tm_mon + 1) as WORD; + sys.wYear = (tm.tm_year + 1900) as WORD; + sys +} + +fn system_time_to_tm(sys: &SYSTEMTIME, tm: &mut Tm) { + tm.tm_sec = sys.wSecond as i32; + tm.tm_min = sys.wMinute as i32; + tm.tm_hour = sys.wHour as i32; + tm.tm_mday = sys.wDay as i32; + tm.tm_wday = sys.wDayOfWeek as i32; + tm.tm_mon = (sys.wMonth - 1) as i32; + tm.tm_year = (sys.wYear - 1900) as i32; + tm.tm_yday = yday(tm.tm_year, tm.tm_mon + 1, tm.tm_mday); + + fn yday(year: i32, month: i32, day: i32) -> i32 { + let leap = if month > 2 { + if year % 4 == 0 { + 1 + } else { + 2 + } + } else { + 0 + }; + let july = if month > 7 { 1 } else { 0 }; + + (month - 1) * 30 + month / 2 + (day - 1) - leap + july + } +} + +macro_rules! call { + ($name:ident($($arg:expr),*)) => { + if $name($($arg),*) == 0 { + panic!(concat!(stringify!($name), " failed with: {}"), + io::Error::last_os_error()); + } + } +} + +pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { + let ft = time_to_file_time(sec); + unsafe { + let mut utc = mem::zeroed(); + let mut local = mem::zeroed(); + call!(FileTimeToSystemTime(&ft, &mut utc)); + call!(SystemTimeToTzSpecificLocalTime(0 as *const _, &mut utc, &mut local)); + system_time_to_tm(&local, tm); + + let local = system_time_to_file_time(&local); + let local_sec = file_time_to_unix_seconds(&local); + + let mut tz = mem::zeroed(); + GetTimeZoneInformation(&mut tz); + + // SystemTimeToTzSpecificLocalTime already applied the biases so + // check if it non standard + tm.tm_utcoff = (local_sec - sec) as i32; + tm.tm_isdst = if tm.tm_utcoff == -60 * (tz.Bias + tz.StandardBias) { 0 } else { 1 }; + } +} + +pub fn utc_tm_to_time(tm: &Tm) -> i64 { + unsafe { + let mut ft = mem::zeroed(); + let sys_time = tm_to_system_time(tm); + call!(SystemTimeToFileTime(&sys_time, &mut ft)); + file_time_to_unix_seconds(&ft) + } +} + +pub fn local_tm_to_time(tm: &Tm) -> i64 { + unsafe { + let mut ft = mem::zeroed(); + let mut utc = mem::zeroed(); + let mut sys_time = tm_to_system_time(tm); + call!(TzSpecificLocalTimeToSystemTime(0 as *mut _, &mut sys_time, &mut utc)); + call!(SystemTimeToFileTime(&utc, &mut ft)); + file_time_to_unix_seconds(&ft) + } +}