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..495ea1a2ff 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"] +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"] } + [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..e288bdbfe0 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,18 @@ 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(all(feature = "clock"))] +extern crate libc; +#[cfg(all(feature = "clock", windows))] +extern crate winapi; +#[cfg(all(feature = "clock"))] +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..2e09a4b206 100644 --- a/src/offset/local.rs +++ b/src/offset/local.rs @@ -3,7 +3,7 @@ //! The local (system) time zone. -use oldtime; +use sys::{self, Timespec}; use super::fixed::FixedOffset; use super::{LocalResult, TimeZone}; @@ -17,20 +17,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 +48,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 +98,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. @@ -151,7 +151,7 @@ impl TimeZone for Local { let mut local = local.clone(); // Get the offset from the js runtime let offset = FixedOffset::west((js_sys::Date::new_0().get_timezone_offset() as i32) * 60); - local -= oldtime::Duration::seconds(offset.local_minus_utc() as i64); + local -= Duration::seconds(offset.local_minus_utc() as i64); LocalResult::Single(DateTime::from_utc(local, offset)) } @@ -160,7 +160,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 +184,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..1929ca9676 100644 --- a/src/offset/utc.rs +++ b/src/offset/utc.rs @@ -5,14 +5,14 @@ use core::fmt; #[cfg(all( - feature = "clock", + feature = "std", not(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind")) ))] -use oldtime; +use std::time::SystemTime; use super::{FixedOffset, LocalResult, Offset, TimeZone}; use naive::{NaiveDate, NaiveDateTime}; -#[cfg(feature = "clock")] +#[cfg(feature = "std")] use {Date, DateTime}; /// The UTC time zone. This is the most efficient time zone when you don't need the local time. @@ -35,7 +35,7 @@ use {Date, DateTime}; #[derive(Copy, Clone, PartialEq, Eq)] pub struct Utc; -#[cfg(feature = "clock")] +#[cfg(feature = "std")] impl Utc { /// Returns a `Date` which corresponds to the current date. pub fn today() -> Date { @@ -45,8 +45,10 @@ 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(SystemTime::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) + } +}