#![cfg_attr(docs, feature(doc_cfg))]
#![cfg_attr(not(std), no_std)]
#![deny(
anonymous_parameters,
clippy::all,
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_code,
unused_extern_crates
)]
#![warn(
clippy::dbg_macro,
clippy::decimal_literal_representation,
clippy::get_unwrap,
clippy::missing_docs_in_private_items,
clippy::nursery,
clippy::option_unwrap_used,
clippy::pedantic,
clippy::print_stdout,
clippy::result_unwrap_used,
clippy::todo,
clippy::unimplemented,
clippy::use_debug,
missing_copy_implementations,
missing_debug_implementations,
single_use_lifetimes,
unused_qualifications,
variant_size_differences
)]
#![allow(
clippy::cast_lossless,
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
clippy::cast_precision_loss,
clippy::cast_sign_loss,
clippy::enum_glob_use,
clippy::inline_always,
clippy::missing_errors_doc,
clippy::module_name_repetitions,
clippy::must_use_candidate,
clippy::suspicious_arithmetic_impl,
clippy::use_self,
clippy::wildcard_imports,
clippy::zero_prefixed_literal,
unstable_name_collisions
)]
#![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))]
#[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, ")"))?
));
}
}
};
}
#[cfg(test)]
macro_rules! time {
($hour:literal : $minute:literal) => {
crate::Time::try_from_hms($hour, $minute, 0)?
};
($hour:literal : $minute:literal : $second:literal) => {
crate::Time::try_from_hms($hour, $minute, $second)?
};
($hour:literal : $minute:literal : $second:literal : $nanosecond:literal) => {
crate::Time::try_from_hms_nano($hour, $minute, $second, $nanosecond)?
};
}
#[cfg(test)]
macro_rules! offset {
(UTC) => {
crate::UtcOffset::UTC
};
($(+)? $hour:literal) => {
crate::UtcOffset::hours($hour)
};
(+ $hour:literal : $minute:literal) => {
crate::UtcOffset::minutes($hour * 60 + $minute)
};
(+ $hour:literal : $minute:literal : $second:literal) => {
crate::UtcOffset::seconds($hour * 3_600 + $minute * 60 + $second)
};
(- $hour:literal : $minute:literal) => {
crate::UtcOffset::minutes($hour * -60 - $minute)
};
(- $hour:literal : $minute:literal : $second:literal) => {
crate::UtcOffset::seconds($hour * -3_600 - $minute * 60 - $second)
};
}
#[cfg(test)]
macro_rules! date {
($(+)? $year:literal - $ordinal:literal) => {
crate::Date::try_from_yo($year, $ordinal)?
};
($(+)? $year:literal - $month:literal - $day:literal) => {
crate::Date::try_from_ymd($year, $month, $day)?
};
}
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 {
#[cfg(not(use_trait_as_underscore))]
pub use crate::{NumericalDuration, NumericalStdDuration};
#[cfg(use_trait_as_underscore)]
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::{
convert::{TryFrom, TryInto},
prelude::*,
};
}
#[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 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()
}