diff options
Diffstat (limited to 'vendor/time/src/lib.rs')
-rw-r--r-- | vendor/time/src/lib.rs | 1567 |
1 files changed, 321 insertions, 1246 deletions
diff --git a/vendor/time/src/lib.rs b/vendor/time/src/lib.rs index 07c38e406..b9868c178 100644 --- a/vendor/time/src/lib.rs +++ b/vendor/time/src/lib.rs @@ -1,1282 +1,357 @@ -// Copyright 2012-2013 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Simple time handling. +//! # Feature flags //! -//! # Usage +//! This crate exposes a number of features. These can be enabled or disabled as shown +//! [in Cargo's documentation](https://doc.rust-lang.org/cargo/reference/features.html). Features +//! are _disabled_ by default unless otherwise noted. //! -//! This crate is [on crates.io](https://crates.io/crates/time) and can be -//! used by adding `time` to the dependencies in your project's `Cargo.toml`. +//! Reliance on a given feature is always indicated alongside the item definition. //! -//! ```toml -//! [dependencies] -//! time = "0.1" -//! ``` +//! - `std` (_enabled by default, implicitly enables `alloc`_) //! -//! And this in your crate root: +//! This enables a number of features that depend on the standard library. //! -//! ```rust -//! extern crate time; -//! ``` +//! - `alloc` (_enabled by default via `std`_) //! -//! This crate uses the same syntax for format strings as the -//! [`strftime()`](http://man7.org/linux/man-pages/man3/strftime.3.html) -//! function from the C standard library. - -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://www.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/time/")] -#![allow(unknown_lints)] -#![allow(ellipsis_inclusive_range_patterns)] // `..=` requires Rust 1.26 -#![allow(trivial_numeric_casts)] -#![cfg_attr(test, deny(warnings))] - -#[cfg(unix)] extern crate libc; -#[cfg(windows)] extern crate winapi; -#[cfg(feature = "rustc-serialize")] extern crate rustc_serialize; - -#[cfg(test)] #[macro_use] extern crate log; - -use std::cmp::Ordering; -use std::error::Error; -use std::fmt; -use std::ops::{Add, Sub}; - -pub use duration::{Duration, OutOfRangeError}; - -use self::ParseError::{InvalidDay, InvalidDayOfMonth, InvalidDayOfWeek, - InvalidDayOfYear, InvalidFormatSpecifier, InvalidHour, - InvalidMinute, InvalidMonth, InvalidSecond, InvalidTime, - InvalidYear, InvalidZoneOffset, InvalidSecondsSinceEpoch, - MissingFormatConverter, UnexpectedCharacter}; - -pub use parse::strptime; - -mod display; -mod duration; -mod parse; -mod sys; - -static NSEC_PER_SEC: i32 = 1_000_000_000; - -/// 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}. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] -pub struct Timespec { pub sec: i64, pub nsec: i32 } -/* - * Timespec assumes that pre-epoch Timespecs have negative sec and positive - * nsec fields. Darwin's and Linux's struct timespec functions handle pre- - * epoch timestamps using a "two steps back, one step forward" representation, - * though the man pages do not actually document this. For example, the time - * -1.2 seconds before the epoch is represented by `Timespec { sec: -2_i64, - * nsec: 800_000_000 }`. - */ -impl Timespec { - pub fn new(sec: i64, nsec: i32) -> Timespec { - assert!(nsec >= 0 && nsec < NSEC_PER_SEC); - Timespec { sec: sec, nsec: nsec } - } -} - -impl Add<Duration> for Timespec { - type Output = Timespec; - - fn add(self, other: Duration) -> Timespec { - let d_sec = other.num_seconds(); - // It is safe to unwrap the nanoseconds, because there cannot be - // more than one second left, which fits in i64 and in i32. - let d_nsec = (other - Duration::seconds(d_sec)) - .num_nanoseconds().unwrap() as i32; - let mut sec = self.sec + d_sec; - let mut nsec = self.nsec + d_nsec; - if nsec >= NSEC_PER_SEC { - nsec -= NSEC_PER_SEC; - sec += 1; - } else if nsec < 0 { - nsec += NSEC_PER_SEC; - sec -= 1; - } - Timespec::new(sec, nsec) - } -} - -impl Sub<Duration> for Timespec { - type Output = Timespec; - - fn sub(self, other: Duration) -> Timespec { - let d_sec = other.num_seconds(); - // It is safe to unwrap the nanoseconds, because there cannot be - // more than one second left, which fits in i64 and in i32. - let d_nsec = (other - Duration::seconds(d_sec)) - .num_nanoseconds().unwrap() as i32; - let mut sec = self.sec - d_sec; - let mut nsec = self.nsec - d_nsec; - if nsec >= NSEC_PER_SEC { - nsec -= NSEC_PER_SEC; - sec += 1; - } else if nsec < 0 { - nsec += NSEC_PER_SEC; - sec -= 1; +//! Enables a number of features that require the ability to dynamically allocate memory. +//! +//! - `macros` +//! +//! Enables macros that provide compile-time verification of values and intuitive syntax. +//! +//! - `formatting` (_implicitly enables `std`_) +//! +//! Enables formatting of most structs. +//! +//! - `parsing` +//! +//! Enables parsing of most structs. +//! +//! - `local-offset` (_implicitly enables `std`_) +//! +//! This feature enables a number of methods that allow obtaining the system's UTC offset. +//! +//! - `large-dates` +//! +//! By default, only years within the ±9999 range (inclusive) are supported. If you need support +//! for years outside this range, consider enabling this feature; the supported range will be +//! increased to ±999,999. +//! +//! Note that enabling this feature has some costs, as it means forgoing some optimizations. +//! Ambiguities may be introduced when parsing that would not otherwise exist. +//! +//! - `serde` +//! +//! Enables [serde](https://docs.rs/serde) support for all types except [`Instant`]. +//! +//! - `serde-human-readable` (_implicitly enables `serde`, `formatting`, and `parsing`_) +//! +//! Allows serde representations to use a human-readable format. This is determined by the +//! serializer, not the user. If this feature is not enabled or if the serializer requests a +//! non-human-readable format, a format optimized for binary representation will be used. +//! +//! Libraries should never enable this feature, as the decision of what format to use should be up +//! to the user. +//! +//! - `serde-well-known` (_implicitly enables `serde-human-readable`_) +//! +//! _This feature flag is deprecated and will be removed in a future breaking release. Use the +//! `serde-human-readable` feature instead._ +//! +//! Enables support for serializing and deserializing well-known formats using serde's +//! [`#[with]` attribute](https://serde.rs/field-attrs.html#with). +//! +//! - `rand` +//! +//! Enables [rand](https://docs.rs/rand) support for all types. +//! +//! - `quickcheck` (_implicitly enables `alloc`_) +//! +//! Enables [quickcheck](https://docs.rs/quickcheck) support for all types except [`Instant`]. +//! +//! - `wasm-bindgen` +//! +//! Enables [wasm-bindgen](https://github.com/rustwasm/wasm-bindgen) support for converting +//! [JavaScript dates](https://rustwasm.github.io/wasm-bindgen/api/js_sys/struct.Date.html), as +//! well as obtaining the UTC offset from JavaScript. +//! +//! <small> +//! One feature only available to end users is the <code>unsound_local_offset</code> cfg. This +//! enables obtaining the system's UTC offset even when it is unsound. To enable this, use the +//! <code>RUSTFLAGS</code> environment variable. This is untested and officially unsupported. Do not +//! use this unless you understand the risk. +//! </small> + +#![doc(html_playground_url = "https://play.rust-lang.org")] +#![cfg_attr(__time_03_docs, feature(doc_auto_cfg, doc_notable_trait))] +#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + anonymous_parameters, + clippy::all, + clippy::alloc_instead_of_core, + clippy::explicit_auto_deref, + clippy::obfuscated_if_else, + clippy::std_instead_of_core, + clippy::undocumented_unsafe_blocks, + const_err, + illegal_floating_point_literal_pattern, + late_bound_lifetime_arguments, + path_statements, + patterns_in_fns_without_body, + rust_2018_idioms, + trivial_casts, + trivial_numeric_casts, + unreachable_pub, + unsafe_op_in_unsafe_fn, + unused_extern_crates, + rustdoc::broken_intra_doc_links, + rustdoc::private_intra_doc_links +)] +#![warn( + clippy::dbg_macro, + clippy::decimal_literal_representation, + clippy::get_unwrap, + clippy::missing_docs_in_private_items, + clippy::nursery, + clippy::print_stdout, + clippy::todo, + clippy::unimplemented, + clippy::unnested_or_patterns, + clippy::unwrap_in_result, + clippy::unwrap_used, + clippy::use_debug, + deprecated_in_future, + missing_copy_implementations, + missing_debug_implementations, + unused_qualifications, + variant_size_differences +)] +#![allow( + clippy::redundant_pub_crate, // suggests bad style + clippy::option_if_let_else, // suggests terrible code + clippy::unused_peekable, // temporary due to bug: remove when Rust 1.66 is released + clippy::std_instead_of_core, // temporary due to bug: remove when Rust 1.66 is released +)] +#![doc(html_favicon_url = "https://avatars0.githubusercontent.com/u/55999857")] +#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/55999857")] +#![doc(test(attr(deny(warnings))))] + +#[allow(unused_extern_crates)] +#[cfg(feature = "alloc")] +extern crate alloc; + +// region: macros +/// Helper macro for easily implementing `OpAssign`. +macro_rules! __impl_assign { + ($sym:tt $op:ident $fn:ident $target:ty : $($(#[$attr:meta])* $t:ty),+) => {$( + #[allow(unused_qualifications)] + $(#[$attr])* + impl core::ops::$op<$t> for $target { + fn $fn(&mut self, rhs: $t) { + *self = *self $sym rhs; + } } - Timespec::new(sec, nsec) - } -} - -impl Sub<Timespec> for Timespec { - type Output = Duration; - - fn sub(self, other: Timespec) -> Duration { - let sec = self.sec - other.sec; - let nsec = self.nsec - other.nsec; - Duration::seconds(sec) + Duration::nanoseconds(nsec as i64) - } -} - -/** - * Returns the current time as a `timespec` containing the seconds and - * nanoseconds since 1970-01-01T00:00:00Z. - */ -pub fn get_time() -> Timespec { - let (sec, nsec) = sys::get_time(); - Timespec::new(sec, nsec) -} - - -/** - * Returns the current value of a high-resolution performance counter - * in nanoseconds since an unspecified epoch. - */ -#[inline] -pub fn precise_time_ns() -> u64 { - sys::get_precise_ns() -} - - -/** - * Returns the current value of a high-resolution performance counter - * in seconds since an unspecified epoch. - */ -pub fn precise_time_s() -> f64 { - return (precise_time_ns() as f64) / 1000000000.; -} - -/// An opaque structure representing a moment in time. -/// -/// The only operation that can be performed on a `PreciseTime` is the -/// calculation of the `Duration` of time that lies between them. -/// -/// # Examples -/// -/// Repeatedly call a function for 1 second: -/// -/// ```rust -/// use time::{Duration, PreciseTime}; -/// # fn do_some_work() {} -/// -/// let start = PreciseTime::now(); -/// -/// while start.to(PreciseTime::now()) < Duration::seconds(1) { -/// do_some_work(); -/// } -/// ``` -#[derive(Copy, Clone)] -pub struct PreciseTime(u64); - -impl PreciseTime { - /// Returns a `PreciseTime` representing the current moment in time. - pub fn now() -> PreciseTime { - PreciseTime(precise_time_ns()) - } - - /// Returns a `Duration` representing the span of time from the value of - /// `self` to the value of `later`. - /// - /// # Notes - /// - /// If `later` represents a time before `self`, the result of this method - /// is unspecified. - /// - /// If `later` represents a time more than 293 years after `self`, the - /// result of this method is unspecified. - #[inline] - pub fn to(&self, later: PreciseTime) -> Duration { - // NB: even if later is less than self due to overflow, this will work - // since the subtraction will underflow properly as well. - // - // We could deal with the overflow when casting to an i64, but all that - // gets us is the ability to handle intervals of up to 584 years, which - // seems not very useful :) - Duration::nanoseconds((later.0 - self.0) as i64) - } -} - -/// A structure representing a moment in time. -/// -/// `SteadyTime`s are generated by a "steady" clock, that is, a clock which -/// never experiences discontinuous jumps and for which time always flows at -/// the same rate. -/// -/// # Examples -/// -/// Repeatedly call a function for 1 second: -/// -/// ```rust -/// # use time::{Duration, SteadyTime}; -/// # fn do_some_work() {} -/// let start = SteadyTime::now(); -/// -/// while SteadyTime::now() - start < Duration::seconds(1) { -/// do_some_work(); -/// } -/// ``` -#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug)] -pub struct SteadyTime(sys::SteadyTime); - -impl SteadyTime { - /// Returns a `SteadyTime` representing the current moment in time. - pub fn now() -> SteadyTime { - SteadyTime(sys::SteadyTime::now()) - } -} - -impl fmt::Display for SteadyTime { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - // TODO: needs a display customization - fmt::Debug::fmt(self, fmt) - } -} - -impl Sub for SteadyTime { - type Output = Duration; - - fn sub(self, other: SteadyTime) -> Duration { - self.0 - other.0 - } -} - -impl Sub<Duration> for SteadyTime { - type Output = SteadyTime; - - fn sub(self, other: Duration) -> SteadyTime { - SteadyTime(self.0 - other) - } -} - -impl Add<Duration> for SteadyTime { - type Output = SteadyTime; - - fn add(self, other: Duration) -> SteadyTime { - SteadyTime(self.0 + other) - } -} - -#[cfg(not(any(windows, target_env = "sgx")))] -pub fn tzset() { - extern { fn tzset(); } - unsafe { tzset() } -} - - -#[cfg(any(windows, target_env = "sgx"))] -pub fn tzset() {} - -/// 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? -#[repr(C)] -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] -#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] -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, 10<sup>9</sup> - 1] - pub tm_nsec: i32, -} - -impl Add<Duration> for Tm { - type Output = Tm; - - /// The resulting Tm is in UTC. - // FIXME: The resulting Tm should have the same timezone as `self`; - // however, we need a function such as `at_tm(clock: Timespec, offset: i32)` - // for this. - fn add(self, other: Duration) -> Tm { - at_utc(self.to_timespec() + other) - } -} - -impl Sub<Duration> for Tm { - type Output = Tm; - - /// The resulting Tm is in UTC. - // FIXME: The resulting Tm should have the same timezone as `self`; - // however, we need a function such as `at_tm(clock: Timespec, offset: i32)` - // for this. - fn sub(self, other: Duration) -> Tm { - at_utc(self.to_timespec() - other) - } -} - -impl Sub<Tm> for Tm { - type Output = Duration; - - fn sub(self, other: Tm) -> Duration { - self.to_timespec() - other.to_timespec() - } -} - -impl PartialOrd for Tm { - fn partial_cmp(&self, other: &Tm) -> Option<Ordering> { - self.to_timespec().partial_cmp(&other.to_timespec()) - } -} - -impl Ord for Tm { - fn cmp(&self, other: &Tm) -> Ordering { - self.to_timespec().cmp(&other.to_timespec()) - } -} - -pub fn empty_tm() -> 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, - } + )+}; } -/// Returns the specified time in UTC -pub fn at_utc(clock: Timespec) -> Tm { - let Timespec { sec, nsec } = clock; - let mut tm = empty_tm(); - sys::time_to_utc_tm(sec, &mut tm); - tm.tm_nsec = nsec; - tm +/// Implement `AddAssign` for the provided types. +macro_rules! impl_add_assign { + ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => { + __impl_assign!(+ AddAssign add_assign $target : $($(#[$attr])* $t),+); + }; } -/// Returns the current time in UTC -pub fn now_utc() -> Tm { - at_utc(get_time()) +/// Implement `SubAssign` for the provided types. +macro_rules! impl_sub_assign { + ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => { + __impl_assign!(- SubAssign sub_assign $target : $($(#[$attr])* $t),+); + }; } -/// Returns the specified time in the local timezone -pub fn at(clock: Timespec) -> Tm { - let Timespec { sec, nsec } = clock; - let mut tm = empty_tm(); - sys::time_to_local_tm(sec, &mut tm); - tm.tm_nsec = nsec; - tm +/// Implement `MulAssign` for the provided types. +macro_rules! impl_mul_assign { + ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => { + __impl_assign!(* MulAssign mul_assign $target : $($(#[$attr])* $t),+); + }; } -/// Returns the current time in the local timezone -pub fn now() -> Tm { - at(get_time()) +/// Implement `DivAssign` for the provided types. +macro_rules! impl_div_assign { + ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => { + __impl_assign!(/ DivAssign div_assign $target : $($(#[$attr])* $t),+); + }; } -impl Tm { - /// Convert time to the seconds from January 1, 1970 - pub fn to_timespec(&self) -> Timespec { - let sec = match self.tm_utcoff { - 0 => sys::utc_tm_to_time(self), - _ => sys::local_tm_to_time(self) - }; - - Timespec::new(sec, self.tm_nsec) - } +/// Division of integers, rounding the resulting value towards negative infinity. +macro_rules! div_floor { + ($a:expr, $b:expr) => {{ + let _a = $a; + let _b = $b; - /// Convert time to the local timezone - pub fn to_local(&self) -> Tm { - at(self.to_timespec()) - } + let (_quotient, _remainder) = (_a / _b, _a % _b); - /// Convert time to the UTC - pub fn to_utc(&self) -> Tm { - match self.tm_utcoff { - 0 => *self, - _ => at_utc(self.to_timespec()) - } - } - - /** - * Returns a TmFmt that outputs according to the `asctime` format in ISO - * C, in the local timezone. - * - * Example: "Thu Jan 1 00:00:00 1970" - */ - pub fn ctime(&self) -> TmFmt { - TmFmt { - tm: self, - format: Fmt::Ctime, + if (_remainder > 0 && _b < 0) || (_remainder < 0 && _b > 0) { + _quotient - 1 + } else { + _quotient } - } - - /** - * Returns a TmFmt that outputs according to the `asctime` format in ISO - * C. - * - * Example: "Thu Jan 1 00:00:00 1970" - */ - pub fn asctime(&self) -> TmFmt { - TmFmt { - tm: self, - format: Fmt::Str("%c"), + }}; +} + +/// Cascade an out-of-bounds value. +macro_rules! cascade { + (@ordinal ordinal) => {}; + (@year year) => {}; + + // Cascade an out-of-bounds value from "from" to "to". + ($from:ident in $min:literal.. $max:literal => $to:tt) => { + #[allow(unused_comparisons, unused_assignments)] + if $from >= $max { + $from -= $max - $min; + $to += 1; + } else if $from < $min { + $from += $max - $min; + $to -= 1; } - } - - /// Formats the time according to the format string. - pub fn strftime<'a>(&'a self, format: &'a str) -> Result<TmFmt<'a>, ParseError> { - validate_format(TmFmt { - tm: self, - format: Fmt::Str(format), - }) - } - - /** - * Returns a TmFmt that outputs according to RFC 822. - * - * local: "Thu, 22 Mar 2012 07:53:18 PST" - * utc: "Thu, 22 Mar 2012 14:53:18 GMT" - */ - pub fn rfc822(&self) -> TmFmt { - let fmt = if self.tm_utcoff == 0 { - "%a, %d %b %Y %T GMT" - } else { - "%a, %d %b %Y %T %Z" - }; - TmFmt { - tm: self, - format: Fmt::Str(fmt), + }; + + // Special case the ordinal-to-year cascade, as it has different behavior. + ($ordinal:ident => $year:ident) => { + // We need to actually capture the idents. Without this, macro hygiene causes errors. + cascade!(@ordinal $ordinal); + cascade!(@year $year); + #[allow(unused_assignments)] + if $ordinal > crate::util::days_in_year($year) as i16 { + $ordinal -= crate::util::days_in_year($year) as i16; + $year += 1; + } else if $ordinal < 1 { + $year -= 1; + $ordinal += crate::util::days_in_year($year) as i16; } - } - - /** - * Returns a TmFmt that outputs according to RFC 822 with Zulu time. - * - * local: "Thu, 22 Mar 2012 07:53:18 -0700" - * utc: "Thu, 22 Mar 2012 14:53:18 -0000" - */ - pub fn rfc822z(&self) -> TmFmt { - TmFmt { - tm: self, - format: Fmt::Str("%a, %d %b %Y %T %z"), + }; +} + +/// Returns `Err(error::ComponentRange)` if the value is not in range. +macro_rules! ensure_value_in_range { + ($value:ident in $start:expr => $end:expr) => {{ + let _start = $start; + let _end = $end; + #[allow(trivial_numeric_casts, unused_comparisons)] + if $value < _start || $value > _end { + return Err(crate::error::ComponentRange { + name: stringify!($value), + minimum: _start as _, + maximum: _end as _, + value: $value as _, + conditional_range: false, + }); } - } - - /** - * Returns a TmFmt that outputs according to RFC 3339. RFC 3339 is - * compatible with ISO 8601. - * - * local: "2012-02-22T07:53:18-07:00" - * utc: "2012-02-22T14:53:18Z" - */ - pub fn rfc3339<'a>(&'a self) -> TmFmt { - TmFmt { - tm: self, - format: Fmt::Rfc3339, + }}; + + ($value:ident conditionally in $start:expr => $end:expr) => {{ + let _start = $start; + let _end = $end; + #[allow(trivial_numeric_casts, unused_comparisons)] + if $value < _start || $value > _end { + return Err(crate::error::ComponentRange { + name: stringify!($value), + minimum: _start as _, + maximum: _end as _, + value: $value as _, + conditional_range: true, + }); } - } -} - -#[derive(Copy, PartialEq, Debug, Clone)] -pub enum ParseError { - InvalidSecond, - InvalidMinute, - InvalidHour, - InvalidDay, - InvalidMonth, - InvalidYear, - InvalidDayOfWeek, - InvalidDayOfMonth, - InvalidDayOfYear, - InvalidZoneOffset, - InvalidTime, - InvalidSecondsSinceEpoch, - MissingFormatConverter, - InvalidFormatSpecifier(char), - UnexpectedCharacter(char, char), + }}; } -impl fmt::Display for ParseError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - #[allow(deprecated)] - match *self { - InvalidFormatSpecifier(ch) => { - write!(f, "{}: %{}", self.description(), ch) - } - UnexpectedCharacter(a, b) => { - write!(f, "expected: `{}`, found: `{}`", a, b) - } - _ => write!(f, "{}", self.description()) +/// Try to unwrap an expression, returning if not possible. +/// +/// This is similar to the `?` operator, but does not perform `.into()`. Because of this, it is +/// usable in `const` contexts. +macro_rules! const_try { + ($e:expr) => { + match $e { + Ok(value) => value, + Err(error) => return Err(error), } - } + }; } -impl Error for ParseError { - fn description(&self) -> &str { - match *self { - InvalidSecond => "Invalid second.", - InvalidMinute => "Invalid minute.", - InvalidHour => "Invalid hour.", - InvalidDay => "Invalid day.", - InvalidMonth => "Invalid month.", - InvalidYear => "Invalid year.", - InvalidDayOfWeek => "Invalid day of the week.", - InvalidDayOfMonth => "Invalid day of the month.", - InvalidDayOfYear => "Invalid day of the year.", - InvalidZoneOffset => "Invalid zone offset.", - InvalidTime => "Invalid time.", - InvalidSecondsSinceEpoch => "Invalid seconds since epoch.", - MissingFormatConverter => "missing format converter after `%`", - InvalidFormatSpecifier(..) => "invalid format specifier", - UnexpectedCharacter(..) => "Unexpected character.", +/// Try to unwrap an expression, returning if not possible. +/// +/// This is similar to the `?` operator, but is usable in `const` contexts. +macro_rules! const_try_opt { + ($e:expr) => { + match $e { + Some(value) => value, + None => return None, } - } -} - -/// A wrapper around a `Tm` and format string that implements Display. -#[derive(Debug)] -pub struct TmFmt<'a> { - tm: &'a Tm, - format: Fmt<'a> -} - -#[derive(Debug)] -enum Fmt<'a> { - Str(&'a str), - Rfc3339, - Ctime, -} - -fn validate_format<'a>(fmt: TmFmt<'a>) -> Result<TmFmt<'a>, ParseError> { - - match (fmt.tm.tm_wday, fmt.tm.tm_mon) { - (0...6, 0...11) => (), - (_wday, 0...11) => return Err(InvalidDayOfWeek), - (0...6, _mon) => return Err(InvalidMonth), - _ => return Err(InvalidDay) - } - match fmt.format { - Fmt::Str(ref s) => { - let mut chars = s.chars(); - loop { - match chars.next() { - Some('%') => { - match chars.next() { - Some('A') | Some('a') | Some('B') | Some('b') | - Some('C') | Some('c') | Some('D') | Some('d') | - Some('e') | Some('F') | Some('f') | Some('G') | - Some('g') | Some('H') | Some('h') | Some('I') | - Some('j') | Some('k') | Some('l') | Some('M') | - Some('m') | Some('n') | Some('P') | Some('p') | - Some('R') | Some('r') | Some('S') | Some('s') | - Some('T') | Some('t') | Some('U') | Some('u') | - Some('V') | Some('v') | Some('W') | Some('w') | - Some('X') | Some('x') | Some('Y') | Some('y') | - Some('Z') | Some('z') | Some('+') | Some('%') => (), - - Some(c) => return Err(InvalidFormatSpecifier(c)), - None => return Err(MissingFormatConverter), - } - }, - None => break, - _ => () - } - } - }, - _ => () - } - Ok(fmt) + }; } -/// Formats the time according to the format string. -pub fn strftime(format: &str, tm: &Tm) -> Result<String, ParseError> { - tm.strftime(format).map(|fmt| fmt.to_string()) +/// Try to unwrap an expression, panicking if not possible. +/// +/// This is similar to `$e.expect($message)`, but is usable in `const` contexts. +macro_rules! expect_opt { + ($e:expr, $message:literal) => { + match $e { + Some(value) => value, + None => crate::expect_failed($message), + } + }; } +// endregion macros +mod date; +mod duration; +pub mod error; +pub mod ext; +#[cfg(any(feature = "formatting", feature = "parsing"))] +pub mod format_description; +#[cfg(feature = "formatting")] +pub mod formatting; +#[cfg(feature = "std")] +mod instant; +#[cfg(feature = "macros")] +pub mod macros; +mod month; +mod offset_date_time; +#[cfg(feature = "parsing")] +pub mod parsing; +mod primitive_date_time; +#[cfg(feature = "quickcheck")] +mod quickcheck; +#[cfg(feature = "rand")] +mod rand; +#[cfg(feature = "serde")] +#[allow(missing_copy_implementations, missing_debug_implementations)] +pub mod serde; +mod sys; #[cfg(test)] -mod tests { - use super::{Timespec, get_time, precise_time_ns, precise_time_s, - at_utc, at, strptime, PreciseTime, SteadyTime, ParseError, Duration}; - use super::ParseError::{InvalidTime, InvalidYear, MissingFormatConverter, - InvalidFormatSpecifier}; - - #[allow(deprecated)] // `Once::new` is const starting in Rust 1.32 - use std::sync::ONCE_INIT; - use std::sync::{Once, Mutex, MutexGuard, LockResult}; - use std::i32; - use std::mem; - - struct TzReset { - _tzreset: ::sys::TzReset, - _lock: LockResult<MutexGuard<'static, ()>>, - } - - fn set_time_zone_la_or_london(london: bool) -> TzReset { - // Lock manages current timezone because some tests require LA some - // London - static mut LOCK: *mut Mutex<()> = 0 as *mut _; - #[allow(deprecated)] // `Once::new` is const starting in Rust 1.32 - static INIT: Once = ONCE_INIT; - - unsafe { - INIT.call_once(|| { - LOCK = mem::transmute(Box::new(Mutex::new(()))); - }); - - let timezone_lock = (*LOCK).lock(); - let reset_func = if london { - ::sys::set_london_with_dst_time_zone() - } else { - ::sys::set_los_angeles_time_zone() - }; - TzReset { - _lock: timezone_lock, - _tzreset: reset_func, - } - } - } - - fn set_time_zone() -> TzReset { - set_time_zone_la_or_london(false) - } - - fn set_time_zone_london_dst() -> TzReset { - set_time_zone_la_or_london(true) - } - - #[test] - fn test_get_time() { - static SOME_RECENT_DATE: i64 = 1577836800i64; // 2020-01-01T00:00:00Z - static SOME_FUTURE_DATE: i64 = i32::MAX as i64; // Y2038 - - let tv1 = get_time(); - debug!("tv1={} sec + {} nsec", tv1.sec, tv1.nsec); - - assert!(tv1.sec > SOME_RECENT_DATE); - assert!(tv1.nsec < 1000000000i32); - - let tv2 = get_time(); - debug!("tv2={} sec + {} nsec", tv2.sec, tv2.nsec); - - assert!(tv2.sec >= tv1.sec); - assert!(tv2.sec < SOME_FUTURE_DATE); - assert!(tv2.nsec < 1000000000i32); - if tv2.sec == tv1.sec { - assert!(tv2.nsec >= tv1.nsec); - } - } - - #[test] - fn test_precise_time() { - let s0 = precise_time_s(); - debug!("s0={} sec", s0); - assert!(s0 > 0.); - - let ns0 = precise_time_ns(); - let ns1 = precise_time_ns(); - debug!("ns0={} ns", ns0); - debug!("ns1={} ns", ns1); - assert!(ns1 >= ns0); - - let ns2 = precise_time_ns(); - debug!("ns2={} ns", ns2); - assert!(ns2 >= ns1); - } - - #[test] - fn test_precise_time_to() { - let t0 = PreciseTime(1000); - let t1 = PreciseTime(1023); - assert_eq!(Duration::nanoseconds(23), t0.to(t1)); - } - - #[test] - fn test_at_utc() { - let _reset = set_time_zone(); - - let time = Timespec::new(1234567890, 54321); - let utc = at_utc(time); - - assert_eq!(utc.tm_sec, 30); - assert_eq!(utc.tm_min, 31); - assert_eq!(utc.tm_hour, 23); - assert_eq!(utc.tm_mday, 13); - assert_eq!(utc.tm_mon, 1); - assert_eq!(utc.tm_year, 109); - assert_eq!(utc.tm_wday, 5); - assert_eq!(utc.tm_yday, 43); - assert_eq!(utc.tm_isdst, 0); - assert_eq!(utc.tm_utcoff, 0); - assert_eq!(utc.tm_nsec, 54321); - } - - #[test] - fn test_at() { - let _reset = set_time_zone(); - - let time = Timespec::new(1234567890, 54321); - let local = at(time); - - debug!("time_at: {:?}", local); - - assert_eq!(local.tm_sec, 30); - assert_eq!(local.tm_min, 31); - assert_eq!(local.tm_hour, 15); - assert_eq!(local.tm_mday, 13); - assert_eq!(local.tm_mon, 1); - assert_eq!(local.tm_year, 109); - assert_eq!(local.tm_wday, 5); - assert_eq!(local.tm_yday, 43); - assert_eq!(local.tm_isdst, 0); - assert_eq!(local.tm_utcoff, -28800); - assert_eq!(local.tm_nsec, 54321); - } - - #[test] - fn test_to_timespec() { - let _reset = set_time_zone(); - - let time = Timespec::new(1234567890, 54321); - let utc = at_utc(time); - - assert_eq!(utc.to_timespec(), time); - assert_eq!(utc.to_local().to_timespec(), time); - } - - #[test] - fn test_conversions() { - let _reset = set_time_zone(); - - let time = Timespec::new(1234567890, 54321); - let utc = at_utc(time); - let local = at(time); - - assert!(local.to_local() == local); - assert!(local.to_utc() == utc); - assert!(local.to_utc().to_local() == local); - assert!(utc.to_utc() == utc); - assert!(utc.to_local() == local); - assert!(utc.to_local().to_utc() == utc); - } - - #[test] - fn test_strptime() { - let _reset = set_time_zone(); - - match strptime("", "") { - Ok(ref tm) => { - assert!(tm.tm_sec == 0); - assert!(tm.tm_min == 0); - assert!(tm.tm_hour == 0); - assert!(tm.tm_mday == 0); - assert!(tm.tm_mon == 0); - assert!(tm.tm_year == 0); - assert!(tm.tm_wday == 0); - assert!(tm.tm_isdst == 0); - assert!(tm.tm_utcoff == 0); - assert!(tm.tm_nsec == 0); - } - Err(_) => () - } - - let format = "%a %b %e %T.%f %Y"; - assert_eq!(strptime("", format), Err(ParseError::InvalidDay)); - assert_eq!(strptime("Fri Feb 13 15:31:30", format), - Err(InvalidTime)); - - match strptime("Fri Feb 13 15:31:30.01234 2009", format) { - Err(e) => panic!("{}", e), - Ok(ref tm) => { - assert_eq!(tm.tm_sec, 30); - assert_eq!(tm.tm_min, 31); - assert_eq!(tm.tm_hour, 15); - assert_eq!(tm.tm_mday, 13); - assert_eq!(tm.tm_mon, 1); - assert_eq!(tm.tm_year, 109); - assert_eq!(tm.tm_wday, 5); - assert_eq!(tm.tm_yday, 0); - assert_eq!(tm.tm_isdst, 0); - assert_eq!(tm.tm_utcoff, 0); - assert_eq!(tm.tm_nsec, 12340000); - } - } - - fn test(s: &str, format: &str) -> bool { - match strptime(s, format) { - Ok(tm) => { - tm.strftime(format).unwrap().to_string() == s.to_string() - }, - Err(e) => panic!("{:?}, s={:?}, format={:?}", e, s, format) - } - } - - fn test_oneway(s : &str, format : &str) -> bool { - match strptime(s, format) { - Ok(_) => { - // oneway tests are used when reformatting the parsed Tm - // back into a string can generate a different string - // from the original (i.e. leading zeroes) - true - }, - Err(e) => panic!("{:?}, s={:?}, format={:?}", e, s, format) - } - } - - let days = [ - "Sunday".to_string(), - "Monday".to_string(), - "Tuesday".to_string(), - "Wednesday".to_string(), - "Thursday".to_string(), - "Friday".to_string(), - "Saturday".to_string() - ]; - for day in days.iter() { - assert!(test(&day, "%A")); - } - - let days = [ - "Sun".to_string(), - "Mon".to_string(), - "Tue".to_string(), - "Wed".to_string(), - "Thu".to_string(), - "Fri".to_string(), - "Sat".to_string() - ]; - for day in days.iter() { - assert!(test(&day, "%a")); - } - - let months = [ - "January".to_string(), - "February".to_string(), - "March".to_string(), - "April".to_string(), - "May".to_string(), - "June".to_string(), - "July".to_string(), - "August".to_string(), - "September".to_string(), - "October".to_string(), - "November".to_string(), - "December".to_string() - ]; - for day in months.iter() { - assert!(test(&day, "%B")); - } - - let months = [ - "Jan".to_string(), - "Feb".to_string(), - "Mar".to_string(), - "Apr".to_string(), - "May".to_string(), - "Jun".to_string(), - "Jul".to_string(), - "Aug".to_string(), - "Sep".to_string(), - "Oct".to_string(), - "Nov".to_string(), - "Dec".to_string() - ]; - for day in months.iter() { - assert!(test(&day, "%b")); - } - - assert!(test("19", "%C")); - assert!(test("Fri Feb 3 23:31:30 2009", "%c")); - assert!(test("Fri Feb 13 23:31:30 2009", "%c")); - assert!(test("02/13/09", "%D")); - assert!(test("03", "%d")); - assert!(test("13", "%d")); - assert!(test(" 3", "%e")); - assert!(test("13", "%e")); - assert!(test("2009-02-13", "%F")); - assert!(test("03", "%H")); - assert!(test("13", "%H")); - assert!(test("03", "%I")); // FIXME (#2350): flesh out - assert!(test("11", "%I")); // FIXME (#2350): flesh out - assert!(test("044", "%j")); - assert!(test(" 3", "%k")); - assert!(test("13", "%k")); - assert!(test(" 1", "%l")); - assert!(test("11", "%l")); - assert!(test("03", "%M")); - assert!(test("13", "%M")); - assert!(test("\n", "%n")); - assert!(test("am", "%P")); - assert!(test("pm", "%P")); - assert!(test("AM", "%p")); - assert!(test("PM", "%p")); - assert!(test("23:31", "%R")); - assert!(test("11:31:30 AM", "%r")); - assert!(test("11:31:30 PM", "%r")); - assert!(test("03", "%S")); - assert!(test("13", "%S")); - assert!(test("15:31:30", "%T")); - assert!(test("\t", "%t")); - assert!(test("1", "%u")); - assert!(test("7", "%u")); - assert!(test("13-Feb-2009", "%v")); - assert!(test("0", "%w")); - assert!(test("6", "%w")); - assert!(test("2009", "%Y")); - assert!(test("09", "%y")); - - assert!(test_oneway("3", "%d")); - assert!(test_oneway("3", "%H")); - assert!(test_oneway("3", "%e")); - assert!(test_oneway("3", "%M")); - assert!(test_oneway("3", "%S")); - - assert!(strptime("-0000", "%z").unwrap().tm_utcoff == 0); - assert!(strptime("-00:00", "%z").unwrap().tm_utcoff == 0); - assert!(strptime("Z", "%z").unwrap().tm_utcoff == 0); - assert_eq!(-28800, strptime("-0800", "%z").unwrap().tm_utcoff); - assert_eq!(-28800, strptime("-08:00", "%z").unwrap().tm_utcoff); - assert_eq!(28800, strptime("+0800", "%z").unwrap().tm_utcoff); - assert_eq!(28800, strptime("+08:00", "%z").unwrap().tm_utcoff); - assert_eq!(5400, strptime("+0130", "%z").unwrap().tm_utcoff); - assert_eq!(5400, strptime("+01:30", "%z").unwrap().tm_utcoff); - assert!(test("%", "%%")); - - // Test for #7256 - assert_eq!(strptime("360", "%Y-%m-%d"), Err(InvalidYear)); - - // Test for epoch seconds parsing - { - assert!(test("1428035610", "%s")); - let tm = strptime("1428035610", "%s").unwrap(); - assert_eq!(tm.tm_utcoff, 0); - assert_eq!(tm.tm_isdst, 0); - assert_eq!(tm.tm_yday, 92); - assert_eq!(tm.tm_wday, 5); - assert_eq!(tm.tm_year, 115); - assert_eq!(tm.tm_mon, 3); - assert_eq!(tm.tm_mday, 3); - assert_eq!(tm.tm_hour, 4); - } - } - - #[test] - fn test_asctime() { - let _reset = set_time_zone(); - - let time = Timespec::new(1234567890, 54321); - let utc = at_utc(time); - let local = at(time); - - debug!("test_ctime: {} {}", utc.asctime(), local.asctime()); - - assert_eq!(utc.asctime().to_string(), "Fri Feb 13 23:31:30 2009".to_string()); - assert_eq!(local.asctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string()); - } - - #[test] - fn test_ctime() { - let _reset = set_time_zone(); - - let time = Timespec::new(1234567890, 54321); - let utc = at_utc(time); - let local = at(time); - - debug!("test_ctime: {} {}", utc.ctime(), local.ctime()); - - assert_eq!(utc.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string()); - assert_eq!(local.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string()); - } - - #[test] - fn test_strftime() { - let _reset = set_time_zone(); - - let time = Timespec::new(1234567890, 54321); - let utc = at_utc(time); - let local = at(time); - - assert_eq!(local.strftime("").unwrap().to_string(), "".to_string()); - assert_eq!(local.strftime("%A").unwrap().to_string(), "Friday".to_string()); - assert_eq!(local.strftime("%a").unwrap().to_string(), "Fri".to_string()); - assert_eq!(local.strftime("%B").unwrap().to_string(), "February".to_string()); - assert_eq!(local.strftime("%b").unwrap().to_string(), "Feb".to_string()); - assert_eq!(local.strftime("%C").unwrap().to_string(), "20".to_string()); - assert_eq!(local.strftime("%c").unwrap().to_string(), - "Fri Feb 13 15:31:30 2009".to_string()); - assert_eq!(local.strftime("%D").unwrap().to_string(), "02/13/09".to_string()); - assert_eq!(local.strftime("%d").unwrap().to_string(), "13".to_string()); - assert_eq!(local.strftime("%e").unwrap().to_string(), "13".to_string()); - assert_eq!(local.strftime("%F").unwrap().to_string(), "2009-02-13".to_string()); - assert_eq!(local.strftime("%f").unwrap().to_string(), "000054321".to_string()); - assert_eq!(local.strftime("%G").unwrap().to_string(), "2009".to_string()); - assert_eq!(local.strftime("%g").unwrap().to_string(), "09".to_string()); - assert_eq!(local.strftime("%H").unwrap().to_string(), "15".to_string()); - assert_eq!(local.strftime("%h").unwrap().to_string(), "Feb".to_string()); - assert_eq!(local.strftime("%I").unwrap().to_string(), "03".to_string()); - assert_eq!(local.strftime("%j").unwrap().to_string(), "044".to_string()); - assert_eq!(local.strftime("%k").unwrap().to_string(), "15".to_string()); - assert_eq!(local.strftime("%l").unwrap().to_string(), " 3".to_string()); - assert_eq!(local.strftime("%M").unwrap().to_string(), "31".to_string()); - assert_eq!(local.strftime("%m").unwrap().to_string(), "02".to_string()); - assert_eq!(local.strftime("%n").unwrap().to_string(), "\n".to_string()); - assert_eq!(local.strftime("%P").unwrap().to_string(), "pm".to_string()); - assert_eq!(local.strftime("%p").unwrap().to_string(), "PM".to_string()); - assert_eq!(local.strftime("%R").unwrap().to_string(), "15:31".to_string()); - assert_eq!(local.strftime("%r").unwrap().to_string(), "03:31:30 PM".to_string()); - assert_eq!(local.strftime("%S").unwrap().to_string(), "30".to_string()); - assert_eq!(local.strftime("%s").unwrap().to_string(), "1234567890".to_string()); - assert_eq!(local.strftime("%T").unwrap().to_string(), "15:31:30".to_string()); - assert_eq!(local.strftime("%t").unwrap().to_string(), "\t".to_string()); - assert_eq!(local.strftime("%U").unwrap().to_string(), "06".to_string()); - assert_eq!(local.strftime("%u").unwrap().to_string(), "5".to_string()); - assert_eq!(local.strftime("%V").unwrap().to_string(), "07".to_string()); - assert_eq!(local.strftime("%v").unwrap().to_string(), "13-Feb-2009".to_string()); - assert_eq!(local.strftime("%W").unwrap().to_string(), "06".to_string()); - assert_eq!(local.strftime("%w").unwrap().to_string(), "5".to_string()); - // FIXME (#2350): support locale - assert_eq!(local.strftime("%X").unwrap().to_string(), "15:31:30".to_string()); - // FIXME (#2350): support locale - assert_eq!(local.strftime("%x").unwrap().to_string(), "02/13/09".to_string()); - assert_eq!(local.strftime("%Y").unwrap().to_string(), "2009".to_string()); - assert_eq!(local.strftime("%y").unwrap().to_string(), "09".to_string()); - // FIXME (#2350): support locale - assert_eq!(local.strftime("%Z").unwrap().to_string(), "".to_string()); - assert_eq!(local.strftime("%z").unwrap().to_string(), "-0800".to_string()); - assert_eq!(local.strftime("%+").unwrap().to_string(), - "2009-02-13T15:31:30-08:00".to_string()); - assert_eq!(local.strftime("%%").unwrap().to_string(), "%".to_string()); - - let invalid_specifiers = ["%E", "%J", "%K", "%L", "%N", "%O", "%o", "%Q", "%q"]; - for &sp in invalid_specifiers.iter() { - assert_eq!(local.strftime(sp).unwrap_err(), - InvalidFormatSpecifier(sp[1..].chars().next().unwrap())); - } - assert_eq!(local.strftime("%").unwrap_err(), MissingFormatConverter); - assert_eq!(local.strftime("%A %").unwrap_err(), MissingFormatConverter); - - assert_eq!(local.asctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string()); - assert_eq!(local.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string()); - assert_eq!(local.rfc822z().to_string(), "Fri, 13 Feb 2009 15:31:30 -0800".to_string()); - assert_eq!(local.rfc3339().to_string(), "2009-02-13T15:31:30-08:00".to_string()); - - assert_eq!(utc.asctime().to_string(), "Fri Feb 13 23:31:30 2009".to_string()); - assert_eq!(utc.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string()); - assert_eq!(utc.rfc822().to_string(), "Fri, 13 Feb 2009 23:31:30 GMT".to_string()); - assert_eq!(utc.rfc822z().to_string(), "Fri, 13 Feb 2009 23:31:30 -0000".to_string()); - assert_eq!(utc.rfc3339().to_string(), "2009-02-13T23:31:30Z".to_string()); - } - - #[test] - fn test_timespec_eq_ord() { - let a = &Timespec::new(-2, 1); - let b = &Timespec::new(-1, 2); - let c = &Timespec::new(1, 2); - let d = &Timespec::new(2, 1); - let e = &Timespec::new(2, 1); - - assert!(d.eq(e)); - assert!(c.ne(e)); - - assert!(a.lt(b)); - assert!(b.lt(c)); - assert!(c.lt(d)); - - assert!(a.le(b)); - assert!(b.le(c)); - assert!(c.le(d)); - assert!(d.le(e)); - assert!(e.le(d)); - - assert!(b.ge(a)); - assert!(c.ge(b)); - assert!(d.ge(c)); - assert!(e.ge(d)); - assert!(d.ge(e)); - - assert!(b.gt(a)); - assert!(c.gt(b)); - assert!(d.gt(c)); - } - - #[test] - #[allow(deprecated)] - fn test_timespec_hash() { - use std::hash::{Hash, Hasher}; - - let c = &Timespec::new(3, 2); - let d = &Timespec::new(2, 1); - let e = &Timespec::new(2, 1); - - let mut hasher = ::std::hash::SipHasher::new(); - - let d_hash:u64 = { - d.hash(&mut hasher); - hasher.finish() - }; - - hasher = ::std::hash::SipHasher::new(); - - let e_hash:u64 = { - e.hash(&mut hasher); - hasher.finish() - }; - - hasher = ::std::hash::SipHasher::new(); - - let c_hash:u64 = { - c.hash(&mut hasher); - hasher.finish() - }; - - assert_eq!(d_hash, e_hash); - assert!(c_hash != e_hash); - } - - #[test] - fn test_timespec_add() { - let a = Timespec::new(1, 2); - let b = Duration::seconds(2) + Duration::nanoseconds(3); - let c = a + b; - assert_eq!(c.sec, 3); - assert_eq!(c.nsec, 5); - - let p = Timespec::new(1, super::NSEC_PER_SEC - 2); - let q = Duration::seconds(2) + Duration::nanoseconds(2); - let r = p + q; - assert_eq!(r.sec, 4); - assert_eq!(r.nsec, 0); - - let u = Timespec::new(1, super::NSEC_PER_SEC - 2); - let v = Duration::seconds(2) + Duration::nanoseconds(3); - let w = u + v; - assert_eq!(w.sec, 4); - assert_eq!(w.nsec, 1); - - let k = Timespec::new(1, 0); - let l = Duration::nanoseconds(-1); - let m = k + l; - assert_eq!(m.sec, 0); - assert_eq!(m.nsec, 999_999_999); - } - - #[test] - fn test_timespec_sub() { - let a = Timespec::new(2, 3); - let b = Timespec::new(1, 2); - let c = a - b; - assert_eq!(c.num_nanoseconds(), Some(super::NSEC_PER_SEC as i64 + 1)); - - let p = Timespec::new(2, 0); - let q = Timespec::new(1, 2); - let r = p - q; - assert_eq!(r.num_nanoseconds(), Some(super::NSEC_PER_SEC as i64 - 2)); - - let u = Timespec::new(1, 2); - let v = Timespec::new(2, 3); - let w = u - v; - assert_eq!(w.num_nanoseconds(), Some(-super::NSEC_PER_SEC as i64 - 1)); - } - - #[test] - fn test_time_sub() { - let a = ::now(); - let b = at(a.to_timespec() + Duration::seconds(5)); - let c = b - a; - assert_eq!(c.num_nanoseconds(), Some(super::NSEC_PER_SEC as i64 * 5)); - } - - #[test] - fn test_steadytime_sub() { - let a = SteadyTime::now(); - let b = a + Duration::seconds(1); - assert_eq!(b - a, Duration::seconds(1)); - assert_eq!(a - b, Duration::seconds(-1)); - } - - #[test] - fn test_date_before_1970() { - let early = strptime("1901-01-06", "%F").unwrap(); - let late = strptime("2000-01-01", "%F").unwrap(); - assert!(early < late); - } - - #[test] - fn test_dst() { - let _reset = set_time_zone_london_dst(); - let utc_in_feb = strptime("2015-02-01Z", "%F%z").unwrap(); - let utc_in_jun = strptime("2015-06-01Z", "%F%z").unwrap(); - let utc_in_nov = strptime("2015-11-01Z", "%F%z").unwrap(); - let local_in_feb = utc_in_feb.to_local(); - let local_in_jun = utc_in_jun.to_local(); - let local_in_nov = utc_in_nov.to_local(); - - assert_eq!(local_in_feb.tm_mon, 1); - assert_eq!(local_in_feb.tm_hour, 0); - assert_eq!(local_in_feb.tm_utcoff, 0); - assert_eq!(local_in_feb.tm_isdst, 0); - - assert_eq!(local_in_jun.tm_mon, 5); - assert_eq!(local_in_jun.tm_hour, 1); - assert_eq!(local_in_jun.tm_utcoff, 3600); - assert_eq!(local_in_jun.tm_isdst, 1); - - assert_eq!(local_in_nov.tm_mon, 10); - assert_eq!(local_in_nov.tm_hour, 0); - assert_eq!(local_in_nov.tm_utcoff, 0); - assert_eq!(local_in_nov.tm_isdst, 0) - } +mod tests; +mod time; +mod utc_offset; +pub mod util; +mod weekday; + +pub use crate::date::Date; +pub use crate::duration::Duration; +pub use crate::error::Error; +#[cfg(feature = "std")] +pub use crate::instant::Instant; +pub use crate::month::Month; +pub use crate::offset_date_time::OffsetDateTime; +pub use crate::primitive_date_time::PrimitiveDateTime; +pub use crate::time::Time; +pub use crate::utc_offset::UtcOffset; +pub use crate::weekday::Weekday; + +/// An alias for [`std::result::Result`] with a generic error from the time crate. +pub type Result<T> = core::result::Result<T, Error>; + +/// This is a separate function to reduce the code size of `expect_opt!`. +#[inline(never)] +#[cold] +#[track_caller] +const fn expect_failed(message: &str) -> ! { + panic!("{}", message) } |