#![cfg_attr(docs, feature(doc_cfg))]
#![cfg_attr(not(std), no_std)]
#![deny(
unsafe_code, // Used when interacting with system APIs
anonymous_parameters,
rust_2018_idioms,
trivial_casts,
trivial_numeric_casts,
unreachable_pub, // some known bugs that are overridden
const_err,
illegal_floating_point_literal_pattern,
late_bound_lifetime_arguments,
path_statements,
patterns_in_fns_without_body,
clippy::all
)]
#![warn(
unused_extern_crates,
missing_copy_implementations,
missing_debug_implementations,
single_use_lifetimes,
unused_qualifications,
variant_size_differences,
clippy::pedantic,
clippy::nursery,
clippy::missing_docs_in_private_items,
clippy::dbg_macro,
clippy::decimal_literal_representation,
clippy::get_unwrap,
clippy::option_unwrap_used,
clippy::print_stdout,
clippy::result_unwrap_used
)]
#![allow(
unstable_name_collisions,
clippy::suspicious_arithmetic_impl,
clippy::inline_always,
clippy::cast_possible_wrap,
clippy::cast_lossless,
clippy::module_name_repetitions,
clippy::must_use_candidate,
clippy::missing_errors_doc,
clippy::use_self, // Not supported in some situations in older compilers.
)]
#![cfg_attr(test, allow(clippy::cognitive_complexity, clippy::too_many_lines))]
#![doc(html_favicon_url = "https://avatars0.githubusercontent.com/u/55999857")]
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/55999857")]
#![doc(test(no_crate_inject))]
extern crate self as time;
#[cfg(docs)]
#[rustversion::not(nightly)]
compile_error!("The `__doc` feature requires a nightly compiler, and is for internal usage only.");
#[rustversion::before(1.34.0)]
compile_error!("The time crate has a minimum supported rust version of 1.34.0.");
#[cfg(not(std))]
#[rustversion::before(1.36.0)]
compile_error!(
"Using the time crate without the standard library enabled requires a global allocator. This \
was stabilized in Rust 1.36.0. You can either upgrade or enable the standard library."
);
#[cfg(panicking_api)]
#[cfg_attr(docs, doc(cfg(feature = "panicking-api")))]
macro_rules! format_conditional {
($conditional:ident) => {
format!(concat!(stringify!($conditional), "={}"), $conditional)
};
($first_conditional:ident, $($conditional:ident),*) => {{
#[cfg(not(std))]
let mut s = alloc::string::String::new();
#[cfg(std)]
let mut s = String::new();
s.push_str(&format_conditional!($first_conditional));
$(s.push_str(&format!(concat!(", ", stringify!($conditional), "={}"), $conditional));)*
s
}}
}
#[cfg(panicking_api)]
#[cfg_attr(docs, doc(cfg(feature = "panicking-api")))]
macro_rules! assert_value_in_range {
($value:ident in $start:expr => $end:expr) => {
#[allow(unused_comparisons)]
{
if $value < $start || $value > $end {
panic!(
concat!(stringify!($value), " must be in the range {}..={} (was {})"),
$start,
$end,
$value,
);
}
}
};
($value:ident in $start:expr => $end:expr, given $($conditional:ident),+ $(,)?) => {
#[allow(unused_comparisons)]
{
if $value < $start || $value > $end {
panic!(
concat!(stringify!($value), " must be in the range {}..={} given{} (was {})"),
$start,
$end,
&format_conditional!($($conditional),+),
$value,
);
};
}
};
}
macro_rules! ensure_value_in_range {
($value:ident in $start:expr => $end:expr) => {
#[allow(unused_comparisons)]
{
if $value < $start || $value > $end {
return Err(ComponentRangeError {
name: stringify!($value),
minimum: i64::from($start),
maximum: i64::from($end),
value: i64::from($value),
given: Vec::new(),
});
}
}
};
($value:ident in $start:expr => $end:expr, given $($conditional:ident),+ $(,)?) => {
#[allow(unused_comparisons)]
{
if $value < $start || $value > $end {
return Err(ComponentRangeError {
name: stringify!($value),
minimum: i64::from($start),
maximum: i64::from($end),
value: i64::from($value),
given: vec![$((stringify!($conditional), i64::from($conditional))),+],
});
};
}
};
}
#[cfg(all(test, std))]
macro_rules! assert_panics {
($e:expr $(, $message:literal)?) => {
#[allow(box_pointers)]
{
if std::panic::catch_unwind(move || $e).is_ok() {
panic!(concat!(
"assertion failed: expected `",
stringify!($e),
"` to panic",
$(concat!(" (", $message, ")"))?
));
}
}
};
}
mod date;
mod duration;
mod error;
mod format;
#[cfg(std)]
mod instant;
pub mod internals;
mod numerical_traits;
mod offset_date_time;
mod primitive_date_time;
#[cfg(rand)]
mod rand;
#[cfg(serde)]
#[allow(missing_copy_implementations, missing_debug_implementations)]
mod serde;
mod sign;
mod time_mod;
mod utc_offset;
mod weekday;
pub use date::{days_in_year, is_leap_year, weeks_in_year, Date};
pub use duration::Duration;
pub use error::{ComponentRangeError, ConversionRangeError, Error, IndeterminateOffsetError};
pub(crate) use format::DeferredFormat;
pub use format::{validate_format_string, Format, ParseError};
#[cfg(std)]
pub use instant::Instant;
use internal_prelude::*;
pub use numerical_traits::{NumericalDuration, NumericalStdDuration, NumericalStdDurationShort};
pub use offset_date_time::OffsetDateTime;
pub use primitive_date_time::PrimitiveDateTime;
#[allow(deprecated)]
pub use sign::Sign;
pub use time_macros::date;
pub use time_macros::offset;
pub use time_macros::time;
pub use time_mod::Time;
pub use utc_offset::UtcOffset;
pub use weekday::Weekday;
pub type Result<T> = core::result::Result<T, Error>;
pub mod prelude {
pub use crate::{NumericalDuration as _, NumericalStdDuration as _};
pub use time_macros::{date, offset, time};
}
mod internal_prelude {
#![allow(unused_imports)]
#[cfg(not(std))]
extern crate alloc;
#[cfg(std)]
pub(crate) use crate::Instant;
pub(crate) use crate::{
format::{ParseError, ParseResult},
ComponentRangeError, ConversionRangeError, Date, DeferredFormat, Duration,
IndeterminateOffsetError, NumericalDuration, NumericalStdDuration, OffsetDateTime,
PrimitiveDateTime, Time, UtcOffset,
Weekday::{self, Friday, Monday, Saturday, Sunday, Thursday, Tuesday, Wednesday},
};
#[cfg(not(std))]
pub(crate) use alloc::{
borrow::ToOwned,
boxed::Box,
format,
string::{String, ToString},
vec,
vec::Vec,
};
pub(crate) use standback::prelude::*;
pub(crate) use time_macros::{date, offset, time};
}
#[allow(clippy::missing_docs_in_private_items)]
mod private {
use super::*;
macro_rules! parsable {
($($type:ty),* $(,)?) => {
$(
impl Parsable for $type {
fn parse(s: impl AsRef<str>, format: impl AsRef<str>) -> ParseResult<Self> {
Self::parse(s, format)
}
}
)*
};
}
pub trait Parsable: Sized {
fn parse(s: impl AsRef<str>, format: impl AsRef<str>) -> ParseResult<Self>;
}
parsable![Time, Date, UtcOffset, PrimitiveDateTime, OffsetDateTime];
}
#[inline(always)]
pub fn parse<T: private::Parsable>(s: impl AsRef<str>, format: impl AsRef<str>) -> ParseResult<T> {
private::Parsable::parse(s, format)
}
#[cfg(all(std, v01_deprecated_api))]
#[cfg_attr(tarpaulin, skip)]
#[allow(clippy::missing_docs_in_private_items)]
#[deprecated(since = "0.2.0", note = "Use `Instant`")]
pub type PreciseTime = Instant;
#[cfg(all(std, v01_deprecated_api))]
#[cfg_attr(tarpaulin, skip)]
#[allow(clippy::missing_docs_in_private_items)]
#[deprecated(since = "0.2.0", note = "Use `Instant`")]
pub type SteadyTime = Instant;
#[cfg(all(std, v01_deprecated_api))]
#[cfg_attr(tarpaulin, skip)]
#[allow(clippy::missing_docs_in_private_items)]
#[deprecated(
since = "0.2.0",
note = "Use `OffsetDateTime::now() - OffsetDateTime::unix_epoch()` to get a `Duration` since \
a known epoch."
)]
#[inline]
pub fn precise_time_ns() -> u64 {
use core::convert::TryInto;
use std::time::SystemTime;
(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH))
.expect("System clock was before 1970.")
.as_nanos()
.try_into()
.expect("This function will be removed long before this is an issue.")
}
#[cfg(all(std, v01_deprecated_api))]
#[cfg_attr(tarpaulin, skip)]
#[allow(clippy::missing_docs_in_private_items)]
#[deprecated(
since = "0.2.0",
note = "Use `OffsetDateTime::now() - OffsetDateTime::unix_epoch()` to get a `Duration` since \
a known epoch."
)]
#[inline]
pub fn precise_time_s() -> f64 {
use std::time::SystemTime;
(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH))
.expect("System clock was before 1970.")
.as_secs_f64()
}