summaryrefslogtreecommitdiffstats
path: root/vendor/time/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /vendor/time/src
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz
rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/time/src')
-rw-r--r--vendor/time/src/date.rs449
-rw-r--r--vendor/time/src/date_time.rs123
-rw-r--r--vendor/time/src/duration.rs333
-rw-r--r--vendor/time/src/error/mod.rs24
-rw-r--r--vendor/time/src/error/parse.rs21
-rw-r--r--vendor/time/src/error/parse_from_description.rs6
-rw-r--r--vendor/time/src/ext.rs36
-rw-r--r--vendor/time/src/format_description/component.rs3
-rw-r--r--vendor/time/src/format_description/modifier.rs15
-rw-r--r--vendor/time/src/format_description/parse/ast.rs5
-rw-r--r--vendor/time/src/format_description/parse/format_item.rs4
-rw-r--r--vendor/time/src/format_description/well_known/iso8601.rs82
-rw-r--r--vendor/time/src/format_description/well_known/iso8601/adt_hack.rs7
-rw-r--r--vendor/time/src/formatting/formattable.rs4
-rw-r--r--vendor/time/src/formatting/iso8601.rs12
-rw-r--r--vendor/time/src/formatting/mod.rs101
-rw-r--r--vendor/time/src/instant.rs1
-rw-r--r--vendor/time/src/internal_macros.rs197
-rw-r--r--vendor/time/src/lib.rs231
-rw-r--r--vendor/time/src/month.rs67
-rw-r--r--vendor/time/src/offset_date_time.rs1
-rw-r--r--vendor/time/src/parsing/component.rs18
-rw-r--r--vendor/time/src/parsing/iso8601.rs36
-rw-r--r--vendor/time/src/parsing/parsable.rs17
-rw-r--r--vendor/time/src/parsing/parsed.rs655
-rw-r--r--vendor/time/src/primitive_date_time.rs1
-rw-r--r--vendor/time/src/quickcheck.rs48
-rw-r--r--vendor/time/src/rand.rs19
-rw-r--r--vendor/time/src/serde/mod.rs18
-rw-r--r--vendor/time/src/serde/visitor.rs17
-rw-r--r--vendor/time/src/sys/local_offset_at/unix.rs3
-rw-r--r--vendor/time/src/sys/local_offset_at/wasm_js.rs2
-rw-r--r--vendor/time/src/sys/local_offset_at/windows.rs2
-rw-r--r--vendor/time/src/tests.rs8
-rw-r--r--vendor/time/src/time.rs471
-rw-r--r--vendor/time/src/utc_offset.rs198
-rw-r--r--vendor/time/src/weekday.rs36
37 files changed, 2038 insertions, 1233 deletions
diff --git a/vendor/time/src/date.rs b/vendor/time/src/date.rs
index 9f194b434..3f76adb2d 100644
--- a/vendor/time/src/date.rs
+++ b/vendor/time/src/date.rs
@@ -1,19 +1,28 @@
//! The [`Date`] struct and its associated `impl`s.
use core::fmt;
+use core::num::NonZeroI32;
use core::ops::{Add, Sub};
use core::time::Duration as StdDuration;
#[cfg(feature = "formatting")]
use std::io;
+use deranged::RangedI32;
+
use crate::convert::*;
#[cfg(feature = "formatting")]
use crate::formatting::Formattable;
+use crate::internal_macros::{
+ cascade, const_try, const_try_opt, div_floor, ensure_ranged, expect_opt, impl_add_assign,
+ impl_sub_assign,
+};
#[cfg(feature = "parsing")]
use crate::parsing::Parsable;
use crate::util::{days_in_year, days_in_year_month, is_leap_year, weeks_in_year};
use crate::{error, Duration, Month, PrimitiveDateTime, Time, Weekday};
+type Year = RangedI32<MIN_YEAR, MAX_YEAR>;
+
/// The minimum valid year.
pub(crate) const MIN_YEAR: i32 = if cfg!(feature = "large-dates") {
-999_999
@@ -39,32 +48,43 @@ pub struct Date {
// | 2 bits | 21 bits | 9 bits |
// | unassigned | year | ordinal |
// The year is 15 bits when `large-dates` is not enabled.
- value: i32,
+ value: NonZeroI32,
}
impl Date {
/// The minimum valid `Date`.
///
/// The value of this may vary depending on the feature flags enabled.
- pub const MIN: Self = Self::__from_ordinal_date_unchecked(MIN_YEAR, 1);
+ // Safety: `ordinal` is not zero.
+ #[allow(clippy::undocumented_unsafe_blocks)]
+ pub const MIN: Self = unsafe { Self::__from_ordinal_date_unchecked(MIN_YEAR, 1) };
/// The maximum valid `Date`.
///
/// The value of this may vary depending on the feature flags enabled.
- pub const MAX: Self = Self::__from_ordinal_date_unchecked(MAX_YEAR, days_in_year(MAX_YEAR));
+ // Safety: `ordinal` is not zero.
+ #[allow(clippy::undocumented_unsafe_blocks)]
+ pub const MAX: Self =
+ unsafe { Self::__from_ordinal_date_unchecked(MAX_YEAR, days_in_year(MAX_YEAR)) };
// region: constructors
/// Construct a `Date` from the year and ordinal values, the validity of which must be
/// guaranteed by the caller.
+ ///
+ /// # Safety
+ ///
+ /// `ordinal` must not be zero. `year` should be in the range `MIN_YEAR..=MAX_YEAR`, but this
+ /// is not a safety invariant.
#[doc(hidden)]
- pub const fn __from_ordinal_date_unchecked(year: i32, ordinal: u16) -> Self {
+ pub const unsafe fn __from_ordinal_date_unchecked(year: i32, ordinal: u16) -> Self {
debug_assert!(year >= MIN_YEAR);
debug_assert!(year <= MAX_YEAR);
debug_assert!(ordinal != 0);
debug_assert!(ordinal <= days_in_year(year));
Self {
- value: (year << 9) | ordinal as i32,
+ // Safety: The caller must guarantee that `ordinal` is not zero.
+ value: unsafe { NonZeroI32::new_unchecked((year << 9) | ordinal as i32) },
}
}
@@ -91,14 +111,29 @@ impl Date {
[0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335],
];
- ensure_value_in_range!(year in MIN_YEAR => MAX_YEAR);
- ensure_value_in_range!(day conditionally in 1 => days_in_year_month(year, month));
+ ensure_ranged!(Year: year);
+ match day {
+ 1..=28 => {}
+ 29..=31 if day <= days_in_year_month(year, month) => {}
+ _ => {
+ return Err(crate::error::ComponentRange {
+ name: "day",
+ minimum: 1,
+ maximum: days_in_year_month(year, month) as _,
+ value: day as _,
+ conditional_range: true,
+ });
+ }
+ }
- Ok(Self::__from_ordinal_date_unchecked(
- year,
- DAYS_CUMULATIVE_COMMON_LEAP[is_leap_year(year) as usize][month as usize - 1]
- + day as u16,
- ))
+ // Safety: `ordinal` is not zero.
+ Ok(unsafe {
+ Self::__from_ordinal_date_unchecked(
+ year,
+ DAYS_CUMULATIVE_COMMON_LEAP[is_leap_year(year) as usize][month as usize - 1]
+ + day as u16,
+ )
+ })
}
/// Attempt to create a `Date` from the year and ordinal day number.
@@ -114,9 +149,23 @@ impl Date {
/// assert!(Date::from_ordinal_date(2019, 366).is_err()); // 2019 isn't a leap year.
/// ```
pub const fn from_ordinal_date(year: i32, ordinal: u16) -> Result<Self, error::ComponentRange> {
- ensure_value_in_range!(year in MIN_YEAR => MAX_YEAR);
- ensure_value_in_range!(ordinal conditionally in 1 => days_in_year(year));
- Ok(Self::__from_ordinal_date_unchecked(year, ordinal))
+ ensure_ranged!(Year: year);
+ match ordinal {
+ 1..=365 => {}
+ 366 if is_leap_year(year) => {}
+ _ => {
+ return Err(crate::error::ComponentRange {
+ name: "ordinal",
+ minimum: 1,
+ maximum: days_in_year(year) as _,
+ value: ordinal as _,
+ conditional_range: true,
+ });
+ }
+ }
+
+ // Safety: `ordinal` is not zero.
+ Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) })
}
/// Attempt to create a `Date` from the ISO year, week, and weekday.
@@ -137,8 +186,20 @@ impl Date {
week: u8,
weekday: Weekday,
) -> Result<Self, error::ComponentRange> {
- ensure_value_in_range!(year in MIN_YEAR => MAX_YEAR);
- ensure_value_in_range!(week conditionally in 1 => weeks_in_year(year));
+ ensure_ranged!(Year: year);
+ match week {
+ 1..=52 => {}
+ 53 if week <= weeks_in_year(year) => {}
+ _ => {
+ return Err(crate::error::ComponentRange {
+ name: "week",
+ minimum: 1,
+ maximum: weeks_in_year(year) as _,
+ value: week as _,
+ conditional_range: true,
+ });
+ }
+ }
let adj_year = year - 1;
let raw = 365 * adj_year + div_floor!(adj_year, 4) - div_floor!(adj_year, 100)
@@ -155,14 +216,21 @@ impl Date {
let ordinal = week as i16 * 7 + weekday.number_from_monday() as i16 - jan_4;
Ok(if ordinal <= 0 {
- Self::__from_ordinal_date_unchecked(
- year - 1,
- (ordinal as u16).wrapping_add(days_in_year(year - 1)),
- )
+ // Safety: `ordinal` is not zero.
+ unsafe {
+ Self::__from_ordinal_date_unchecked(
+ year - 1,
+ (ordinal as u16).wrapping_add(days_in_year(year - 1)),
+ )
+ }
} else if ordinal > days_in_year(year) as i16 {
- Self::__from_ordinal_date_unchecked(year + 1, ordinal as u16 - days_in_year(year))
+ // Safety: `ordinal` is not zero.
+ unsafe {
+ Self::__from_ordinal_date_unchecked(year + 1, ordinal as u16 - days_in_year(year))
+ }
} else {
- Self::__from_ordinal_date_unchecked(year, ordinal as _)
+ // Safety: `ordinal` is not zero.
+ unsafe { Self::__from_ordinal_date_unchecked(year, ordinal as _) }
})
}
@@ -181,9 +249,8 @@ impl Date {
/// ```
#[doc(alias = "from_julian_date")]
pub const fn from_julian_day(julian_day: i32) -> Result<Self, error::ComponentRange> {
- ensure_value_in_range!(
- julian_day in Self::MIN.to_julian_day() => Self::MAX.to_julian_day()
- );
+ type JulianDay = RangedI32<{ Date::MIN.to_julian_day() }, { Date::MAX.to_julian_day() }>;
+ ensure_ranged!(JulianDay: julian_day);
Ok(Self::from_julian_day_unchecked(julian_day))
}
@@ -223,7 +290,8 @@ impl Date {
cascade!(ordinal in 1..366 => year);
}
- Self::__from_ordinal_date_unchecked(year, ordinal)
+ // Safety: `ordinal` is not zero.
+ unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) }
}
// endregion constructors
@@ -237,7 +305,7 @@ impl Date {
/// assert_eq!(date!(2020 - 01 - 01).year(), 2020);
/// ```
pub const fn year(self) -> i32 {
- self.value >> 9
+ self.value.get() >> 9
}
/// Get the month.
@@ -316,7 +384,7 @@ impl Date {
/// assert_eq!(date!(2019 - 12 - 31).ordinal(), 365);
/// ```
pub const fn ordinal(self) -> u16 {
- (self.value & 0x1FF) as _
+ (self.value.get() & 0x1FF) as _
}
/// Get the ISO 8601 year and week number.
@@ -483,14 +551,16 @@ impl Date {
/// ```
pub const fn next_day(self) -> Option<Self> {
if self.ordinal() == 366 || (self.ordinal() == 365 && !is_leap_year(self.year())) {
- if self.value == Self::MAX.value {
+ if self.value.get() == Self::MAX.value.get() {
None
} else {
- Some(Self::__from_ordinal_date_unchecked(self.year() + 1, 1))
+ // Safety: `ordinal` is not zero.
+ unsafe { Some(Self::__from_ordinal_date_unchecked(self.year() + 1, 1)) }
}
} else {
Some(Self {
- value: self.value + 1,
+ // Safety: `ordinal` is not zero.
+ value: unsafe { NonZeroI32::new_unchecked(self.value.get() + 1) },
})
}
}
@@ -517,18 +587,119 @@ impl Date {
pub const fn previous_day(self) -> Option<Self> {
if self.ordinal() != 1 {
Some(Self {
- value: self.value - 1,
+ // Safety: `ordinal` is not zero.
+ value: unsafe { NonZeroI32::new_unchecked(self.value.get() - 1) },
})
- } else if self.value == Self::MIN.value {
+ } else if self.value.get() == Self::MIN.value.get() {
None
} else {
- Some(Self::__from_ordinal_date_unchecked(
- self.year() - 1,
- days_in_year(self.year() - 1),
- ))
+ // Safety: `ordinal` is not zero.
+ Some(unsafe {
+ Self::__from_ordinal_date_unchecked(self.year() - 1, days_in_year(self.year() - 1))
+ })
}
}
+ /// Calculates the first occurrence of a weekday that is strictly later than a given `Date`.
+ ///
+ /// # Panics
+ /// Panics if an overflow occurred.
+ ///
+ /// # Examples
+ /// ```
+ /// # use time::Weekday;
+ /// # use time_macros::date;
+ /// assert_eq!(
+ /// date!(2023 - 06 - 28).next_occurrence(Weekday::Monday),
+ /// date!(2023 - 07 - 03)
+ /// );
+ /// assert_eq!(
+ /// date!(2023 - 06 - 19).next_occurrence(Weekday::Monday),
+ /// date!(2023 - 06 - 26)
+ /// );
+ /// ```
+ pub const fn next_occurrence(self, weekday: Weekday) -> Self {
+ expect_opt!(
+ self.checked_next_occurrence(weekday),
+ "overflow calculating the next occurrence of a weekday"
+ )
+ }
+
+ /// Calculates the first occurrence of a weekday that is strictly earlier than a given `Date`.
+ ///
+ /// # Panics
+ /// Panics if an overflow occurred.
+ ///
+ /// # Examples
+ /// ```
+ /// # use time::Weekday;
+ /// # use time_macros::date;
+ /// assert_eq!(
+ /// date!(2023 - 06 - 28).prev_occurrence(Weekday::Monday),
+ /// date!(2023 - 06 - 26)
+ /// );
+ /// assert_eq!(
+ /// date!(2023 - 06 - 19).prev_occurrence(Weekday::Monday),
+ /// date!(2023 - 06 - 12)
+ /// );
+ /// ```
+ pub const fn prev_occurrence(self, weekday: Weekday) -> Self {
+ expect_opt!(
+ self.checked_prev_occurrence(weekday),
+ "overflow calculating the previous occurrence of a weekday"
+ )
+ }
+
+ /// Calculates the `n`th occurrence of a weekday that is strictly later than a given `Date`.
+ ///
+ /// # Panics
+ /// Panics if an overflow occurred or if `n == 0`.
+ ///
+ /// # Examples
+ /// ```
+ /// # use time::Weekday;
+ /// # use time_macros::date;
+ /// assert_eq!(
+ /// date!(2023 - 06 - 25).nth_next_occurrence(Weekday::Monday, 5),
+ /// date!(2023 - 07 - 24)
+ /// );
+ /// assert_eq!(
+ /// date!(2023 - 06 - 26).nth_next_occurrence(Weekday::Monday, 5),
+ /// date!(2023 - 07 - 31)
+ /// );
+ /// ```
+ pub const fn nth_next_occurrence(self, weekday: Weekday, n: u8) -> Self {
+ expect_opt!(
+ self.checked_nth_next_occurrence(weekday, n),
+ "overflow calculating the next occurrence of a weekday"
+ )
+ }
+
+ /// Calculates the `n`th occurrence of a weekday that is strictly earlier than a given `Date`.
+ ///
+ /// # Panics
+ /// Panics if an overflow occurred or if `n == 0`.
+ ///
+ /// # Examples
+ /// ```
+ /// # use time::Weekday;
+ /// # use time_macros::date;
+ /// assert_eq!(
+ /// date!(2023 - 06 - 27).nth_prev_occurrence(Weekday::Monday, 3),
+ /// date!(2023 - 06 - 12)
+ /// );
+ /// assert_eq!(
+ /// date!(2023 - 06 - 26).nth_prev_occurrence(Weekday::Monday, 3),
+ /// date!(2023 - 06 - 05)
+ /// );
+ /// ```
+ pub const fn nth_prev_occurrence(self, weekday: Weekday, n: u8) -> Self {
+ expect_opt!(
+ self.checked_nth_prev_occurrence(weekday, n),
+ "overflow calculating the previous occurrence of a weekday"
+ )
+ }
+
/// Get the Julian day for the date.
///
/// The algorithm to perform this conversion is derived from one provided by Peter Baum; it is
@@ -597,6 +768,49 @@ impl Date {
}
}
+ /// Computes `self + duration`, returning `None` if an overflow occurred.
+ ///
+ /// ```rust
+ /// # use time::{Date, ext::NumericalStdDuration};
+ /// # use time_macros::date;
+ /// assert_eq!(Date::MAX.checked_add_std(1.std_days()), None);
+ /// assert_eq!(
+ /// date!(2020 - 12 - 31).checked_add_std(2.std_days()),
+ /// Some(date!(2021 - 01 - 02))
+ /// );
+ /// ```
+ ///
+ /// # Note
+ ///
+ /// This function only takes whole days into account.
+ ///
+ /// ```rust
+ /// # use time::{Date, ext::NumericalStdDuration};
+ /// # use time_macros::date;
+ /// assert_eq!(Date::MAX.checked_add_std(23.std_hours()), Some(Date::MAX));
+ /// assert_eq!(
+ /// date!(2020 - 12 - 31).checked_add_std(23.std_hours()),
+ /// Some(date!(2020 - 12 - 31))
+ /// );
+ /// assert_eq!(
+ /// date!(2020 - 12 - 31).checked_add_std(47.std_hours()),
+ /// Some(date!(2021 - 01 - 01))
+ /// );
+ /// ```
+ pub const fn checked_add_std(self, duration: StdDuration) -> Option<Self> {
+ let whole_days = duration.as_secs() / Second::per(Day) as u64;
+ if whole_days > i32::MAX as u64 {
+ return None;
+ }
+
+ let julian_day = const_try_opt!(self.to_julian_day().checked_add(whole_days as _));
+ if let Ok(date) = Self::from_julian_day(julian_day) {
+ Some(date)
+ } else {
+ None
+ }
+ }
+
/// Computes `self - duration`, returning `None` if an overflow occurred.
///
/// ```
@@ -641,6 +855,109 @@ impl Date {
None
}
}
+
+ /// Computes `self - duration`, returning `None` if an overflow occurred.
+ ///
+ /// ```
+ /// # use time::{Date, ext::NumericalStdDuration};
+ /// # use time_macros::date;
+ /// assert_eq!(Date::MIN.checked_sub_std(1.std_days()), None);
+ /// assert_eq!(
+ /// date!(2020 - 12 - 31).checked_sub_std(2.std_days()),
+ /// Some(date!(2020 - 12 - 29))
+ /// );
+ /// ```
+ ///
+ /// # Note
+ ///
+ /// This function only takes whole days into account.
+ ///
+ /// ```
+ /// # use time::{Date, ext::NumericalStdDuration};
+ /// # use time_macros::date;
+ /// assert_eq!(Date::MIN.checked_sub_std(23.std_hours()), Some(Date::MIN));
+ /// assert_eq!(
+ /// date!(2020 - 12 - 31).checked_sub_std(23.std_hours()),
+ /// Some(date!(2020 - 12 - 31))
+ /// );
+ /// assert_eq!(
+ /// date!(2020 - 12 - 31).checked_sub_std(47.std_hours()),
+ /// Some(date!(2020 - 12 - 30))
+ /// );
+ /// ```
+ pub const fn checked_sub_std(self, duration: StdDuration) -> Option<Self> {
+ let whole_days = duration.as_secs() / Second::per(Day) as u64;
+ if whole_days > i32::MAX as u64 {
+ return None;
+ }
+
+ let julian_day = const_try_opt!(self.to_julian_day().checked_sub(whole_days as _));
+ if let Ok(date) = Self::from_julian_day(julian_day) {
+ Some(date)
+ } else {
+ None
+ }
+ }
+
+ /// Calculates the first occurrence of a weekday that is strictly later than a given `Date`.
+ /// Returns `None` if an overflow occurred.
+ pub(crate) const fn checked_next_occurrence(self, weekday: Weekday) -> Option<Self> {
+ let day_diff = match weekday as i8 - self.weekday() as i8 {
+ 1 | -6 => 1,
+ 2 | -5 => 2,
+ 3 | -4 => 3,
+ 4 | -3 => 4,
+ 5 | -2 => 5,
+ 6 | -1 => 6,
+ val => {
+ debug_assert!(val == 0);
+ 7
+ }
+ };
+
+ self.checked_add(Duration::days(day_diff))
+ }
+
+ /// Calculates the first occurrence of a weekday that is strictly earlier than a given `Date`.
+ /// Returns `None` if an overflow occurred.
+ pub(crate) const fn checked_prev_occurrence(self, weekday: Weekday) -> Option<Self> {
+ let day_diff = match weekday as i8 - self.weekday() as i8 {
+ 1 | -6 => 6,
+ 2 | -5 => 5,
+ 3 | -4 => 4,
+ 4 | -3 => 3,
+ 5 | -2 => 2,
+ 6 | -1 => 1,
+ val => {
+ debug_assert!(val == 0);
+ 7
+ }
+ };
+
+ self.checked_sub(Duration::days(day_diff))
+ }
+
+ /// Calculates the `n`th occurrence of a weekday that is strictly later than a given `Date`.
+ /// Returns `None` if an overflow occurred or if `n == 0`.
+ pub(crate) const fn checked_nth_next_occurrence(self, weekday: Weekday, n: u8) -> Option<Self> {
+ if n == 0 {
+ return None;
+ }
+
+ const_try_opt!(self.checked_next_occurrence(weekday))
+ .checked_add(Duration::weeks(n as i64 - 1))
+ }
+
+ /// Calculates the `n`th occurrence of a weekday that is strictly earlier than a given `Date`.
+ /// Returns `None` if an overflow occurred or if `n == 0`.
+ pub(crate) const fn checked_nth_prev_occurrence(self, weekday: Weekday, n: u8) -> Option<Self> {
+ if n == 0 {
+ return None;
+ }
+
+ const_try_opt!(self.checked_prev_occurrence(weekday))
+ .checked_sub(Duration::weeks(n as i64 - 1))
+ }
// endregion: checked arithmetic
// region: saturating arithmetic
@@ -739,17 +1056,21 @@ impl Date {
/// ```
#[must_use = "This method does not mutate the original `Date`."]
pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
- ensure_value_in_range!(year in MIN_YEAR => MAX_YEAR);
+ ensure_ranged!(Year: year);
let ordinal = self.ordinal();
// Dates in January and February are unaffected by leap years.
if ordinal <= 59 {
- return Ok(Self::__from_ordinal_date_unchecked(year, ordinal));
+ // Safety: `ordinal` is not zero.
+ return Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) });
}
match (is_leap_year(self.year()), is_leap_year(year)) {
- (false, false) | (true, true) => Ok(Self::__from_ordinal_date_unchecked(year, ordinal)),
+ (false, false) | (true, true) => {
+ // Safety: `ordinal` is not zero.
+ Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) })
+ }
// February 29 does not exist in common years.
(true, false) if ordinal == 60 => Err(error::ComponentRange {
name: "day",
@@ -760,10 +1081,12 @@ impl Date {
}),
// We're going from a common year to a leap year. Shift dates in March and later by
// one day.
- (false, true) => Ok(Self::__from_ordinal_date_unchecked(year, ordinal + 1)),
+ // Safety: `ordinal` is not zero.
+ (false, true) => Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal + 1) }),
// We're going from a leap year to a common year. Shift dates in January and
// February by one day.
- (true, false) => Ok(Self::__from_ordinal_date_unchecked(year, ordinal - 1)),
+ // Safety: `ordinal` is not zero.
+ (true, false) => Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal - 1) }),
}
}
@@ -801,17 +1124,27 @@ impl Date {
/// ```
#[must_use = "This method does not mutate the original `Date`."]
pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
- // Days 1-28 are present in every month, so we can skip checking.
- if day == 0 || day >= 29 {
- ensure_value_in_range!(
- day conditionally in 1 => days_in_year_month(self.year(), self.month())
- );
+ match day {
+ 1..=28 => {}
+ 29..=31 if day <= days_in_year_month(self.year(), self.month()) => {}
+ _ => {
+ return Err(crate::error::ComponentRange {
+ name: "day",
+ minimum: 1,
+ maximum: days_in_year_month(self.year(), self.month()) as _,
+ value: day as _,
+ conditional_range: true,
+ });
+ }
}
- Ok(Self::__from_ordinal_date_unchecked(
- self.year(),
- (self.ordinal() as i16 - self.day() as i16 + day as i16) as _,
- ))
+ // Safety: `ordinal` is not zero.
+ Ok(unsafe {
+ Self::__from_ordinal_date_unchecked(
+ self.year(),
+ (self.ordinal() as i16 - self.day() as i16 + day as i16) as _,
+ )
+ })
}
// endregion replacement
}
@@ -1014,10 +1347,8 @@ impl Add<StdDuration> for Date {
type Output = Self;
fn add(self, duration: StdDuration) -> Self::Output {
- Self::from_julian_day(
- self.to_julian_day() + (duration.as_secs() / Second.per(Day) as u64) as i32,
- )
- .expect("overflow adding duration to date")
+ self.checked_add_std(duration)
+ .expect("overflow adding duration to date")
}
}
@@ -1036,10 +1367,8 @@ impl Sub<StdDuration> for Date {
type Output = Self;
fn sub(self, duration: StdDuration) -> Self::Output {
- Self::from_julian_day(
- self.to_julian_day() - (duration.as_secs() / Second.per(Day) as u64) as i32,
- )
- .expect("overflow subtracting duration from date")
+ self.checked_sub_std(duration)
+ .expect("overflow subtracting duration from date")
}
}
diff --git a/vendor/time/src/date_time.rs b/vendor/time/src/date_time.rs
index 819f6d36b..53cae5eb4 100644
--- a/vendor/time/src/date_time.rs
+++ b/vendor/time/src/date_time.rs
@@ -16,10 +16,16 @@ use std::io;
#[cfg(feature = "std")]
use std::time::SystemTime;
+use deranged::RangedI64;
+
use crate::convert::*;
use crate::date::{MAX_YEAR, MIN_YEAR};
#[cfg(feature = "formatting")]
use crate::formatting::Formattable;
+use crate::internal_macros::{
+ bug, cascade, const_try, const_try_opt, div_floor, ensure_ranged, expect_opt, impl_add_assign,
+ impl_sub_assign,
+};
#[cfg(feature = "parsing")]
use crate::parsing::{Parsable, Parsed};
use crate::{error, util, Date, Duration, Month, Time, UtcOffset, Weekday};
@@ -191,7 +197,10 @@ pub(crate) const fn maybe_offset_from_offset<O: MaybeOffset>(
// endregion const trait methods hacks
/// The Julian day of the Unix epoch.
-const UNIX_EPOCH_JULIAN_DAY: i32 = Date::__from_ordinal_date_unchecked(1970, 1).to_julian_day();
+// Safety: `ordinal` is not zero.
+#[allow(clippy::undocumented_unsafe_blocks)]
+const UNIX_EPOCH_JULIAN_DAY: i32 =
+ unsafe { Date::__from_ordinal_date_unchecked(1970, 1) }.to_julian_day();
pub struct DateTime<O: MaybeOffset> {
pub(crate) date: Date,
@@ -226,7 +235,8 @@ impl DateTime<offset_kind::None> {
impl DateTime<offset_kind::Fixed> {
pub const UNIX_EPOCH: Self = Self {
- date: Date::__from_ordinal_date_unchecked(1970, 1),
+ // Safety: `ordinal` is not zero.
+ date: unsafe { Date::__from_ordinal_date_unchecked(1970, 1) },
time: Time::MIDNIGHT,
offset: UtcOffset::UTC,
};
@@ -248,28 +258,27 @@ impl<O: MaybeOffset> DateTime<O> {
where
O: HasLogicalOffset,
{
- #[allow(clippy::missing_docs_in_private_items)]
- const MIN_TIMESTAMP: i64 = Date::MIN.midnight().assume_utc().unix_timestamp();
- #[allow(clippy::missing_docs_in_private_items)]
- const MAX_TIMESTAMP: i64 = Date::MAX
- .with_time(Time::__from_hms_nanos_unchecked(23, 59, 59, 999_999_999))
- .assume_utc()
- .unix_timestamp();
-
- ensure_value_in_range!(timestamp in MIN_TIMESTAMP => MAX_TIMESTAMP);
+ type Timestamp = RangedI64<
+ { Date::MIN.midnight().assume_utc().unix_timestamp() },
+ { Date::MAX.with_time(Time::MAX).assume_utc().unix_timestamp() },
+ >;
+ ensure_ranged!(Timestamp: timestamp);
// Use the unchecked method here, as the input validity has already been verified.
let date = Date::from_julian_day_unchecked(
- UNIX_EPOCH_JULIAN_DAY + div_floor!(timestamp, Second.per(Day) as i64) as i32,
+ UNIX_EPOCH_JULIAN_DAY + div_floor!(timestamp, Second::per(Day) as i64) as i32,
);
- let seconds_within_day = timestamp.rem_euclid(Second.per(Day) as _);
- let time = Time::__from_hms_nanos_unchecked(
- (seconds_within_day / Second.per(Hour) as i64) as _,
- ((seconds_within_day % Second.per(Hour) as i64) / Minute.per(Hour) as i64) as _,
- (seconds_within_day % Second.per(Minute) as i64) as _,
- 0,
- );
+ let seconds_within_day = timestamp.rem_euclid(Second::per(Day) as _);
+ // Safety: All values are in range.
+ let time = unsafe {
+ Time::__from_hms_nanos_unchecked(
+ (seconds_within_day / Second::per(Hour) as i64) as _,
+ ((seconds_within_day % Second::per(Hour) as i64) / Minute::per(Hour) as i64) as _,
+ (seconds_within_day % Second::per(Minute) as i64) as _,
+ 0,
+ )
+ };
Ok(Self {
date,
@@ -284,17 +293,20 @@ impl<O: MaybeOffset> DateTime<O> {
{
let datetime = const_try!(Self::from_unix_timestamp(div_floor!(
timestamp,
- Nanosecond.per(Second) as i128
+ Nanosecond::per(Second) as i128
) as i64));
Ok(Self {
date: datetime.date,
- time: Time::__from_hms_nanos_unchecked(
- datetime.hour(),
- datetime.minute(),
- datetime.second(),
- timestamp.rem_euclid(Nanosecond.per(Second) as _) as u32,
- ),
+ // Safety: `nanosecond` is in range due to `rem_euclid`.
+ time: unsafe {
+ Time::__from_hms_nanos_unchecked(
+ datetime.hour(),
+ datetime.minute(),
+ datetime.second(),
+ timestamp.rem_euclid(Nanosecond::per(Second) as _) as u32,
+ )
+ },
offset: maybe_offset_from_offset::<O>(UtcOffset::UTC),
})
}
@@ -455,9 +467,9 @@ impl<O: MaybeOffset> DateTime<O> {
let offset = maybe_offset_as_offset::<O>(self.offset).whole_seconds() as i64;
let days =
- (self.to_julian_day() as i64 - UNIX_EPOCH_JULIAN_DAY as i64) * Second.per(Day) as i64;
- let hours = self.hour() as i64 * Second.per(Hour) as i64;
- let minutes = self.minute() as i64 * Second.per(Minute) as i64;
+ (self.to_julian_day() as i64 - UNIX_EPOCH_JULIAN_DAY as i64) * Second::per(Day) as i64;
+ let hours = self.hour() as i64 * Second::per(Hour) as i64;
+ let minutes = self.minute() as i64 * Second::per(Minute) as i64;
let seconds = self.second() as i64;
days + hours + minutes + seconds - offset
}
@@ -466,7 +478,7 @@ impl<O: MaybeOffset> DateTime<O> {
where
O: HasLogicalOffset,
{
- self.unix_timestamp() as i128 * Nanosecond.per(Second) as i128 + self.nanosecond() as i128
+ self.unix_timestamp() as i128 * Nanosecond::per(Second) as i128 + self.nanosecond() as i128
}
// endregion unix timestamp getters
// endregion: getters
@@ -526,7 +538,8 @@ impl<O: MaybeOffset> DateTime<O> {
}
Some(DateTime {
- date: Date::__from_ordinal_date_unchecked(year, ordinal),
+ // Safety: `ordinal` is not zero.
+ date: unsafe { Date::__from_ordinal_date_unchecked(year, ordinal) },
time,
offset,
})
@@ -558,12 +571,12 @@ impl<O: MaybeOffset> DateTime<O> {
let mut ordinal = ordinal as i16;
// Cascade the values twice. This is needed because the values are adjusted twice above.
- cascade!(second in 0..Second.per(Minute) as i16 => minute);
- cascade!(second in 0..Second.per(Minute) as i16 => minute);
- cascade!(minute in 0..Minute.per(Hour) as i16 => hour);
- cascade!(minute in 0..Minute.per(Hour) as i16 => hour);
- cascade!(hour in 0..Hour.per(Day) as i8 => ordinal);
- cascade!(hour in 0..Hour.per(Day) as i8 => ordinal);
+ cascade!(second in 0..Second::per(Minute) as i16 => minute);
+ cascade!(second in 0..Second::per(Minute) as i16 => minute);
+ cascade!(minute in 0..Minute::per(Hour) as i16 => hour);
+ cascade!(minute in 0..Minute::per(Hour) as i16 => hour);
+ cascade!(hour in 0..Hour::per(Day) as i8 => ordinal);
+ cascade!(hour in 0..Hour::per(Day) as i8 => ordinal);
cascade!(ordinal => year);
debug_assert!(ordinal > 0);
@@ -572,12 +585,15 @@ impl<O: MaybeOffset> DateTime<O> {
(
year,
ordinal as _,
- Time::__from_hms_nanos_unchecked(
- hour as _,
- minute as _,
- second as _,
- self.nanosecond(),
- ),
+ // Safety: The cascades above ensure the values are in range.
+ unsafe {
+ Time::__from_hms_nanos_unchecked(
+ hour as _,
+ minute as _,
+ second as _,
+ self.nanosecond(),
+ )
+ },
)
}
// endregion to offset
@@ -653,6 +669,7 @@ impl<O: MaybeOffset> DateTime<O> {
// endregion saturating arithmetic
// region: replacement
+ #[must_use = "this does not modify the original value"]
pub const fn replace_time(self, time: Time) -> Self {
Self {
date: self.date,
@@ -661,6 +678,7 @@ impl<O: MaybeOffset> DateTime<O> {
}
}
+ #[must_use = "this does not modify the original value"]
pub const fn replace_date(self, date: Date) -> Self {
Self {
date,
@@ -669,6 +687,7 @@ impl<O: MaybeOffset> DateTime<O> {
}
}
+ #[must_use = "this does not modify the original value"]
pub const fn replace_date_time(self, date_time: DateTime<offset_kind::None>) -> Self
where
O: HasLogicalOffset,
@@ -680,6 +699,7 @@ impl<O: MaybeOffset> DateTime<O> {
}
}
+ #[must_use = "this does not modify the original value"]
pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
Ok(Self {
date: const_try!(self.date.replace_year(year)),
@@ -688,6 +708,7 @@ impl<O: MaybeOffset> DateTime<O> {
})
}
+ #[must_use = "this does not modify the original value"]
pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
Ok(Self {
date: const_try!(self.date.replace_month(month)),
@@ -696,6 +717,7 @@ impl<O: MaybeOffset> DateTime<O> {
})
}
+ #[must_use = "this does not modify the original value"]
pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
Ok(Self {
date: const_try!(self.date.replace_day(day)),
@@ -704,6 +726,7 @@ impl<O: MaybeOffset> DateTime<O> {
})
}
+ #[must_use = "this does not modify the original value"]
pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> {
Ok(Self {
date: self.date,
@@ -712,6 +735,7 @@ impl<O: MaybeOffset> DateTime<O> {
})
}
+ #[must_use = "this does not modify the original value"]
pub const fn replace_minute(self, minute: u8) -> Result<Self, error::ComponentRange> {
Ok(Self {
date: self.date,
@@ -720,6 +744,7 @@ impl<O: MaybeOffset> DateTime<O> {
})
}
+ #[must_use = "this does not modify the original value"]
pub const fn replace_second(self, second: u8) -> Result<Self, error::ComponentRange> {
Ok(Self {
date: self.date,
@@ -728,6 +753,7 @@ impl<O: MaybeOffset> DateTime<O> {
})
}
+ #[must_use = "this does not modify the original value"]
pub const fn replace_millisecond(
self,
millisecond: u16,
@@ -739,6 +765,7 @@ impl<O: MaybeOffset> DateTime<O> {
})
}
+ #[must_use = "this does not modify the original value"]
pub const fn replace_microsecond(
self,
microsecond: u32,
@@ -750,6 +777,7 @@ impl<O: MaybeOffset> DateTime<O> {
})
}
+ #[must_use = "this does not modify the original value"]
pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
Ok(Self {
date: self.date,
@@ -760,6 +788,7 @@ impl<O: MaybeOffset> DateTime<O> {
// Don't gate this on just having an offset, as `ZonedDateTime` cannot be set to an arbitrary
// offset.
+ #[must_use = "this does not modify the original value"]
pub const fn replace_offset(self, offset: UtcOffset) -> DateTime<offset_kind::Fixed>
where
O: IsOffsetKindFixed,
@@ -822,7 +851,9 @@ impl<O: MaybeOffset> DateTime<O> {
}
let (year, ordinal, time) = self.to_offset_raw(UtcOffset::UTC);
- let Ok(date) = Date::from_ordinal_date(year, ordinal) else { return false };
+ let Ok(date) = Date::from_ordinal_date(year, ordinal) else {
+ return false;
+ };
time.hour() == 23
&& time.minute() == 59
@@ -1156,7 +1187,7 @@ impl From<DateTime<offset_kind::Fixed>> for SystemTime {
impl From<js_sys::Date> for DateTime<offset_kind::Fixed> {
fn from(js_date: js_sys::Date) -> Self {
// get_time() returns milliseconds
- let timestamp_nanos = (js_date.get_time() * Nanosecond.per(Millisecond) as f64) as i128;
+ let timestamp_nanos = (js_date.get_time() * Nanosecond::per(Millisecond) as f64) as i128;
Self::from_unix_timestamp_nanos(timestamp_nanos)
.expect("invalid timestamp: Timestamp cannot fit in range")
}
@@ -1171,7 +1202,7 @@ impl From<DateTime<offset_kind::Fixed>> for js_sys::Date {
fn from(datetime: DateTime<offset_kind::Fixed>) -> Self {
// new Date() takes milliseconds
let timestamp =
- (datetime.unix_timestamp_nanos() / Nanosecond.per(Millisecond) as i128) as f64;
+ (datetime.unix_timestamp_nanos() / Nanosecond::per(Millisecond) as i128) as f64;
js_sys::Date::new(&timestamp.into())
}
}
diff --git a/vendor/time/src/duration.rs b/vendor/time/src/duration.rs
index 453d2254d..4b4134f9e 100644
--- a/vendor/time/src/duration.rs
+++ b/vendor/time/src/duration.rs
@@ -6,8 +6,13 @@ use core::iter::Sum;
use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
use core::time::Duration as StdDuration;
+use deranged::RangedI32;
+
use crate::convert::*;
use crate::error;
+use crate::internal_macros::{
+ const_try_opt, expect_opt, impl_add_assign, impl_div_assign, impl_mul_assign, impl_sub_assign,
+};
#[cfg(feature = "std")]
use crate::Instant;
@@ -20,11 +25,9 @@ pub(crate) enum Padding {
Optimize,
}
-impl Default for Padding {
- fn default() -> Self {
- Self::Optimize
- }
-}
+/// The type of the `nanosecond` field of `Duration`.
+type Nanoseconds =
+ RangedI32<{ -(Nanosecond::per(Second) as i32 - 1) }, { Nanosecond::per(Second) as i32 - 1 }>;
/// A span of time with nanosecond precision.
///
@@ -32,12 +35,13 @@ impl Default for Padding {
/// nanoseconds.
///
/// This implementation allows for negative durations, unlike [`core::time::Duration`].
-#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Duration {
/// Number of whole seconds.
seconds: i64,
/// Number of nanoseconds within the second. The sign always matches the `seconds` field.
- nanoseconds: i32, // always -10^9 < nanoseconds < 10^9
+ // Sign must match that of `seconds` (though this is not a safety requirement).
+ nanoseconds: Nanoseconds,
#[allow(clippy::missing_docs_in_private_items)]
padding: Padding,
}
@@ -51,10 +55,22 @@ impl fmt::Debug for Duration {
}
}
-/// This is adapted from the `std` implementation, which uses mostly bit
+impl Default for Duration {
+ fn default() -> Self {
+ Self {
+ seconds: 0,
+ nanoseconds: Nanoseconds::new_static::<0>(),
+ padding: Padding::Optimize,
+ }
+ }
+}
+
+/// This is adapted from the [`std` implementation][std], which uses mostly bit
/// operations to ensure the highest precision:
-/// https://github.com/rust-lang/rust/blob/3a37c2f0523c87147b64f1b8099fc9df22e8c53e/library/core/src/time.rs#L1262-L1340
+///
/// Changes from `std` are marked and explained below.
+///
+/// [std]: https://github.com/rust-lang/rust/blob/3a37c2f0523c87147b64f1b8099fc9df22e8c53e/library/core/src/time.rs#L1262-L1340
#[rustfmt::skip] // Skip `rustfmt` because it reformats the arguments of the macro weirdly.
macro_rules! try_from_secs {
(
@@ -87,7 +103,7 @@ macro_rules! try_from_secs {
// the input is less than 1 second
let t = <$double_ty>::from(mant) << ($offset + exp);
let nanos_offset = $mant_bits + $offset;
- let nanos_tmp = u128::from(Nanosecond.per(Second)) * u128::from(t);
+ let nanos_tmp = u128::from(Nanosecond::per(Second)) * u128::from(t);
let nanos = (nanos_tmp >> nanos_offset) as u32;
let rem_mask = (1 << nanos_offset) - 1;
@@ -101,7 +117,7 @@ macro_rules! try_from_secs {
// f32 does not have enough precision to trigger the second branch
// since it can not represent numbers between 0.999_999_940_395 and 1.0.
let nanos = nanos + add_ns as u32;
- if ($mant_bits == 23) || (nanos != Nanosecond.per(Second)) {
+ if ($mant_bits == 23) || (nanos != Nanosecond::per(Second)) {
(0, nanos)
} else {
(1, 0)
@@ -110,7 +126,7 @@ macro_rules! try_from_secs {
let secs = u64::from(mant >> ($mant_bits - exp));
let t = <$double_ty>::from((mant << exp) & MANT_MASK);
let nanos_offset = $mant_bits;
- let nanos_tmp = <$double_ty>::from(Nanosecond.per(Second)) * t;
+ let nanos_tmp = <$double_ty>::from(Nanosecond::per(Second)) * t;
let nanos = (nanos_tmp >> nanos_offset) as u32;
let rem_mask = (1 << nanos_offset) - 1;
@@ -126,7 +142,7 @@ macro_rules! try_from_secs {
// and 2.0. Bigger values result in even smaller precision of the
// fractional part.
let nanos = nanos + add_ns as u32;
- if ($mant_bits == 23) || (nanos != Nanosecond.per(Second)) {
+ if ($mant_bits == 23) || (nanos != Nanosecond::per(Second)) {
(secs, nanos)
} else {
(secs + 1, 0)
@@ -144,7 +160,7 @@ macro_rules! try_from_secs {
// following numbers -128..=127. The check above (exp < 63)
// doesn't cover i64::MIN as that is -2^63, so we have this
// additional case to handle the asymmetry of iN::MIN.
- break 'value Self::new_unchecked(i64::MIN, 0);
+ break 'value Self::new_ranged_unchecked(i64::MIN, Nanoseconds::new_static::<0>());
} else if $secs.is_nan() {
// Change from std: std doesn't differentiate between the error
// cases.
@@ -164,7 +180,8 @@ macro_rules! try_from_secs {
let secs_signed = ((secs as i64) ^ (mask as i64)) - (mask as i64);
#[allow(trivial_numeric_casts)]
let nanos_signed = ((nanos as i32) ^ (mask as i32)) - (mask as i32);
- Self::new_unchecked(secs_signed, nanos_signed)
+ // Safety: `nanos_signed` is in range.
+ unsafe { Self::new_unchecked(secs_signed, nanos_signed) }
}
}};
}
@@ -244,10 +261,10 @@ impl Duration {
pub const WEEK: Self = Self::weeks(1);
/// The minimum possible duration. Adding any negative duration to this will cause an overflow.
- pub const MIN: Self = Self::new_unchecked(i64::MIN, -((Nanosecond.per(Second) - 1) as i32));
+ pub const MIN: Self = Self::new_ranged(i64::MIN, Nanoseconds::MIN);
/// The maximum possible duration. Adding any positive duration to this will cause an overflow.
- pub const MAX: Self = Self::new_unchecked(i64::MAX, (Nanosecond.per(Second) - 1) as _);
+ pub const MAX: Self = Self::new_ranged(i64::MAX, Nanoseconds::MAX);
// endregion constants
// region: is_{sign}
@@ -259,7 +276,7 @@ impl Duration {
/// assert!(!1.nanoseconds().is_zero());
/// ```
pub const fn is_zero(self) -> bool {
- self.seconds == 0 && self.nanoseconds == 0
+ self.seconds == 0 && self.nanoseconds.get() == 0
}
/// Check if a duration is negative.
@@ -271,7 +288,7 @@ impl Duration {
/// assert!(!1.seconds().is_negative());
/// ```
pub const fn is_negative(self) -> bool {
- self.seconds < 0 || self.nanoseconds < 0
+ self.seconds < 0 || self.nanoseconds.get() < 0
}
/// Check if a duration is positive.
@@ -283,7 +300,7 @@ impl Duration {
/// assert!(!(-1).seconds().is_positive());
/// ```
pub const fn is_positive(self) -> bool {
- self.seconds > 0 || self.nanoseconds > 0
+ self.seconds > 0 || self.nanoseconds.get() > 0
}
// endregion is_{sign}
@@ -299,7 +316,10 @@ impl Duration {
/// assert_eq!((-1).seconds().abs(), 1.seconds());
/// ```
pub const fn abs(self) -> Self {
- Self::new_unchecked(self.seconds.saturating_abs(), self.nanoseconds.abs())
+ match self.seconds.checked_abs() {
+ Some(seconds) => Self::new_ranged_unchecked(seconds, self.nanoseconds.abs()),
+ None => Self::MAX,
+ }
}
/// Convert the existing `Duration` to a `std::time::Duration` and its sign. This returns a
@@ -312,21 +332,36 @@ impl Duration {
/// assert_eq!((-1).seconds().unsigned_abs(), 1.std_seconds());
/// ```
pub const fn unsigned_abs(self) -> StdDuration {
- StdDuration::new(self.seconds.unsigned_abs(), self.nanoseconds.unsigned_abs())
+ StdDuration::new(
+ self.seconds.unsigned_abs(),
+ self.nanoseconds.get().unsigned_abs(),
+ )
}
// endregion abs
// region: constructors
/// Create a new `Duration` without checking the validity of the components.
- pub(crate) const fn new_unchecked(seconds: i64, nanoseconds: i32) -> Self {
+ ///
+ /// # Safety
+ ///
+ /// - `nanoseconds` must be in the range `-999_999_999..=999_999_999`.
+ ///
+ /// While the sign of `nanoseconds` is required to be the same as the sign of `seconds`, this is
+ /// not a safety invariant.
+ pub(crate) const unsafe fn new_unchecked(seconds: i64, nanoseconds: i32) -> Self {
+ Self::new_ranged_unchecked(
+ seconds,
+ // Safety: The caller must uphold the safety invariants.
+ unsafe { Nanoseconds::new_unchecked(nanoseconds) },
+ )
+ }
+
+ /// Create a new `Duration` without checking the validity of the components.
+ pub(crate) const fn new_ranged_unchecked(seconds: i64, nanoseconds: Nanoseconds) -> Self {
if seconds < 0 {
- debug_assert!(nanoseconds <= 0);
- debug_assert!(nanoseconds > -(Nanosecond.per(Second) as i32));
+ debug_assert!(nanoseconds.get() <= 0);
} else if seconds > 0 {
- debug_assert!(nanoseconds >= 0);
- debug_assert!(nanoseconds < Nanosecond.per(Second) as _);
- } else {
- debug_assert!(nanoseconds.unsigned_abs() < Nanosecond.per(Second));
+ debug_assert!(nanoseconds.get() >= 0);
}
Self {
@@ -347,22 +382,46 @@ impl Duration {
/// ```
pub const fn new(mut seconds: i64, mut nanoseconds: i32) -> Self {
seconds = expect_opt!(
- seconds.checked_add(nanoseconds as i64 / Nanosecond.per(Second) as i64),
+ seconds.checked_add(nanoseconds as i64 / Nanosecond::per(Second) as i64),
"overflow constructing `time::Duration`"
);
- nanoseconds %= Nanosecond.per(Second) as i32;
+ nanoseconds %= Nanosecond::per(Second) as i32;
if seconds > 0 && nanoseconds < 0 {
// `seconds` cannot overflow here because it is positive.
seconds -= 1;
- nanoseconds += Nanosecond.per(Second) as i32;
+ nanoseconds += Nanosecond::per(Second) as i32;
} else if seconds < 0 && nanoseconds > 0 {
// `seconds` cannot overflow here because it is negative.
seconds += 1;
- nanoseconds -= Nanosecond.per(Second) as i32;
+ nanoseconds -= Nanosecond::per(Second) as i32;
+ }
+
+ // Safety: `nanoseconds` is in range due to the modulus above.
+ unsafe { Self::new_unchecked(seconds, nanoseconds) }
+ }
+
+ /// Create a new `Duration` with the provided seconds and nanoseconds.
+ pub(crate) const fn new_ranged(mut seconds: i64, mut nanoseconds: Nanoseconds) -> Self {
+ if seconds > 0 && nanoseconds.get() < 0 {
+ // `seconds` cannot overflow here because it is positive.
+ seconds -= 1;
+ // Safety: `nanoseconds` is negative with a maximum of 999,999,999, so adding a billion
+ // to it is guaranteed to result in an in-range value.
+ nanoseconds = unsafe {
+ Nanoseconds::new_unchecked(nanoseconds.get() + Nanosecond::per(Second) as i32)
+ };
+ } else if seconds < 0 && nanoseconds.get() > 0 {
+ // `seconds` cannot overflow here because it is negative.
+ seconds += 1;
+ // Safety: `nanoseconds` is positive with a minimum of -999,999,999, so subtracting a
+ // billion from it is guaranteed to result in an in-range value.
+ nanoseconds = unsafe {
+ Nanoseconds::new_unchecked(nanoseconds.get() - Nanosecond::per(Second) as i32)
+ };
}
- Self::new_unchecked(seconds, nanoseconds)
+ Self::new_ranged_unchecked(seconds, nanoseconds)
}
/// Create a new `Duration` with the given number of weeks. Equivalent to
@@ -374,7 +433,7 @@ impl Duration {
/// ```
pub const fn weeks(weeks: i64) -> Self {
Self::seconds(expect_opt!(
- weeks.checked_mul(Second.per(Week) as _),
+ weeks.checked_mul(Second::per(Week) as _),
"overflow constructing `time::Duration`"
))
}
@@ -388,7 +447,7 @@ impl Duration {
/// ```
pub const fn days(days: i64) -> Self {
Self::seconds(expect_opt!(
- days.checked_mul(Second.per(Day) as _),
+ days.checked_mul(Second::per(Day) as _),
"overflow constructing `time::Duration`"
))
}
@@ -402,7 +461,7 @@ impl Duration {
/// ```
pub const fn hours(hours: i64) -> Self {
Self::seconds(expect_opt!(
- hours.checked_mul(Second.per(Hour) as _),
+ hours.checked_mul(Second::per(Hour) as _),
"overflow constructing `time::Duration`"
))
}
@@ -416,7 +475,7 @@ impl Duration {
/// ```
pub const fn minutes(minutes: i64) -> Self {
Self::seconds(expect_opt!(
- minutes.checked_mul(Second.per(Minute) as _),
+ minutes.checked_mul(Second::per(Minute) as _),
"overflow constructing `time::Duration`"
))
}
@@ -428,7 +487,7 @@ impl Duration {
/// assert_eq!(Duration::seconds(1), 1_000.milliseconds());
/// ```
pub const fn seconds(seconds: i64) -> Self {
- Self::new_unchecked(seconds, 0)
+ Self::new_ranged_unchecked(seconds, Nanoseconds::new_static::<0>())
}
/// Creates a new `Duration` from the specified number of seconds represented as `f64`.
@@ -611,11 +670,14 @@ impl Duration {
/// assert_eq!(Duration::milliseconds(-1), (-1_000).microseconds());
/// ```
pub const fn milliseconds(milliseconds: i64) -> Self {
- Self::new_unchecked(
- milliseconds / Millisecond.per(Second) as i64,
- (milliseconds % Millisecond.per(Second) as i64 * Nanosecond.per(Millisecond) as i64)
- as _,
- )
+ // Safety: `nanoseconds` is guaranteed to be in range because of the modulus.
+ unsafe {
+ Self::new_unchecked(
+ milliseconds / Millisecond::per(Second) as i64,
+ (milliseconds % Millisecond::per(Second) as i64
+ * Nanosecond::per(Millisecond) as i64) as _,
+ )
+ }
}
/// Create a new `Duration` with the given number of microseconds.
@@ -626,11 +688,14 @@ impl Duration {
/// assert_eq!(Duration::microseconds(-1), (-1_000).nanoseconds());
/// ```
pub const fn microseconds(microseconds: i64) -> Self {
- Self::new_unchecked(
- microseconds / Microsecond.per(Second) as i64,
- (microseconds % Microsecond.per(Second) as i64 * Nanosecond.per(Microsecond) as i64)
- as _,
- )
+ // Safety: `nanoseconds` is guaranteed to be in range because of the modulus.
+ unsafe {
+ Self::new_unchecked(
+ microseconds / Microsecond::per(Second) as i64,
+ (microseconds % Microsecond::per(Second) as i64
+ * Nanosecond::per(Microsecond) as i64) as _,
+ )
+ }
}
/// Create a new `Duration` with the given number of nanoseconds.
@@ -641,10 +706,13 @@ impl Duration {
/// assert_eq!(Duration::nanoseconds(-1), (-1).microseconds() / 1_000);
/// ```
pub const fn nanoseconds(nanoseconds: i64) -> Self {
- Self::new_unchecked(
- nanoseconds / Nanosecond.per(Second) as i64,
- (nanoseconds % Nanosecond.per(Second) as i64) as _,
- )
+ // Safety: `nanoseconds` is guaranteed to be in range because of the modulus.
+ unsafe {
+ Self::new_unchecked(
+ nanoseconds / Nanosecond::per(Second) as i64,
+ (nanoseconds % Nanosecond::per(Second) as i64) as _,
+ )
+ }
}
/// Create a new `Duration` with the given number of nanoseconds.
@@ -652,14 +720,15 @@ impl Duration {
/// As the input range cannot be fully mapped to the output, this should only be used where it's
/// known to result in a valid value.
pub(crate) const fn nanoseconds_i128(nanoseconds: i128) -> Self {
- let seconds = nanoseconds / Nanosecond.per(Second) as i128;
- let nanoseconds = nanoseconds % Nanosecond.per(Second) as i128;
+ let seconds = nanoseconds / Nanosecond::per(Second) as i128;
+ let nanoseconds = nanoseconds % Nanosecond::per(Second) as i128;
if seconds > i64::MAX as i128 || seconds < i64::MIN as i128 {
crate::expect_failed("overflow constructing `time::Duration`");
}
- Self::new_unchecked(seconds as _, nanoseconds as _)
+ // Safety: `nanoseconds` is guaranteed to be in range because of the modulus above.
+ unsafe { Self::new_unchecked(seconds as _, nanoseconds as _) }
}
// endregion constructors
@@ -674,7 +743,7 @@ impl Duration {
/// assert_eq!((-6).days().whole_weeks(), 0);
/// ```
pub const fn whole_weeks(self) -> i64 {
- self.whole_seconds() / Second.per(Week) as i64
+ self.whole_seconds() / Second::per(Week) as i64
}
/// Get the number of whole days in the duration.
@@ -687,7 +756,7 @@ impl Duration {
/// assert_eq!((-23).hours().whole_days(), 0);
/// ```
pub const fn whole_days(self) -> i64 {
- self.whole_seconds() / Second.per(Day) as i64
+ self.whole_seconds() / Second::per(Day) as i64
}
/// Get the number of whole hours in the duration.
@@ -700,7 +769,7 @@ impl Duration {
/// assert_eq!((-59).minutes().whole_hours(), 0);
/// ```
pub const fn whole_hours(self) -> i64 {
- self.whole_seconds() / Second.per(Hour) as i64
+ self.whole_seconds() / Second::per(Hour) as i64
}
/// Get the number of whole minutes in the duration.
@@ -713,7 +782,7 @@ impl Duration {
/// assert_eq!((-59).seconds().whole_minutes(), 0);
/// ```
pub const fn whole_minutes(self) -> i64 {
- self.whole_seconds() / Second.per(Minute) as i64
+ self.whole_seconds() / Second::per(Minute) as i64
}
/// Get the number of whole seconds in the duration.
@@ -737,7 +806,7 @@ impl Duration {
/// assert_eq!((-1.5).seconds().as_seconds_f64(), -1.5);
/// ```
pub fn as_seconds_f64(self) -> f64 {
- self.seconds as f64 + self.nanoseconds as f64 / Nanosecond.per(Second) as f64
+ self.seconds as f64 + self.nanoseconds.get() as f64 / Nanosecond::per(Second) as f64
}
/// Get the number of fractional seconds in the duration.
@@ -748,7 +817,7 @@ impl Duration {
/// assert_eq!((-1.5).seconds().as_seconds_f32(), -1.5);
/// ```
pub fn as_seconds_f32(self) -> f32 {
- self.seconds as f32 + self.nanoseconds as f32 / Nanosecond.per(Second) as f32
+ self.seconds as f32 + self.nanoseconds.get() as f32 / Nanosecond::per(Second) as f32
}
/// Get the number of whole milliseconds in the duration.
@@ -761,8 +830,8 @@ impl Duration {
/// assert_eq!((-1).milliseconds().whole_milliseconds(), -1);
/// ```
pub const fn whole_milliseconds(self) -> i128 {
- self.seconds as i128 * Millisecond.per(Second) as i128
- + self.nanoseconds as i128 / Nanosecond.per(Millisecond) as i128
+ self.seconds as i128 * Millisecond::per(Second) as i128
+ + self.nanoseconds.get() as i128 / Nanosecond::per(Millisecond) as i128
}
/// Get the number of milliseconds past the number of whole seconds.
@@ -776,7 +845,7 @@ impl Duration {
/// ```
// Allow the lint, as the value is guaranteed to be less than 1000.
pub const fn subsec_milliseconds(self) -> i16 {
- (self.nanoseconds / Nanosecond.per(Millisecond) as i32) as _
+ (self.nanoseconds.get() / Nanosecond::per(Millisecond) as i32) as _
}
/// Get the number of whole microseconds in the duration.
@@ -789,8 +858,8 @@ impl Duration {
/// assert_eq!((-1).microseconds().whole_microseconds(), -1);
/// ```
pub const fn whole_microseconds(self) -> i128 {
- self.seconds as i128 * Microsecond.per(Second) as i128
- + self.nanoseconds as i128 / Nanosecond.per(Microsecond) as i128
+ self.seconds as i128 * Microsecond::per(Second) as i128
+ + self.nanoseconds.get() as i128 / Nanosecond::per(Microsecond) as i128
}
/// Get the number of microseconds past the number of whole seconds.
@@ -803,7 +872,7 @@ impl Duration {
/// assert_eq!((-1.0004).seconds().subsec_microseconds(), -400);
/// ```
pub const fn subsec_microseconds(self) -> i32 {
- self.nanoseconds / Nanosecond.per(Microsecond) as i32
+ self.nanoseconds.get() / Nanosecond::per(Microsecond) as i32
}
/// Get the number of nanoseconds in the duration.
@@ -816,7 +885,7 @@ impl Duration {
/// assert_eq!((-1).nanoseconds().whole_nanoseconds(), -1);
/// ```
pub const fn whole_nanoseconds(self) -> i128 {
- self.seconds as i128 * Nanosecond.per(Second) as i128 + self.nanoseconds as i128
+ self.seconds as i128 * Nanosecond::per(Second) as i128 + self.nanoseconds.get() as i128
}
/// Get the number of nanoseconds past the number of whole seconds.
@@ -829,6 +898,12 @@ impl Duration {
/// assert_eq!((-1.000_000_400).seconds().subsec_nanoseconds(), -400);
/// ```
pub const fn subsec_nanoseconds(self) -> i32 {
+ self.nanoseconds.get()
+ }
+
+ /// Get the number of nanoseconds past the number of whole seconds.
+ #[cfg(feature = "quickcheck")]
+ pub(crate) const fn subsec_nanoseconds_ranged(self) -> Nanoseconds {
self.nanoseconds
}
// endregion getters
@@ -844,18 +919,19 @@ impl Duration {
/// ```
pub const fn checked_add(self, rhs: Self) -> Option<Self> {
let mut seconds = const_try_opt!(self.seconds.checked_add(rhs.seconds));
- let mut nanoseconds = self.nanoseconds + rhs.nanoseconds;
+ let mut nanoseconds = self.nanoseconds.get() + rhs.nanoseconds.get();
- if nanoseconds >= Nanosecond.per(Second) as _ || seconds < 0 && nanoseconds > 0 {
- nanoseconds -= Nanosecond.per(Second) as i32;
+ if nanoseconds >= Nanosecond::per(Second) as _ || seconds < 0 && nanoseconds > 0 {
+ nanoseconds -= Nanosecond::per(Second) as i32;
seconds = const_try_opt!(seconds.checked_add(1));
- } else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0
+ } else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
{
- nanoseconds += Nanosecond.per(Second) as i32;
+ nanoseconds += Nanosecond::per(Second) as i32;
seconds = const_try_opt!(seconds.checked_sub(1));
}
- Some(Self::new_unchecked(seconds, nanoseconds))
+ // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
+ unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
}
/// Computes `self - rhs`, returning `None` if an overflow occurred.
@@ -868,18 +944,19 @@ impl Duration {
/// ```
pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
let mut seconds = const_try_opt!(self.seconds.checked_sub(rhs.seconds));
- let mut nanoseconds = self.nanoseconds - rhs.nanoseconds;
+ let mut nanoseconds = self.nanoseconds.get() - rhs.nanoseconds.get();
- if nanoseconds >= Nanosecond.per(Second) as _ || seconds < 0 && nanoseconds > 0 {
- nanoseconds -= Nanosecond.per(Second) as i32;
+ if nanoseconds >= Nanosecond::per(Second) as _ || seconds < 0 && nanoseconds > 0 {
+ nanoseconds -= Nanosecond::per(Second) as i32;
seconds = const_try_opt!(seconds.checked_add(1));
- } else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0
+ } else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
{
- nanoseconds += Nanosecond.per(Second) as i32;
+ nanoseconds += Nanosecond::per(Second) as i32;
seconds = const_try_opt!(seconds.checked_sub(1));
}
- Some(Self::new_unchecked(seconds, nanoseconds))
+ // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
+ unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
}
/// Computes `self * rhs`, returning `None` if an overflow occurred.
@@ -894,14 +971,15 @@ impl Duration {
/// ```
pub const fn checked_mul(self, rhs: i32) -> Option<Self> {
// Multiply nanoseconds as i64, because it cannot overflow that way.
- let total_nanos = self.nanoseconds as i64 * rhs as i64;
- let extra_secs = total_nanos / Nanosecond.per(Second) as i64;
- let nanoseconds = (total_nanos % Nanosecond.per(Second) as i64) as _;
+ let total_nanos = self.nanoseconds.get() as i64 * rhs as i64;
+ let extra_secs = total_nanos / Nanosecond::per(Second) as i64;
+ let nanoseconds = (total_nanos % Nanosecond::per(Second) as i64) as _;
let seconds = const_try_opt!(
const_try_opt!(self.seconds.checked_mul(rhs as _)).checked_add(extra_secs)
);
- Some(Self::new_unchecked(seconds, nanoseconds))
+ // Safety: `nanoseconds` is guaranteed to be in range because of the modulus above.
+ unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
}
/// Computes `self / rhs`, returning `None` if `rhs == 0` or if the result would overflow.
@@ -913,13 +991,16 @@ impl Duration {
/// assert_eq!(1.seconds().checked_div(0), None);
/// ```
pub const fn checked_div(self, rhs: i32) -> Option<Self> {
- let seconds = const_try_opt!(self.seconds.checked_div(rhs as i64));
- let carry = self.seconds - seconds * (rhs as i64);
- let extra_nanos =
- const_try_opt!((carry * Nanosecond.per(Second) as i64).checked_div(rhs as i64));
- let nanoseconds = const_try_opt!(self.nanoseconds.checked_div(rhs)) + (extra_nanos as i32);
+ let (secs, extra_secs) = (
+ const_try_opt!(self.seconds.checked_div(rhs as i64)),
+ self.seconds % (rhs as i64),
+ );
+ let (mut nanos, extra_nanos) = (self.nanoseconds.get() / rhs, self.nanoseconds.get() % rhs);
+ nanos += ((extra_secs * (Nanosecond::per(Second) as i64) + extra_nanos as i64)
+ / (rhs as i64)) as i32;
- Some(Self::new_unchecked(seconds, nanoseconds))
+ // Safety: `nanoseconds` is in range.
+ unsafe { Some(Self::new_unchecked(secs, nanos)) }
}
// endregion checked arithmetic
@@ -944,24 +1025,25 @@ impl Duration {
}
return Self::MIN;
}
- let mut nanoseconds = self.nanoseconds + rhs.nanoseconds;
+ let mut nanoseconds = self.nanoseconds.get() + rhs.nanoseconds.get();
- if nanoseconds >= Nanosecond.per(Second) as _ || seconds < 0 && nanoseconds > 0 {
- nanoseconds -= Nanosecond.per(Second) as i32;
+ if nanoseconds >= Nanosecond::per(Second) as _ || seconds < 0 && nanoseconds > 0 {
+ nanoseconds -= Nanosecond::per(Second) as i32;
seconds = match seconds.checked_add(1) {
Some(seconds) => seconds,
None => return Self::MAX,
};
- } else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0
+ } else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
{
- nanoseconds += Nanosecond.per(Second) as i32;
+ nanoseconds += Nanosecond::per(Second) as i32;
seconds = match seconds.checked_sub(1) {
Some(seconds) => seconds,
None => return Self::MIN,
};
}
- Self::new_unchecked(seconds, nanoseconds)
+ // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
+ unsafe { Self::new_unchecked(seconds, nanoseconds) }
}
/// Computes `self - rhs`, saturating if an overflow occurred.
@@ -984,24 +1066,25 @@ impl Duration {
}
return Self::MIN;
}
- let mut nanoseconds = self.nanoseconds - rhs.nanoseconds;
+ let mut nanoseconds = self.nanoseconds.get() - rhs.nanoseconds.get();
- if nanoseconds >= Nanosecond.per(Second) as _ || seconds < 0 && nanoseconds > 0 {
- nanoseconds -= Nanosecond.per(Second) as i32;
+ if nanoseconds >= Nanosecond::per(Second) as _ || seconds < 0 && nanoseconds > 0 {
+ nanoseconds -= Nanosecond::per(Second) as i32;
seconds = match seconds.checked_add(1) {
Some(seconds) => seconds,
None => return Self::MAX,
};
- } else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0
+ } else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
{
- nanoseconds += Nanosecond.per(Second) as i32;
+ nanoseconds += Nanosecond::per(Second) as i32;
seconds = match seconds.checked_sub(1) {
Some(seconds) => seconds,
None => return Self::MIN,
};
}
- Self::new_unchecked(seconds, nanoseconds)
+ // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
+ unsafe { Self::new_unchecked(seconds, nanoseconds) }
}
/// Computes `self * rhs`, saturating if an overflow occurred.
@@ -1018,9 +1101,9 @@ impl Duration {
/// ```
pub const fn saturating_mul(self, rhs: i32) -> Self {
// Multiply nanoseconds as i64, because it cannot overflow that way.
- let total_nanos = self.nanoseconds as i64 * rhs as i64;
- let extra_secs = total_nanos / Nanosecond.per(Second) as i64;
- let nanoseconds = (total_nanos % Nanosecond.per(Second) as i64) as _;
+ let total_nanos = self.nanoseconds.get() as i64 * rhs as i64;
+ let extra_secs = total_nanos / Nanosecond::per(Second) as i64;
+ let nanoseconds = (total_nanos % Nanosecond::per(Second) as i64) as _;
let (seconds, overflow1) = self.seconds.overflowing_mul(rhs as _);
if overflow1 {
if self.seconds > 0 && rhs > 0 || self.seconds < 0 && rhs < 0 {
@@ -1036,7 +1119,8 @@ impl Duration {
return Self::MIN;
}
- Self::new_unchecked(seconds, nanoseconds)
+ // Safety: `nanoseconds` is guaranteed to be in range because of to the modulus above.
+ unsafe { Self::new_unchecked(seconds, nanoseconds) }
}
// endregion saturating arithmetic
@@ -1094,13 +1178,13 @@ impl fmt::Display for Duration {
// Even if this produces a de-normal float, because we're rounding we don't really care.
let seconds = self.unsigned_abs().as_secs_f64();
- item!("d", seconds / Second.per(Day) as f64);
- item!("h", seconds / Second.per(Hour) as f64);
- item!("m", seconds / Second.per(Minute) as f64);
+ item!("d", seconds / Second::per(Day) as f64);
+ item!("h", seconds / Second::per(Hour) as f64);
+ item!("m", seconds / Second::per(Minute) as f64);
item!("s", seconds);
- item!("ms", seconds * Millisecond.per(Second) as f64);
- item!("µs", seconds * Microsecond.per(Second) as f64);
- item!("ns", seconds * Nanosecond.per(Second) as f64);
+ item!("ms", seconds * Millisecond::per(Second) as f64);
+ item!("µs", seconds * Microsecond::per(Second) as f64);
+ item!("ns", seconds * Nanosecond::per(Second) as f64);
} else {
// Precise, but verbose representation.
@@ -1119,25 +1203,25 @@ impl fmt::Display for Duration {
}
let seconds = self.seconds.unsigned_abs();
- let nanoseconds = self.nanoseconds.unsigned_abs();
+ let nanoseconds = self.nanoseconds.get().unsigned_abs();
- item!("d", seconds / Second.per(Day) as u64)?;
+ item!("d", seconds / Second::per(Day) as u64)?;
item!(
"h",
- seconds / Second.per(Hour) as u64 % Hour.per(Day) as u64
+ seconds / Second::per(Hour) as u64 % Hour::per(Day) as u64
)?;
item!(
"m",
- seconds / Second.per(Minute) as u64 % Minute.per(Hour) as u64
+ seconds / Second::per(Minute) as u64 % Minute::per(Hour) as u64
)?;
- item!("s", seconds % Second.per(Minute) as u64)?;
- item!("ms", nanoseconds / Nanosecond.per(Millisecond))?;
+ item!("s", seconds % Second::per(Minute) as u64)?;
+ item!("ms", nanoseconds / Nanosecond::per(Millisecond))?;
item!(
"µs",
- nanoseconds / Nanosecond.per(Microsecond) as u32
- % Microsecond.per(Millisecond) as u32
+ nanoseconds / Nanosecond::per(Microsecond) as u32
+ % Microsecond::per(Millisecond) as u32
)?;
- item!("ns", nanoseconds % Nanosecond.per(Microsecond) as u32)?;
+ item!("ns", nanoseconds % Nanosecond::per(Microsecond) as u32)?;
}
Ok(())
@@ -1169,6 +1253,7 @@ impl TryFrom<Duration> for StdDuration {
.map_err(|_| error::ConversionRange)?,
duration
.nanoseconds
+ .get()
.try_into()
.map_err(|_| error::ConversionRange)?,
))
@@ -1216,7 +1301,7 @@ impl Neg for Duration {
type Output = Self;
fn neg(self) -> Self::Output {
- Self::new_unchecked(-self.seconds, -self.nanoseconds)
+ Self::new_ranged_unchecked(-self.seconds, self.nanoseconds.neg())
}
}
@@ -1390,7 +1475,7 @@ impl PartialOrd<StdDuration> for Duration {
Some(
self.seconds
.cmp(&(rhs.as_secs() as _))
- .then_with(|| self.nanoseconds.cmp(&(rhs.subsec_nanos() as _))),
+ .then_with(|| self.nanoseconds.get().cmp(&(rhs.subsec_nanos() as _))),
)
}
}
diff --git a/vendor/time/src/error/mod.rs b/vendor/time/src/error/mod.rs
index 346b89f74..d2730c462 100644
--- a/vendor/time/src/error/mod.rs
+++ b/vendor/time/src/error/mod.rs
@@ -36,31 +36,47 @@ pub use parse_from_description::ParseFromDescription;
#[cfg(feature = "parsing")]
pub use try_from_parsed::TryFromParsed;
+#[cfg(feature = "parsing")]
+use crate::internal_macros::bug;
+
/// A unified error type for anything returned by a method in the time crate.
///
/// This can be used when you either don't know or don't care about the exact error returned.
/// `Result<_, time::Error>` (or its alias `time::Result<_>`) will work in these situations.
#[allow(missing_copy_implementations, variant_size_differences)]
-#[allow(clippy::missing_docs_in_private_items)] // variants only
#[non_exhaustive]
#[derive(Debug)]
pub enum Error {
+ #[allow(missing_docs)]
ConversionRange(ConversionRange),
+ #[allow(missing_docs)]
ComponentRange(ComponentRange),
#[cfg(feature = "local-offset")]
+ #[allow(missing_docs)]
IndeterminateOffset(IndeterminateOffset),
#[cfg(feature = "formatting")]
+ #[allow(missing_docs)]
Format(Format),
#[cfg(feature = "parsing")]
+ #[allow(missing_docs)]
ParseFromDescription(ParseFromDescription),
#[cfg(feature = "parsing")]
+ #[allow(missing_docs)]
#[non_exhaustive]
+ #[deprecated(
+ since = "0.3.28",
+ note = "no longer output. moved to the `ParseFromDescription` variant"
+ )]
UnexpectedTrailingCharacters,
#[cfg(feature = "parsing")]
+ #[allow(missing_docs)]
TryFromParsed(TryFromParsed),
#[cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc"))]
+ #[allow(missing_docs)]
InvalidFormatDescription(InvalidFormatDescription),
+ #[allow(missing_docs)]
DifferentVariant(DifferentVariant),
+ #[allow(missing_docs)]
InvalidVariant(InvalidVariant),
}
@@ -76,7 +92,8 @@ impl fmt::Display for Error {
#[cfg(feature = "parsing")]
Self::ParseFromDescription(e) => e.fmt(f),
#[cfg(feature = "parsing")]
- Self::UnexpectedTrailingCharacters => f.write_str("unexpected trailing characters"),
+ #[allow(deprecated)]
+ Self::UnexpectedTrailingCharacters => bug!("variant should not be used"),
#[cfg(feature = "parsing")]
Self::TryFromParsed(e) => e.fmt(f),
#[cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc"))]
@@ -100,7 +117,8 @@ impl std::error::Error for Error {
#[cfg(feature = "parsing")]
Self::ParseFromDescription(err) => Some(err),
#[cfg(feature = "parsing")]
- Self::UnexpectedTrailingCharacters => None,
+ #[allow(deprecated)]
+ Self::UnexpectedTrailingCharacters => bug!("variant should not be used"),
#[cfg(feature = "parsing")]
Self::TryFromParsed(err) => Some(err),
#[cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc"))]
diff --git a/vendor/time/src/error/parse.rs b/vendor/time/src/error/parse.rs
index b90ac74e7..09935b1c9 100644
--- a/vendor/time/src/error/parse.rs
+++ b/vendor/time/src/error/parse.rs
@@ -3,18 +3,23 @@
use core::fmt;
use crate::error::{self, ParseFromDescription, TryFromParsed};
+use crate::internal_macros::bug;
/// An error that occurred at some stage of parsing.
#[allow(variant_size_differences)]
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Parse {
- #[allow(clippy::missing_docs_in_private_items)]
+ #[allow(missing_docs)]
TryFromParsed(TryFromParsed),
- #[allow(clippy::missing_docs_in_private_items)]
+ #[allow(missing_docs)]
ParseFromDescription(ParseFromDescription),
/// The input should have ended, but there were characters remaining.
#[non_exhaustive]
+ #[deprecated(
+ since = "0.3.28",
+ note = "no longer output. moved to the `ParseFromDescription` variant"
+ )]
UnexpectedTrailingCharacters,
}
@@ -23,7 +28,8 @@ impl fmt::Display for Parse {
match self {
Self::TryFromParsed(err) => err.fmt(f),
Self::ParseFromDescription(err) => err.fmt(f),
- Self::UnexpectedTrailingCharacters => f.write_str("unexpected trailing characters"),
+ #[allow(deprecated)]
+ Self::UnexpectedTrailingCharacters => bug!("variant should not be used"),
}
}
}
@@ -34,7 +40,8 @@ impl std::error::Error for Parse {
match self {
Self::TryFromParsed(err) => Some(err),
Self::ParseFromDescription(err) => Some(err),
- Self::UnexpectedTrailingCharacters => None,
+ #[allow(deprecated)]
+ Self::UnexpectedTrailingCharacters => bug!("variant should not be used"),
}
}
}
@@ -78,7 +85,8 @@ impl From<Parse> for crate::Error {
match err {
Parse::TryFromParsed(err) => Self::TryFromParsed(err),
Parse::ParseFromDescription(err) => Self::ParseFromDescription(err),
- Parse::UnexpectedTrailingCharacters => Self::UnexpectedTrailingCharacters,
+ #[allow(deprecated)]
+ Parse::UnexpectedTrailingCharacters => bug!("variant should not be used"),
}
}
}
@@ -89,7 +97,8 @@ impl TryFrom<crate::Error> for Parse {
fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
match err {
crate::Error::ParseFromDescription(err) => Ok(Self::ParseFromDescription(err)),
- crate::Error::UnexpectedTrailingCharacters => Ok(Self::UnexpectedTrailingCharacters),
+ #[allow(deprecated)]
+ crate::Error::UnexpectedTrailingCharacters => bug!("variant should not be used"),
crate::Error::TryFromParsed(err) => Ok(Self::TryFromParsed(err)),
_ => Err(error::DifferentVariant),
}
diff --git a/vendor/time/src/error/parse_from_description.rs b/vendor/time/src/error/parse_from_description.rs
index 772f10d17..40124dce3 100644
--- a/vendor/time/src/error/parse_from_description.rs
+++ b/vendor/time/src/error/parse_from_description.rs
@@ -13,6 +13,9 @@ pub enum ParseFromDescription {
InvalidLiteral,
/// A dynamic component was not valid.
InvalidComponent(&'static str),
+ /// The input was expected to have ended, but there are characters that remain.
+ #[non_exhaustive]
+ UnexpectedTrailingCharacters,
}
impl fmt::Display for ParseFromDescription {
@@ -22,6 +25,9 @@ impl fmt::Display for ParseFromDescription {
Self::InvalidComponent(name) => {
write!(f, "the '{name}' component could not be parsed")
}
+ Self::UnexpectedTrailingCharacters => {
+ f.write_str("unexpected trailing characters; the end of input was expected")
+ }
}
}
}
diff --git a/vendor/time/src/ext.rs b/vendor/time/src/ext.rs
index 8b7759d8e..a2acc1101 100644
--- a/vendor/time/src/ext.rs
+++ b/vendor/time/src/ext.rs
@@ -117,31 +117,31 @@ impl NumericalDuration for f64 {
}
fn microseconds(self) -> Duration {
- Duration::nanoseconds((self * Nanosecond.per(Microsecond) as Self) as _)
+ Duration::nanoseconds((self * Nanosecond::per(Microsecond) as Self) as _)
}
fn milliseconds(self) -> Duration {
- Duration::nanoseconds((self * Nanosecond.per(Millisecond) as Self) as _)
+ Duration::nanoseconds((self * Nanosecond::per(Millisecond) as Self) as _)
}
fn seconds(self) -> Duration {
- Duration::nanoseconds((self * Nanosecond.per(Second) as Self) as _)
+ Duration::nanoseconds((self * Nanosecond::per(Second) as Self) as _)
}
fn minutes(self) -> Duration {
- Duration::nanoseconds((self * Nanosecond.per(Minute) as Self) as _)
+ Duration::nanoseconds((self * Nanosecond::per(Minute) as Self) as _)
}
fn hours(self) -> Duration {
- Duration::nanoseconds((self * Nanosecond.per(Hour) as Self) as _)
+ Duration::nanoseconds((self * Nanosecond::per(Hour) as Self) as _)
}
fn days(self) -> Duration {
- Duration::nanoseconds((self * Nanosecond.per(Day) as Self) as _)
+ Duration::nanoseconds((self * Nanosecond::per(Day) as Self) as _)
}
fn weeks(self) -> Duration {
- Duration::nanoseconds((self * Nanosecond.per(Week) as Self) as _)
+ Duration::nanoseconds((self * Nanosecond::per(Week) as Self) as _)
}
}
// endregion NumericalDuration
@@ -220,19 +220,19 @@ impl NumericalStdDuration for u64 {
}
fn std_minutes(self) -> StdDuration {
- StdDuration::from_secs(self * Second.per(Minute) as Self)
+ StdDuration::from_secs(self * Second::per(Minute) as Self)
}
fn std_hours(self) -> StdDuration {
- StdDuration::from_secs(self * Second.per(Hour) as Self)
+ StdDuration::from_secs(self * Second::per(Hour) as Self)
}
fn std_days(self) -> StdDuration {
- StdDuration::from_secs(self * Second.per(Day) as Self)
+ StdDuration::from_secs(self * Second::per(Day) as Self)
}
fn std_weeks(self) -> StdDuration {
- StdDuration::from_secs(self * Second.per(Week) as Self)
+ StdDuration::from_secs(self * Second::per(Week) as Self)
}
}
@@ -244,37 +244,37 @@ impl NumericalStdDuration for f64 {
fn std_microseconds(self) -> StdDuration {
assert!(self >= 0.);
- StdDuration::from_nanos((self * Nanosecond.per(Microsecond) as Self) as _)
+ StdDuration::from_nanos((self * Nanosecond::per(Microsecond) as Self) as _)
}
fn std_milliseconds(self) -> StdDuration {
assert!(self >= 0.);
- StdDuration::from_nanos((self * Nanosecond.per(Millisecond) as Self) as _)
+ StdDuration::from_nanos((self * Nanosecond::per(Millisecond) as Self) as _)
}
fn std_seconds(self) -> StdDuration {
assert!(self >= 0.);
- StdDuration::from_nanos((self * Nanosecond.per(Second) as Self) as _)
+ StdDuration::from_nanos((self * Nanosecond::per(Second) as Self) as _)
}
fn std_minutes(self) -> StdDuration {
assert!(self >= 0.);
- StdDuration::from_nanos((self * Nanosecond.per(Minute) as Self) as _)
+ StdDuration::from_nanos((self * Nanosecond::per(Minute) as Self) as _)
}
fn std_hours(self) -> StdDuration {
assert!(self >= 0.);
- StdDuration::from_nanos((self * Nanosecond.per(Hour) as Self) as _)
+ StdDuration::from_nanos((self * Nanosecond::per(Hour) as Self) as _)
}
fn std_days(self) -> StdDuration {
assert!(self >= 0.);
- StdDuration::from_nanos((self * Nanosecond.per(Day) as Self) as _)
+ StdDuration::from_nanos((self * Nanosecond::per(Day) as Self) as _)
}
fn std_weeks(self) -> StdDuration {
assert!(self >= 0.);
- StdDuration::from_nanos((self * Nanosecond.per(Week) as Self) as _)
+ StdDuration::from_nanos((self * Nanosecond::per(Week) as Self) as _)
}
}
// endregion NumericalStdDuration
diff --git a/vendor/time/src/format_description/component.rs b/vendor/time/src/format_description/component.rs
index 672559081..9119c0905 100644
--- a/vendor/time/src/format_description/component.rs
+++ b/vendor/time/src/format_description/component.rs
@@ -38,4 +38,7 @@ pub enum Component {
Ignore(modifier::Ignore),
/// A Unix timestamp.
UnixTimestamp(modifier::UnixTimestamp),
+ /// The end of input. Parsing this component will fail if there is any input remaining. This
+ /// component neither affects formatting nor consumes any input when parsing.
+ End(modifier::End),
}
diff --git a/vendor/time/src/format_description/modifier.rs b/vendor/time/src/format_description/modifier.rs
index cdac1ae97..3a57bb6f6 100644
--- a/vendor/time/src/format_description/modifier.rs
+++ b/vendor/time/src/format_description/modifier.rs
@@ -279,6 +279,13 @@ pub struct UnixTimestamp {
pub sign_is_mandatory: bool,
}
+/// The end of input.
+///
+/// There is currently not customization for this modifier.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct End;
+
/// Generate the provided code if and only if `pub` is present.
macro_rules! if_pub {
(pub $(#[$attr:meta])*; $($x:tt)*) => {
@@ -385,10 +392,10 @@ impl_const_default! {
/// Creates a modifier that indicates the stringified value contains [one or more
/// digits](SubsecondDigits::OneOrMore).
@pub Subsecond => Self { digits: SubsecondDigits::OneOrMore };
- /// Creates a modifier that indicates the value uses the `+` sign for all positive values
- /// and is [padded with zeroes](Padding::Zero).
+ /// Creates a modifier that indicates the value only uses a sign for negative values and is
+ /// [padded with zeroes](Padding::Zero).
@pub OffsetHour => Self {
- sign_is_mandatory: true,
+ sign_is_mandatory: false,
padding: Padding::Zero,
};
/// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
@@ -406,4 +413,6 @@ impl_const_default! {
precision: UnixTimestampPrecision::Second,
sign_is_mandatory: false,
};
+ /// Creates a modifier used to represent the end of input.
+ @pub End => End;
}
diff --git a/vendor/time/src/format_description/parse/ast.rs b/vendor/time/src/format_description/parse/ast.rs
index 12fc5d55d..c7fc5e05a 100644
--- a/vendor/time/src/format_description/parse/ast.rs
+++ b/vendor/time/src/format_description/parse/ast.rs
@@ -6,6 +6,7 @@ use alloc::vec::Vec;
use core::iter;
use super::{lexer, unused, Error, Location, Spanned, SpannedValue, Unused};
+use crate::internal_macros::bug;
/// One part of a complete format description.
pub(super) enum Item<'a> {
@@ -266,7 +267,9 @@ fn parse_component<
let mut modifiers = Vec::new();
let trailing_whitespace = loop {
- let Some(whitespace) = tokens.next_if_whitespace() else { break None };
+ let Some(whitespace) = tokens.next_if_whitespace() else {
+ break None;
+ };
// This is not necessary for proper parsing, but provides a much better error when a nested
// description is used where it's not allowed.
diff --git a/vendor/time/src/format_description/parse/format_item.rs b/vendor/time/src/format_description/parse/format_item.rs
index c0e64d92a..f33078ec4 100644
--- a/vendor/time/src/format_description/parse/format_item.rs
+++ b/vendor/time/src/format_description/parse/format_item.rs
@@ -6,6 +6,7 @@ use core::num::NonZeroU16;
use core::str::{self, FromStr};
use super::{ast, unused, Error, Span, Spanned};
+use crate::internal_macros::bug;
/// Parse an AST iterator into a sequence of format items.
pub(super) fn parse<'a>(
@@ -190,6 +191,8 @@ macro_rules! component_definition {
_component_span: Span,
) -> Result<Self, Error>
{
+ // rustc will complain if the modifier is empty.
+ #[allow(unused_mut)]
let mut this = Self {
$($field: None),*
};
@@ -280,6 +283,7 @@ component_definition! {
Day = "day" {
padding = "padding": Option<Padding> => padding,
},
+ End = "end" {},
Hour = "hour" {
padding = "padding": Option<Padding> => padding,
base = "repr": Option<HourBase> => is_12_hour_clock,
diff --git a/vendor/time/src/format_description/well_known/iso8601.rs b/vendor/time/src/format_description/well_known/iso8601.rs
index f19181a92..756f034ef 100644
--- a/vendor/time/src/format_description/well_known/iso8601.rs
+++ b/vendor/time/src/format_description/well_known/iso8601.rs
@@ -4,23 +4,9 @@ mod adt_hack;
use core::num::NonZeroU8;
-pub use self::adt_hack::{DoNotRelyOnWhatThisIs, EncodedConfig};
-
-/// A configuration for [`Iso8601`] that only parses values.
-const PARSING_ONLY: EncodedConfig = Config {
- formatted_components: FormattedComponents::None,
- use_separators: false,
- year_is_six_digits: false,
- date_kind: DateKind::Calendar,
- time_precision: TimePrecision::Hour {
- decimal_digits: None,
- },
- offset_precision: OffsetPrecision::Hour,
-}
-.encode();
-
-/// The default configuration for [`Iso8601`].
-const DEFAULT_CONFIG: EncodedConfig = Config::DEFAULT.encode();
+#[doc(hidden)]
+pub use self::adt_hack::DoNotRelyOnWhatThisIs;
+pub use self::adt_hack::EncodedConfig;
/// The format described in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html).
///
@@ -43,7 +29,7 @@ const DEFAULT_CONFIG: EncodedConfig = Config::DEFAULT.encode();
/// # Ok::<_, time::Error>(())
/// ```
#[derive(Clone, Copy, PartialEq, Eq)]
-pub struct Iso8601<const CONFIG: EncodedConfig = DEFAULT_CONFIG>;
+pub struct Iso8601<const CONFIG: EncodedConfig = { Config::DEFAULT.encode() }>;
impl<const CONFIG: EncodedConfig> core::fmt::Debug for Iso8601<CONFIG> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
@@ -53,7 +39,18 @@ impl<const CONFIG: EncodedConfig> core::fmt::Debug for Iso8601<CONFIG> {
}
}
-impl Iso8601<DEFAULT_CONFIG> {
+/// Define associated constants for `Iso8601`.
+macro_rules! define_assoc_consts {
+ ($($(#[$doc:meta])* $vis:vis const $const_name:ident = $format:expr;)*) => {$(
+ const $const_name: EncodedConfig = $format.encode();
+ impl Iso8601<$const_name> {
+ $(#[$doc])*
+ $vis const $const_name: Self = Self;
+ }
+ )*};
+}
+
+define_assoc_consts! {
/// An [`Iso8601`] with the default configuration.
///
/// The following is the default behavior:
@@ -66,15 +63,29 @@ impl Iso8601<DEFAULT_CONFIG> {
/// - The time has precision to the second and nine decimal digits.
/// - The UTC offset has precision to the minute.
///
- /// If you need different behavior, use [`Config::DEFAULT`] and [`Config`]'s methods to create
- /// a custom configuration.
- pub const DEFAULT: Self = Self;
-}
-
-impl Iso8601<PARSING_ONLY> {
+ /// If you need different behavior, use another associated constant. For full customization, use
+ /// [`Config::DEFAULT`] and [`Config`]'s methods to create a custom configuration.
+ pub const DEFAULT = Config::DEFAULT;
/// An [`Iso8601`] that can only be used for parsing. Using this to format a value is
/// unspecified behavior.
- pub const PARSING: Self = Self;
+ pub const PARSING = Config::PARSING;
+ /// An [`Iso8601`] that handles only the date, but is otherwise the same as [`Config::DEFAULT`].
+ pub const DATE = Config::DEFAULT.set_formatted_components(FormattedComponents::Date);
+ /// An [`Iso8601`] that handles only the time, but is otherwise the same as [`Config::DEFAULT`].
+ pub const TIME = Config::DEFAULT.set_formatted_components(FormattedComponents::Time);
+ /// An [`Iso8601`] that handles only the UTC offset, but is otherwise the same as
+ /// [`Config::DEFAULT`].
+ pub const OFFSET = Config::DEFAULT.set_formatted_components(FormattedComponents::Offset);
+ /// An [`Iso8601`] that handles the date and time, but is otherwise the same as
+ /// [`Config::DEFAULT`].
+ pub const DATE_TIME = Config::DEFAULT.set_formatted_components(FormattedComponents::DateTime);
+ /// An [`Iso8601`] that handles the date, time, and UTC offset. This is the same as
+ /// [`Config::DEFAULT`].
+ pub const DATE_TIME_OFFSET = Config::DEFAULT;
+ /// An [`Iso8601`] that handles the time and UTC offset, but is otherwise the same as
+ /// [`Config::DEFAULT`].
+ pub const TIME_OFFSET = Config::DEFAULT
+ .set_formatted_components(FormattedComponents::TimeOffset);
}
/// Which components to format.
@@ -114,19 +125,19 @@ pub enum TimePrecision {
/// Format the hour only. Minutes, seconds, and nanoseconds will be represented with the
/// specified number of decimal digits, if any.
Hour {
- #[allow(clippy::missing_docs_in_private_items)]
+ #[allow(missing_docs)]
decimal_digits: Option<NonZeroU8>,
},
/// Format the hour and minute. Seconds and nanoseconds will be represented with the specified
/// number of decimal digits, if any.
Minute {
- #[allow(clippy::missing_docs_in_private_items)]
+ #[allow(missing_docs)]
decimal_digits: Option<NonZeroU8>,
},
/// Format the hour, minute, and second. Nanoseconds will be represented with the specified
/// number of decimal digits, if any.
Second {
- #[allow(clippy::missing_docs_in_private_items)]
+ #[allow(missing_docs)]
decimal_digits: Option<NonZeroU8>,
},
}
@@ -186,6 +197,19 @@ impl Config {
offset_precision: OffsetPrecision::Minute,
};
+ /// A configuration that can only be used for parsing. Using this to format a value is
+ /// unspecified behavior.
+ const PARSING: Self = Self {
+ formatted_components: FormattedComponents::None,
+ use_separators: false,
+ year_is_six_digits: false,
+ date_kind: DateKind::Calendar,
+ time_precision: TimePrecision::Hour {
+ decimal_digits: None,
+ },
+ offset_precision: OffsetPrecision::Hour,
+ };
+
/// Set whether the format the date, time, and/or UTC offset.
pub const fn set_formatted_components(self, formatted_components: FormattedComponents) -> Self {
Self {
diff --git a/vendor/time/src/format_description/well_known/iso8601/adt_hack.rs b/vendor/time/src/format_description/well_known/iso8601/adt_hack.rs
index 1fdecaf26..12b1c725f 100644
--- a/vendor/time/src/format_description/well_known/iso8601/adt_hack.rs
+++ b/vendor/time/src/format_description/well_known/iso8601/adt_hack.rs
@@ -49,11 +49,10 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
}
impl Config {
- /// Encode the configuration, permitting it to be used as a const parameter of
- /// [`Iso8601`](super::Iso8601).
+ /// Encode the configuration, permitting it to be used as a const parameter of [`Iso8601`].
///
- /// The value returned by this method must only be used as a const parameter to
- /// [`Iso8601`](super::Iso8601). Any other usage is unspecified behavior.
+ /// The value returned by this method must only be used as a const parameter to [`Iso8601`]. Any
+ /// other usage is unspecified behavior.
pub const fn encode(&self) -> EncodedConfig {
let mut bytes = [0; EncodedConfig::BITS as usize / 8];
diff --git a/vendor/time/src/formatting/formattable.rs b/vendor/time/src/formatting/formattable.rs
index 2b4b35088..cad1d482d 100644
--- a/vendor/time/src/formatting/formattable.rs
+++ b/vendor/time/src/formatting/formattable.rs
@@ -59,7 +59,7 @@ mod sealed {
}
// region: custom formats
-impl<'a> sealed::Sealed for FormatItem<'a> {
+impl sealed::Sealed for FormatItem<'_> {
fn format_into(
&self,
output: &mut impl io::Write,
@@ -80,7 +80,7 @@ impl<'a> sealed::Sealed for FormatItem<'a> {
}
}
-impl<'a> sealed::Sealed for [FormatItem<'a>] {
+impl sealed::Sealed for [FormatItem<'_>] {
fn format_into(
&self,
output: &mut impl io::Write,
diff --git a/vendor/time/src/formatting/iso8601.rs b/vendor/time/src/formatting/iso8601.rs
index 29d443ef4..67bc66b21 100644
--- a/vendor/time/src/formatting/iso8601.rs
+++ b/vendor/time/src/formatting/iso8601.rs
@@ -85,17 +85,17 @@ pub(super) fn format_time<const CONFIG: EncodedConfig>(
match Iso8601::<CONFIG>::TIME_PRECISION {
TimePrecision::Hour { decimal_digits } => {
let hours = (hours as f64)
- + (minutes as f64) / Minute.per(Hour) as f64
- + (seconds as f64) / Second.per(Hour) as f64
- + (nanoseconds as f64) / Nanosecond.per(Hour) as f64;
+ + (minutes as f64) / Minute::per(Hour) as f64
+ + (seconds as f64) / Second::per(Hour) as f64
+ + (nanoseconds as f64) / Nanosecond::per(Hour) as f64;
format_float(output, hours, 2, decimal_digits)?;
}
TimePrecision::Minute { decimal_digits } => {
bytes += format_number_pad_zero::<2>(output, hours)?;
bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b":")?;
let minutes = (minutes as f64)
- + (seconds as f64) / Second.per(Minute) as f64
- + (nanoseconds as f64) / Nanosecond.per(Minute) as f64;
+ + (seconds as f64) / Second::per(Minute) as f64
+ + (nanoseconds as f64) / Nanosecond::per(Minute) as f64;
bytes += format_float(output, minutes, 2, decimal_digits)?;
}
TimePrecision::Second { decimal_digits } => {
@@ -103,7 +103,7 @@ pub(super) fn format_time<const CONFIG: EncodedConfig>(
bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b":")?;
bytes += format_number_pad_zero::<2>(output, minutes)?;
bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b":")?;
- let seconds = (seconds as f64) + (nanoseconds as f64) / Nanosecond.per(Second) as f64;
+ let seconds = (seconds as f64) + (nanoseconds as f64) / Nanosecond::per(Second) as f64;
bytes += format_float(output, seconds, 2, decimal_digits)?;
}
}
diff --git a/vendor/time/src/formatting/mod.rs b/vendor/time/src/formatting/mod.rs
index e5017063a..a22742236 100644
--- a/vendor/time/src/formatting/mod.rs
+++ b/vendor/time/src/formatting/mod.rs
@@ -47,75 +47,22 @@ pub(crate) trait DigitCount {
/// The number of digits in the stringified value.
fn num_digits(self) -> u8;
}
-impl DigitCount for u8 {
- fn num_digits(self) -> u8 {
- // Using a lookup table as with u32 is *not* faster in standalone benchmarks.
- if self < 10 {
- 1
- } else if self < 100 {
- 2
- } else {
- 3
- }
- }
-}
-impl DigitCount for u16 {
- fn num_digits(self) -> u8 {
- // Using a lookup table as with u32 is *not* faster in standalone benchmarks.
- if self < 10 {
- 1
- } else if self < 100 {
- 2
- } else if self < 1_000 {
- 3
- } else if self < 10_000 {
- 4
- } else {
- 5
- }
- }
-}
-impl DigitCount for u32 {
- fn num_digits(self) -> u8 {
- /// Lookup table
- const TABLE: &[u64] = &[
- 0x0001_0000_0000,
- 0x0001_0000_0000,
- 0x0001_0000_0000,
- 0x0001_FFFF_FFF6,
- 0x0002_0000_0000,
- 0x0002_0000_0000,
- 0x0002_FFFF_FF9C,
- 0x0003_0000_0000,
- 0x0003_0000_0000,
- 0x0003_FFFF_FC18,
- 0x0004_0000_0000,
- 0x0004_0000_0000,
- 0x0004_0000_0000,
- 0x0004_FFFF_D8F0,
- 0x0005_0000_0000,
- 0x0005_0000_0000,
- 0x0005_FFFE_7960,
- 0x0006_0000_0000,
- 0x0006_0000_0000,
- 0x0006_FFF0_BDC0,
- 0x0007_0000_0000,
- 0x0007_0000_0000,
- 0x0007_0000_0000,
- 0x0007_FF67_6980,
- 0x0008_0000_0000,
- 0x0008_0000_0000,
- 0x0008_FA0A_1F00,
- 0x0009_0000_0000,
- 0x0009_0000_0000,
- 0x0009_C465_3600,
- 0x000A_0000_0000,
- 0x000A_0000_0000,
- ];
- ((self as u64 + TABLE[31_u32.saturating_sub(self.leading_zeros()) as usize]) >> 32) as _
- }
+/// A macro to generate implementations of `DigitCount` for unsigned integers.
+macro_rules! impl_digit_count {
+ ($($t:ty),* $(,)?) => {
+ $(impl DigitCount for $t {
+ fn num_digits(self) -> u8 {
+ match self.checked_ilog10() {
+ Some(n) => (n as u8) + 1,
+ None => 1,
+ }
+ }
+ })*
+ };
}
+
+impl_digit_count!(u8, u16, u32);
// endregion extension trait
/// Write all bytes to the output, returning the number of bytes written.
@@ -250,7 +197,19 @@ pub(crate) fn format_component(
(UnixTimestamp(modifier), Some(date), Some(time), Some(offset)) => {
fmt_unix_timestamp(output, date, time, offset, modifier)?
}
- _ => return Err(error::Format::InsufficientTypeInformation),
+ (End(modifier::End {}), ..) => 0,
+
+ // This is functionally the same as a wildcard arm, but it will cause an error if a new
+ // component is added. This is to avoid a bug where a new component, the code compiles, and
+ // formatting fails.
+ // Allow unreachable patterns because some branches may be fully matched above.
+ #[allow(unreachable_patterns)]
+ (
+ Day(_) | Month(_) | Ordinal(_) | Weekday(_) | WeekNumber(_) | Year(_) | Hour(_)
+ | Minute(_) | Period(_) | Second(_) | Subsecond(_) | OffsetHour(_) | OffsetMinute(_)
+ | OffsetSecond(_) | Ignore(_) | UnixTimestamp(_) | End(_),
+ ..,
+ ) => return Err(error::Format::InsufficientTypeInformation),
})
}
@@ -532,11 +491,13 @@ fn fmt_unix_timestamp(
}
modifier::UnixTimestampPrecision::Millisecond => format_number_pad_none(
output,
- (date_time.unix_timestamp_nanos() / Nanosecond.per(Millisecond) as i128).unsigned_abs(),
+ (date_time.unix_timestamp_nanos() / Nanosecond::per(Millisecond) as i128)
+ .unsigned_abs(),
),
modifier::UnixTimestampPrecision::Microsecond => format_number_pad_none(
output,
- (date_time.unix_timestamp_nanos() / Nanosecond.per(Microsecond) as i128).unsigned_abs(),
+ (date_time.unix_timestamp_nanos() / Nanosecond::per(Microsecond) as i128)
+ .unsigned_abs(),
),
modifier::UnixTimestampPrecision::Nanosecond => {
format_number_pad_none(output, date_time.unix_timestamp_nanos().unsigned_abs())
diff --git a/vendor/time/src/instant.rs b/vendor/time/src/instant.rs
index 58579b101..706c759c4 100644
--- a/vendor/time/src/instant.rs
+++ b/vendor/time/src/instant.rs
@@ -6,6 +6,7 @@ use core::ops::{Add, Sub};
use core::time::Duration as StdDuration;
use std::time::Instant as StdInstant;
+use crate::internal_macros::{impl_add_assign, impl_sub_assign};
use crate::Duration;
/// A measurement of a monotonically non-decreasing clock. Opaque and useful only with [`Duration`].
diff --git a/vendor/time/src/internal_macros.rs b/vendor/time/src/internal_macros.rs
new file mode 100644
index 000000000..857138983
--- /dev/null
+++ b/vendor/time/src/internal_macros.rs
@@ -0,0 +1,197 @@
+//! Macros for use within the library. They are not publicly available.
+
+/// 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;
+ }
+ }
+ )+};
+}
+
+/// Implement `AddAssign` for the provided types.
+macro_rules! impl_add_assign {
+ ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
+ $crate::internal_macros::__impl_assign!(
+ + AddAssign add_assign $target : $($(#[$attr])* $t),+
+ );
+ };
+}
+
+/// Implement `SubAssign` for the provided types.
+macro_rules! impl_sub_assign {
+ ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
+ $crate::internal_macros::__impl_assign!(
+ - SubAssign sub_assign $target : $($(#[$attr])* $t),+
+ );
+ };
+}
+
+/// Implement `MulAssign` for the provided types.
+macro_rules! impl_mul_assign {
+ ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
+ $crate::internal_macros::__impl_assign!(
+ * MulAssign mul_assign $target : $($(#[$attr])* $t),+
+ );
+ };
+}
+
+/// Implement `DivAssign` for the provided types.
+macro_rules! impl_div_assign {
+ ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
+ $crate::internal_macros::__impl_assign!(
+ / DivAssign div_assign $target : $($(#[$attr])* $t),+
+ );
+ };
+}
+
+/// Division of integers, rounding the resulting value towards negative infinity.
+macro_rules! div_floor {
+ ($a:expr, $b:expr) => {{
+ let _a = $a;
+ let _b = $b;
+
+ let (_quotient, _remainder) = (_a / _b, _a % _b);
+
+ if (_remainder > 0 && _b < 0) || (_remainder < 0 && _b > 0) {
+ _quotient - 1
+ } else {
+ _quotient
+ }
+ }};
+}
+
+/// 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:expr => $to:tt) => {
+ #[allow(unused_comparisons, unused_assignments)]
+ let min = $min;
+ let max = $max;
+ if $from >= max {
+ $from -= max - min;
+ $to += 1;
+ } else if $from < min {
+ $from += max - min;
+ $to -= 1;
+ }
+ };
+
+ // 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;
+ }
+ };
+}
+
+/// Constructs a ranged integer, returning a `ComponentRange` error if the value is out of range.
+macro_rules! ensure_ranged {
+ ($type:ident : $value:ident) => {
+ match $type::new($value) {
+ Some(val) => val,
+ None => {
+ #[allow(trivial_numeric_casts)]
+ return Err(crate::error::ComponentRange {
+ name: stringify!($value),
+ minimum: $type::MIN.get() as _,
+ maximum: $type::MAX.get() as _,
+ value: $value as _,
+ conditional_range: false,
+ });
+ }
+ }
+ };
+
+ ($type:ident : $value:ident $(as $as_type:ident)? * $factor:expr) => {
+ match ($value $(as $as_type)?).checked_mul($factor) {
+ Some(val) => match $type::new(val) {
+ Some(val) => val,
+ None => {
+ #[allow(trivial_numeric_casts)]
+ return Err(crate::error::ComponentRange {
+ name: stringify!($value),
+ minimum: $type::MIN.get() as i64 / $factor as i64,
+ maximum: $type::MAX.get() as i64 / $factor as i64,
+ value: $value as _,
+ conditional_range: false,
+ });
+ }
+ },
+ None => {
+ return Err(crate::error::ComponentRange {
+ name: stringify!($value),
+ minimum: $type::MIN.get() as i64 / $factor as i64,
+ maximum: $type::MAX.get() as i64 / $factor as i64,
+ value: $value as _,
+ conditional_range: false,
+ });
+ }
+ }
+ };
+}
+
+/// 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),
+ }
+ };
+}
+
+/// 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,
+ }
+ };
+}
+
+/// 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),
+ }
+ };
+}
+
+/// `unreachable!()`, but better.
+macro_rules! bug {
+ () => { compile_error!("provide an error message to help fix a possible bug") };
+ ($descr:literal $($rest:tt)?) => {
+ panic!(concat!("internal error: ", $descr) $($rest)?)
+ }
+}
+
+pub(crate) use {
+ __impl_assign, bug, cascade, const_try, const_try_opt, div_floor, ensure_ranged, expect_opt,
+ impl_add_assign, impl_div_assign, impl_mul_assign, impl_sub_assign,
+};
diff --git a/vendor/time/src/lib.rs b/vendor/time/src/lib.rs
index 2ab59cf8e..110c28648 100644
--- a/vendor/time/src/lib.rs
+++ b/vendor/time/src/lib.rs
@@ -76,55 +76,7 @@
#![doc(html_playground_url = "https://play.rust-lang.org")]
#![cfg_attr(__time_03_docs, feature(doc_auto_cfg, doc_notable_trait))]
-#![cfg_attr(coverage_nightly, feature(no_coverage))]
#![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,
- 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::uninlined_format_args,
- 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))))]
@@ -133,185 +85,6 @@
#[cfg(feature = "alloc")]
extern crate alloc;
-// TODO(jhpratt) remove this after a while
-#[cfg(unsound_local_offset)]
-compile_error!(
- "The `unsound_local_offset` flag was removed in time 0.3.18. If you need this functionality, \
- see the `time::util::local_offset::set_soundness` function."
-);
-
-// 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;
- }
- }
- )+};
-}
-
-/// 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),+);
- };
-}
-
-/// 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),+);
- };
-}
-
-/// 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),+);
- };
-}
-
-/// 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),+);
- };
-}
-
-/// Division of integers, rounding the resulting value towards negative infinity.
-macro_rules! div_floor {
- ($a:expr, $b:expr) => {{
- let _a = $a;
- let _b = $b;
-
- let (_quotient, _remainder) = (_a / _b, _a % _b);
-
- if (_remainder > 0 && _b < 0) || (_remainder < 0 && _b > 0) {
- _quotient - 1
- } else {
- _quotient
- }
- }};
-}
-
-/// 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:expr => $to:tt) => {
- #[allow(unused_comparisons, unused_assignments)]
- let min = $min;
- let max = $max;
- if $from >= max {
- $from -= max - min;
- $to += 1;
- } else if $from < min {
- $from += max - min;
- $to -= 1;
- }
- };
-
- // 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 `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,
- });
- }
- }};
-
- ($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,
- });
- }
- }};
-}
-
-/// 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),
- }
- };
-}
-
-/// 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,
- }
- };
-}
-
-/// 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),
- }
- };
-}
-
-/// `unreachable!()`, but better.
-macro_rules! bug {
- () => { compile_error!("provide an error message to help fix a possible bug") };
- ($descr:literal $($rest:tt)?) => {
- panic!(concat!("internal error: ", $descr) $($rest)?)
- }
-}
-// endregion macros
-
mod date;
mod date_time;
mod duration;
@@ -323,6 +96,7 @@ pub mod format_description;
pub mod formatting;
#[cfg(feature = "std")]
mod instant;
+mod internal_macros;
#[cfg(feature = "macros")]
pub mod macros;
mod month;
@@ -345,8 +119,7 @@ mod utc_offset;
pub mod util;
mod weekday;
-// Not public yet.
-use time_core::convert;
+pub use time_core::convert;
pub use crate::date::Date;
use crate::date_time::DateTime;
diff --git a/vendor/time/src/month.rs b/vendor/time/src/month.rs
index 0c657e982..ea3480f00 100644
--- a/vendor/time/src/month.rs
+++ b/vendor/time/src/month.rs
@@ -8,21 +8,32 @@ use self::Month::*;
use crate::error;
/// Months of the year.
-#[allow(clippy::missing_docs_in_private_items)] // variants
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Month {
+ #[allow(missing_docs)]
January = 1,
+ #[allow(missing_docs)]
February = 2,
+ #[allow(missing_docs)]
March = 3,
+ #[allow(missing_docs)]
April = 4,
+ #[allow(missing_docs)]
May = 5,
+ #[allow(missing_docs)]
June = 6,
+ #[allow(missing_docs)]
July = 7,
+ #[allow(missing_docs)]
August = 8,
+ #[allow(missing_docs)]
September = 9,
+ #[allow(missing_docs)]
October = 10,
+ #[allow(missing_docs)]
November = 11,
+ #[allow(missing_docs)]
December = 12,
}
@@ -97,6 +108,60 @@ impl Month {
December => January,
}
}
+
+ /// Get n-th next month.
+ ///
+ /// ```rust
+ /// # use time::Month;
+ /// assert_eq!(Month::January.nth_next(4), Month::May);
+ /// assert_eq!(Month::July.nth_next(9), Month::April);
+ /// ```
+ pub const fn nth_next(self, n: u8) -> Self {
+ match (self as u8 - 1 + n % 12) % 12 {
+ 0 => January,
+ 1 => February,
+ 2 => March,
+ 3 => April,
+ 4 => May,
+ 5 => June,
+ 6 => July,
+ 7 => August,
+ 8 => September,
+ 9 => October,
+ 10 => November,
+ val => {
+ debug_assert!(val == 11);
+ December
+ }
+ }
+ }
+
+ /// Get n-th previous month.
+ ///
+ /// ```rust
+ /// # use time::Month;
+ /// assert_eq!(Month::January.nth_prev(4), Month::September);
+ /// assert_eq!(Month::July.nth_prev(9), Month::October);
+ /// ```
+ pub const fn nth_prev(self, n: u8) -> Self {
+ match self as i8 - 1 - (n % 12) as i8 {
+ 1 | -11 => February,
+ 2 | -10 => March,
+ 3 | -9 => April,
+ 4 | -8 => May,
+ 5 | -7 => June,
+ 6 | -6 => July,
+ 7 | -5 => August,
+ 8 | -4 => September,
+ 9 | -3 => October,
+ 10 | -2 => November,
+ 11 | -1 => December,
+ val => {
+ debug_assert!(val == 0);
+ January
+ }
+ }
+ }
}
impl fmt::Display for Month {
diff --git a/vendor/time/src/offset_date_time.rs b/vendor/time/src/offset_date_time.rs
index d979174e1..e88097fe3 100644
--- a/vendor/time/src/offset_date_time.rs
+++ b/vendor/time/src/offset_date_time.rs
@@ -16,6 +16,7 @@ use std::time::SystemTime;
use crate::date_time::offset_kind;
#[cfg(feature = "formatting")]
use crate::formatting::Formattable;
+use crate::internal_macros::{const_try, const_try_opt};
#[cfg(feature = "parsing")]
use crate::parsing::Parsable;
use crate::{error, Date, DateTime, Duration, Month, PrimitiveDateTime, Time, UtcOffset, Weekday};
diff --git a/vendor/time/src/parsing/component.rs b/vendor/time/src/parsing/component.rs
index 23035893e..42d15e9f6 100644
--- a/vendor/time/src/parsing/component.rs
+++ b/vendor/time/src/parsing/component.rs
@@ -316,12 +316,12 @@ pub(crate) fn parse_unix_timestamp(
let ParsedItem(input, sign) = opt(sign)(input);
let ParsedItem(input, nano_timestamp) = match modifiers.precision {
modifier::UnixTimestampPrecision::Second => {
- n_to_m_digits::<1, 14, u128>(input)?.map(|val| val * Nanosecond.per(Second) as u128)
+ n_to_m_digits::<1, 14, u128>(input)?.map(|val| val * Nanosecond::per(Second) as u128)
}
modifier::UnixTimestampPrecision::Millisecond => n_to_m_digits::<1, 17, u128>(input)?
- .map(|val| val * Nanosecond.per(Millisecond) as u128),
+ .map(|val| val * Nanosecond::per(Millisecond) as u128),
modifier::UnixTimestampPrecision::Microsecond => n_to_m_digits::<1, 20, u128>(input)?
- .map(|val| val * Nanosecond.per(Microsecond) as u128),
+ .map(|val| val * Nanosecond::per(Microsecond) as u128),
modifier::UnixTimestampPrecision::Nanosecond => n_to_m_digits::<1, 23, _>(input)?,
};
@@ -331,3 +331,15 @@ pub(crate) fn parse_unix_timestamp(
_ => Some(ParsedItem(input, nano_timestamp as _)),
}
}
+
+/// Parse the `end` component, which represents the end of input. If any input is remaining, `None`
+/// is returned.
+pub(crate) const fn parse_end(input: &[u8], end: modifier::End) -> Option<ParsedItem<'_, ()>> {
+ let modifier::End {} = end;
+
+ if input.is_empty() {
+ Some(ParsedItem(input, ()))
+ } else {
+ None
+ }
+}
diff --git a/vendor/time/src/parsing/iso8601.rs b/vendor/time/src/parsing/iso8601.rs
index 1afee4e31..792c43280 100644
--- a/vendor/time/src/parsing/iso8601.rs
+++ b/vendor/time/src/parsing/iso8601.rs
@@ -125,16 +125,16 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
*parsed = parsed
.with_hour_24(hour)
.ok_or(InvalidComponent("hour"))?
- .with_minute((fractional_part * Second.per(Minute) as f64) as _)
+ .with_minute((fractional_part * Second::per(Minute) as f64) as _)
.ok_or(InvalidComponent("minute"))?
.with_second(
- (fractional_part * Second.per(Hour) as f64 % Minute.per(Hour) as f64)
+ (fractional_part * Second::per(Hour) as f64 % Minute::per(Hour) as f64)
as _,
)
.ok_or(InvalidComponent("second"))?
.with_subsecond(
- (fractional_part * Nanosecond.per(Hour) as f64
- % Nanosecond.per(Second) as f64) as _,
+ (fractional_part * Nanosecond::per(Hour) as f64
+ % Nanosecond::per(Second) as f64) as _,
)
.ok_or(InvalidComponent("subsecond"))?;
return Ok(input);
@@ -162,11 +162,11 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
*parsed = parsed
.with_minute(minute)
.ok_or(InvalidComponent("minute"))?
- .with_second((fractional_part * Second.per(Minute) as f64) as _)
+ .with_second((fractional_part * Second::per(Minute) as f64) as _)
.ok_or(InvalidComponent("second"))?
.with_subsecond(
- (fractional_part * Nanosecond.per(Minute) as f64
- % Nanosecond.per(Second) as f64) as _,
+ (fractional_part * Nanosecond::per(Minute) as f64
+ % Nanosecond::per(Second) as f64) as _,
)
.ok_or(InvalidComponent("subsecond"))?;
return Ok(input);
@@ -209,7 +209,7 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
Some(ParsedItem(input, (second, Some(fractional_part)))) => (
input,
second,
- round(fractional_part * Nanosecond.per(Second) as f64) as _,
+ round(fractional_part * Nanosecond::per(Second) as f64) as _,
),
None if extended_kind.is_extended() => {
return Err(error::Parse::ParseFromDescription(InvalidComponent(
@@ -271,17 +271,23 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
};
}
- let input = min(input)
- .and_then(|parsed_item| {
- parsed_item.consume_value(|min| {
- parsed.set_offset_minute_signed(if sign == b'-' {
+ match min(input) {
+ Some(ParsedItem(new_input, min)) => {
+ input = new_input;
+ parsed
+ .set_offset_minute_signed(if sign == b'-' {
-(min as i8)
} else {
min as _
})
- })
- })
- .ok_or(InvalidComponent("offset minute"))?;
+ .ok_or(InvalidComponent("offset minute"))?;
+ }
+ None => {
+ // Omitted offset minute is assumed to be zero.
+ parsed.set_offset_minute_signed(0);
+ }
+ }
+
// If `:` was present, the format has already been set to extended. As such, this call
// will do nothing in that case. If there wasn't `:` but minutes were
// present, we know it's the basic format. Do not use `?` on the call, as
diff --git a/vendor/time/src/parsing/parsable.rs b/vendor/time/src/parsing/parsable.rs
index 78bbe64f0..30fda4db2 100644
--- a/vendor/time/src/parsing/parsable.rs
+++ b/vendor/time/src/parsing/parsable.rs
@@ -9,6 +9,7 @@ use crate::format_description::well_known::{Iso8601, Rfc2822, Rfc3339};
use crate::format_description::FormatItem;
#[cfg(feature = "alloc")]
use crate::format_description::OwnedFormatItem;
+use crate::internal_macros::bug;
use crate::parsing::{Parsed, ParsedItem};
use crate::{error, Date, DateTime, Month, Time, UtcOffset, Weekday};
@@ -52,7 +53,9 @@ mod sealed {
if self.parse_into(input, &mut parsed)?.is_empty() {
Ok(parsed)
} else {
- Err(error::Parse::UnexpectedTrailingCharacters)
+ Err(error::Parse::ParseFromDescription(
+ error::ParseFromDescription::UnexpectedTrailingCharacters,
+ ))
}
}
@@ -237,7 +240,7 @@ impl sealed::Sealed for Rfc2822 {
};
// The RFC explicitly allows leap seconds.
- parsed.set_flag(Parsed::LEAP_SECOND_ALLOWED_FLAG, true);
+ parsed.leap_second_allowed = true;
#[allow(clippy::unnecessary_lazy_evaluations)] // rust-lang/rust-clippy#8522
let zone_literal = first_match(
@@ -430,7 +433,9 @@ impl sealed::Sealed for Rfc2822 {
};
if !input.is_empty() {
- return Err(error::Parse::UnexpectedTrailingCharacters);
+ return Err(error::Parse::ParseFromDescription(
+ error::ParseFromDescription::UnexpectedTrailingCharacters,
+ ));
}
let mut nanosecond = 0;
@@ -533,7 +538,7 @@ impl sealed::Sealed for Rfc3339 {
};
// The RFC explicitly allows leap seconds.
- parsed.set_flag(Parsed::LEAP_SECOND_ALLOWED_FLAG, true);
+ parsed.leap_second_allowed = true;
if let Some(ParsedItem(input, ())) = ascii_char_ignore_case::<b'Z'>(input) {
parsed
@@ -662,7 +667,9 @@ impl sealed::Sealed for Rfc3339 {
};
if !input.is_empty() {
- return Err(error::Parse::UnexpectedTrailingCharacters);
+ return Err(error::Parse::ParseFromDescription(
+ error::ParseFromDescription::UnexpectedTrailingCharacters,
+ ));
}
// The RFC explicitly permits leap seconds. We don't currently support them, so treat it as
diff --git a/vendor/time/src/parsing/parsed.rs b/vendor/time/src/parsing/parsed.rs
index 04c74a720..f31087fe2 100644
--- a/vendor/time/src/parsing/parsed.rs
+++ b/vendor/time/src/parsing/parsed.rs
@@ -1,16 +1,22 @@
//! Information parsed from an input and format description.
-use core::mem::MaybeUninit;
use core::num::{NonZeroU16, NonZeroU8};
+use deranged::{
+ OptionRangedI128, OptionRangedI32, OptionRangedI8, OptionRangedU16, OptionRangedU32,
+ OptionRangedU8, RangedI128, RangedI32, RangedI8, RangedU16, RangedU32, RangedU8,
+};
+
+use crate::convert::{Day, Hour, Minute, Nanosecond, Second};
+use crate::date::{MAX_YEAR, MIN_YEAR};
use crate::date_time::{maybe_offset_from_offset, offset_kind, DateTime, MaybeOffset};
use crate::error::TryFromParsed::InsufficientInformation;
-use crate::format_description::modifier::{WeekNumberRepr, YearRepr};
#[cfg(feature = "alloc")]
use crate::format_description::OwnedFormatItem;
-use crate::format_description::{Component, FormatItem};
+use crate::format_description::{modifier, Component, FormatItem};
+use crate::internal_macros::const_try_opt;
use crate::parsing::component::{
- parse_day, parse_hour, parse_ignore, parse_minute, parse_month, parse_offset_hour,
+ parse_day, parse_end, parse_hour, parse_ignore, parse_minute, parse_month, parse_offset_hour,
parse_offset_minute, parse_offset_second, parse_ordinal, parse_period, parse_second,
parse_subsecond, parse_unix_timestamp, parse_week_number, parse_weekday, parse_year, Period,
};
@@ -99,10 +105,6 @@ impl sealed::AnyFormatItem for OwnedFormatItem {
}
}
-/// The type of the `flags` field in [`Parsed`]. Allows for changing a single location and having it
-/// effect all uses.
-type Flag = u32;
-
/// All information parsed.
///
/// This information is directly used to construct the final values.
@@ -111,106 +113,97 @@ type Flag = u32;
/// control over values, in the instance that the default parser is insufficient.
#[derive(Debug, Clone, Copy)]
pub struct Parsed {
- /// Bitflags indicating whether a particular field is present.
- flags: Flag,
/// Calendar year.
- year: MaybeUninit<i32>,
+ year: OptionRangedI32<{ MIN_YEAR }, { MAX_YEAR }>,
/// The last two digits of the calendar year.
- year_last_two: MaybeUninit<u8>,
+ year_last_two: OptionRangedU8<0, 99>,
/// Year of the [ISO week date](https://en.wikipedia.org/wiki/ISO_week_date).
- iso_year: MaybeUninit<i32>,
+ iso_year: OptionRangedI32<{ MIN_YEAR }, { MAX_YEAR }>,
/// The last two digits of the ISO week year.
- iso_year_last_two: MaybeUninit<u8>,
+ iso_year_last_two: OptionRangedU8<0, 99>,
/// Month of the year.
month: Option<Month>,
/// Week of the year, where week one begins on the first Sunday of the calendar year.
- sunday_week_number: MaybeUninit<u8>,
+ sunday_week_number: OptionRangedU8<0, 53>,
/// Week of the year, where week one begins on the first Monday of the calendar year.
- monday_week_number: MaybeUninit<u8>,
+ monday_week_number: OptionRangedU8<0, 53>,
/// Week of the year, where week one is the Monday-to-Sunday period containing January 4.
- iso_week_number: Option<NonZeroU8>,
+ iso_week_number: OptionRangedU8<1, 53>,
/// Day of the week.
weekday: Option<Weekday>,
/// Day of the year.
- ordinal: Option<NonZeroU16>,
+ ordinal: OptionRangedU16<1, 366>,
/// Day of the month.
- day: Option<NonZeroU8>,
+ day: OptionRangedU8<1, 31>,
/// Hour within the day.
- hour_24: MaybeUninit<u8>,
+ hour_24: OptionRangedU8<0, { Hour::per(Day) - 1 }>,
/// Hour within the 12-hour period (midnight to noon or vice versa). This is typically used in
/// conjunction with AM/PM, which is indicated by the `hour_12_is_pm` field.
- hour_12: Option<NonZeroU8>,
+ hour_12: OptionRangedU8<1, 12>,
/// Whether the `hour_12` field indicates a time that "PM".
hour_12_is_pm: Option<bool>,
/// Minute within the hour.
- minute: MaybeUninit<u8>,
+ // minute: MaybeUninit<u8>,
+ minute: OptionRangedU8<0, { Minute::per(Hour) - 1 }>,
/// Second within the minute.
- second: MaybeUninit<u8>,
+ // do not subtract one, as leap seconds may be allowed
+ second: OptionRangedU8<0, { Second::per(Minute) }>,
/// Nanosecond within the second.
- subsecond: MaybeUninit<u32>,
+ subsecond: OptionRangedU32<0, { Nanosecond::per(Second) - 1 }>,
/// Whole hours of the UTC offset.
- offset_hour: MaybeUninit<i8>,
+ offset_hour: OptionRangedI8<-23, 23>,
/// Minutes within the hour of the UTC offset.
- offset_minute: MaybeUninit<i8>,
+ offset_minute:
+ OptionRangedI8<{ -((Minute::per(Hour) - 1) as i8) }, { (Minute::per(Hour) - 1) as _ }>,
/// Seconds within the minute of the UTC offset.
- offset_second: MaybeUninit<i8>,
+ offset_second:
+ OptionRangedI8<{ -((Second::per(Minute) - 1) as i8) }, { (Second::per(Minute) - 1) as _ }>,
/// The Unix timestamp in nanoseconds.
- unix_timestamp_nanos: MaybeUninit<i128>,
-}
-
-#[allow(clippy::missing_docs_in_private_items)]
-impl Parsed {
- const YEAR_FLAG: Flag = 1 << 0;
- const YEAR_LAST_TWO_FLAG: Flag = 1 << 1;
- const ISO_YEAR_FLAG: Flag = 1 << 2;
- const ISO_YEAR_LAST_TWO_FLAG: Flag = 1 << 3;
- const SUNDAY_WEEK_NUMBER_FLAG: Flag = 1 << 4;
- const MONDAY_WEEK_NUMBER_FLAG: Flag = 1 << 5;
- const HOUR_24_FLAG: Flag = 1 << 6;
- const MINUTE_FLAG: Flag = 1 << 7;
- const SECOND_FLAG: Flag = 1 << 8;
- const SUBSECOND_FLAG: Flag = 1 << 9;
- const OFFSET_HOUR_FLAG: Flag = 1 << 10;
- const OFFSET_MINUTE_FLAG: Flag = 1 << 11;
- const OFFSET_SECOND_FLAG: Flag = 1 << 12;
+ // unix_timestamp_nanos: MaybeUninit<i128>,
+ unix_timestamp_nanos: OptionRangedI128<
+ { Date::MIN.midnight().assume_utc().unix_timestamp_nanos() },
+ {
+ Date::MAX
+ .with_time(Time::MAX)
+ .assume_utc()
+ .unix_timestamp_nanos()
+ },
+ >,
+ /// Indicates whether the [`UtcOffset`] is negative. This information is obtained when parsing
+ /// the offset hour, but may not otherwise be stored due to "-0" being equivalent to "0".
+ offset_is_negative: Option<bool>,
/// Indicates whether a leap second is permitted to be parsed. This is required by some
/// well-known formats.
- pub(super) const LEAP_SECOND_ALLOWED_FLAG: Flag = 1 << 13;
- /// Indicates whether the `UtcOffset` is negative. This information is obtained when parsing the
- /// offset hour, but may not otherwise be stored due to "-0" being equivalent to "0".
- const OFFSET_IS_NEGATIVE_FLAG: Flag = 1 << 14;
- /// Does the value at `OFFSET_IS_NEGATIVE_FLAG` have any semantic meaning, or is it just the
- /// default value? If the latter, the value should be considered to have no meaning.
- const OFFSET_IS_NEGATIVE_FLAG_IS_INITIALIZED: Flag = 1 << 15;
- const UNIX_TIMESTAMP_NANOS_FLAG: Flag = 1 << 16;
+ pub(super) leap_second_allowed: bool,
}
impl Parsed {
/// Create a new instance of `Parsed` with no information known.
pub const fn new() -> Self {
Self {
- flags: 0,
- year: MaybeUninit::uninit(),
- year_last_two: MaybeUninit::uninit(),
- iso_year: MaybeUninit::uninit(),
- iso_year_last_two: MaybeUninit::uninit(),
+ year: OptionRangedI32::None,
+ year_last_two: OptionRangedU8::None,
+ iso_year: OptionRangedI32::None,
+ iso_year_last_two: OptionRangedU8::None,
month: None,
- sunday_week_number: MaybeUninit::uninit(),
- monday_week_number: MaybeUninit::uninit(),
- iso_week_number: None,
+ sunday_week_number: OptionRangedU8::None,
+ monday_week_number: OptionRangedU8::None,
+ iso_week_number: OptionRangedU8::None,
weekday: None,
- ordinal: None,
- day: None,
- hour_24: MaybeUninit::uninit(),
- hour_12: None,
+ ordinal: OptionRangedU16::None,
+ day: OptionRangedU8::None,
+ hour_24: OptionRangedU8::None,
+ hour_12: OptionRangedU8::None,
hour_12_is_pm: None,
- minute: MaybeUninit::uninit(),
- second: MaybeUninit::uninit(),
- subsecond: MaybeUninit::uninit(),
- offset_hour: MaybeUninit::uninit(),
- offset_minute: MaybeUninit::uninit(),
- offset_second: MaybeUninit::uninit(),
- unix_timestamp_nanos: MaybeUninit::uninit(),
+ minute: OptionRangedU8::None,
+ second: OptionRangedU8::None,
+ subsecond: OptionRangedU32::None,
+ offset_hour: OptionRangedI8::None,
+ offset_minute: OptionRangedI8::None,
+ offset_second: OptionRangedI8::None,
+ unix_timestamp_nanos: OptionRangedI128::None,
+ offset_is_negative: None,
+ leap_second_allowed: false,
}
}
@@ -283,11 +276,11 @@ impl Parsed {
let ParsedItem(remaining, value) =
parse_week_number(input, modifiers).ok_or(InvalidComponent("week number"))?;
match modifiers.repr {
- WeekNumberRepr::Iso => {
+ modifier::WeekNumberRepr::Iso => {
NonZeroU8::new(value).and_then(|value| self.set_iso_week_number(value))
}
- WeekNumberRepr::Sunday => self.set_sunday_week_number(value),
- WeekNumberRepr::Monday => self.set_monday_week_number(value),
+ modifier::WeekNumberRepr::Sunday => self.set_sunday_week_number(value),
+ modifier::WeekNumberRepr::Monday => self.set_monday_week_number(value),
}
.ok_or(InvalidComponent("week number"))?;
Ok(remaining)
@@ -296,10 +289,10 @@ impl Parsed {
let ParsedItem(remaining, value) =
parse_year(input, modifiers).ok_or(InvalidComponent("year"))?;
match (modifiers.iso_week_based, modifiers.repr) {
- (false, YearRepr::Full) => self.set_year(value),
- (false, YearRepr::LastTwo) => self.set_year_last_two(value as _),
- (true, YearRepr::Full) => self.set_iso_year(value),
- (true, YearRepr::LastTwo) => self.set_iso_year_last_two(value as _),
+ (false, modifier::YearRepr::Full) => self.set_year(value),
+ (false, modifier::YearRepr::LastTwo) => self.set_year_last_two(value as _),
+ (true, modifier::YearRepr::Full) => self.set_iso_year(value),
+ (true, modifier::YearRepr::LastTwo) => self.set_iso_year_last_two(value as _),
}
.ok_or(InvalidComponent("year"))?;
Ok(remaining)
@@ -332,9 +325,9 @@ impl Parsed {
Component::OffsetHour(modifiers) => parse_offset_hour(input, modifiers)
.and_then(|parsed| {
parsed.consume_value(|(value, is_negative)| {
- self.set_flag(Self::OFFSET_IS_NEGATIVE_FLAG_IS_INITIALIZED, true);
- self.set_flag(Self::OFFSET_IS_NEGATIVE_FLAG, is_negative);
- self.set_offset_hour(value)
+ self.set_offset_hour(value)?;
+ self.offset_is_negative = Some(is_negative);
+ Some(())
})
})
.ok_or(InvalidComponent("offset hour")),
@@ -356,145 +349,152 @@ impl Parsed {
parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
})
.ok_or(InvalidComponent("unix_timestamp")),
+ Component::End(modifiers) => parse_end(input, modifiers)
+ .map(ParsedItem::<()>::into_inner)
+ .ok_or(error::ParseFromDescription::UnexpectedTrailingCharacters),
}
}
+}
- /// Get the value of the provided flag.
- const fn get_flag(&self, flag: Flag) -> bool {
- self.flags & flag == flag
+/// Getter methods
+impl Parsed {
+ /// Obtain the `year` component.
+ pub const fn year(&self) -> Option<i32> {
+ self.year.get_primitive()
}
- /// Set the value of the provided flag.
- pub(super) fn set_flag(&mut self, flag: Flag, value: bool) {
- if value {
- self.flags |= flag;
- } else {
- self.flags &= !flag;
- }
+ /// Obtain the `year_last_two` component.
+ pub const fn year_last_two(&self) -> Option<u8> {
+ self.year_last_two.get_primitive()
}
-}
-/// Generate getters for each of the fields.
-macro_rules! getters {
- ($($(@$flag:ident)? $name:ident: $ty:ty),+ $(,)?) => {$(
- getters!(! $(@$flag)? $name: $ty);
- )*};
- (! $name:ident : $ty:ty) => {
- /// Obtain the named component.
- pub const fn $name(&self) -> Option<$ty> {
- self.$name
- }
- };
- (! @$flag:ident $name:ident : $ty:ty) => {
- /// Obtain the named component.
- pub const fn $name(&self) -> Option<$ty> {
- if !self.get_flag(Self::$flag) {
- None
- } else {
- // SAFETY: We just checked if the field is present.
- Some(unsafe { self.$name.assume_init() })
- }
- }
- };
-}
+ /// Obtain the `iso_year` component.
+ pub const fn iso_year(&self) -> Option<i32> {
+ self.iso_year.get_primitive()
+ }
-/// Getter methods
-impl Parsed {
- getters! {
- @YEAR_FLAG year: i32,
- @YEAR_LAST_TWO_FLAG year_last_two: u8,
- @ISO_YEAR_FLAG iso_year: i32,
- @ISO_YEAR_LAST_TWO_FLAG iso_year_last_two: u8,
- month: Month,
- @SUNDAY_WEEK_NUMBER_FLAG sunday_week_number: u8,
- @MONDAY_WEEK_NUMBER_FLAG monday_week_number: u8,
- iso_week_number: NonZeroU8,
- weekday: Weekday,
- ordinal: NonZeroU16,
- day: NonZeroU8,
- @HOUR_24_FLAG hour_24: u8,
- hour_12: NonZeroU8,
- hour_12_is_pm: bool,
- @MINUTE_FLAG minute: u8,
- @SECOND_FLAG second: u8,
- @SUBSECOND_FLAG subsecond: u32,
- @OFFSET_HOUR_FLAG offset_hour: i8,
- @UNIX_TIMESTAMP_NANOS_FLAG unix_timestamp_nanos: i128,
- }
-
- /// Obtain the absolute value of the offset minute.
+ /// Obtain the `iso_year_last_two` component.
+ pub const fn iso_year_last_two(&self) -> Option<u8> {
+ self.iso_year_last_two.get_primitive()
+ }
+
+ /// Obtain the `month` component.
+ pub const fn month(&self) -> Option<Month> {
+ self.month
+ }
+
+ /// Obtain the `sunday_week_number` component.
+ pub const fn sunday_week_number(&self) -> Option<u8> {
+ self.sunday_week_number.get_primitive()
+ }
+
+ /// Obtain the `monday_week_number` component.
+ pub const fn monday_week_number(&self) -> Option<u8> {
+ self.monday_week_number.get_primitive()
+ }
+
+ /// Obtain the `iso_week_number` component.
+ pub const fn iso_week_number(&self) -> Option<NonZeroU8> {
+ NonZeroU8::new(const_try_opt!(self.iso_week_number.get_primitive()))
+ }
+
+ /// Obtain the `weekday` component.
+ pub const fn weekday(&self) -> Option<Weekday> {
+ self.weekday
+ }
+
+ /// Obtain the `ordinal` component.
+ pub const fn ordinal(&self) -> Option<NonZeroU16> {
+ NonZeroU16::new(const_try_opt!(self.ordinal.get_primitive()))
+ }
+
+ /// Obtain the `day` component.
+ pub const fn day(&self) -> Option<NonZeroU8> {
+ NonZeroU8::new(const_try_opt!(self.day.get_primitive()))
+ }
+
+ /// Obtain the `hour_24` component.
+ pub const fn hour_24(&self) -> Option<u8> {
+ self.hour_24.get_primitive()
+ }
+
+ /// Obtain the `hour_12` component.
+ pub const fn hour_12(&self) -> Option<NonZeroU8> {
+ NonZeroU8::new(const_try_opt!(self.hour_12.get_primitive()))
+ }
+
+ /// Obtain the `hour_12_is_pm` component.
+ pub const fn hour_12_is_pm(&self) -> Option<bool> {
+ self.hour_12_is_pm
+ }
+
+ /// Obtain the `minute` component.
+ pub const fn minute(&self) -> Option<u8> {
+ self.minute.get_primitive()
+ }
+
+ /// Obtain the `second` component.
+ pub const fn second(&self) -> Option<u8> {
+ self.second.get_primitive()
+ }
+
+ /// Obtain the `subsecond` component.
+ pub const fn subsecond(&self) -> Option<u32> {
+ self.subsecond.get_primitive()
+ }
+
+ /// Obtain the `offset_hour` component.
+ pub const fn offset_hour(&self) -> Option<i8> {
+ self.offset_hour.get_primitive()
+ }
+
+ /// Obtain the absolute value of the `offset_minute` component.
#[doc(hidden)]
#[deprecated(since = "0.3.8", note = "use `parsed.offset_minute_signed()` instead")]
pub const fn offset_minute(&self) -> Option<u8> {
Some(const_try_opt!(self.offset_minute_signed()).unsigned_abs())
}
- /// Obtain the offset minute as an `i8`.
+ /// Obtain the `offset_minute` component.
pub const fn offset_minute_signed(&self) -> Option<i8> {
- if !self.get_flag(Self::OFFSET_MINUTE_FLAG) {
- None
- } else {
- // SAFETY: We just checked if the field is present.
- let value = unsafe { self.offset_minute.assume_init() };
-
- if self.get_flag(Self::OFFSET_IS_NEGATIVE_FLAG_IS_INITIALIZED)
- && (value.is_negative() != self.get_flag(Self::OFFSET_IS_NEGATIVE_FLAG))
- {
- Some(-value)
- } else {
- Some(value)
- }
+ match (self.offset_minute.get_primitive(), self.offset_is_negative) {
+ (Some(offset_minute), Some(true)) => Some(-offset_minute),
+ (Some(offset_minute), _) => Some(offset_minute),
+ (None, _) => None,
}
}
- /// Obtain the absolute value of the offset second.
+ /// Obtain the absolute value of the `offset_second` component.
#[doc(hidden)]
#[deprecated(since = "0.3.8", note = "use `parsed.offset_second_signed()` instead")]
pub const fn offset_second(&self) -> Option<u8> {
Some(const_try_opt!(self.offset_second_signed()).unsigned_abs())
}
- /// Obtain the offset second as an `i8`.
+ /// Obtain the `offset_second` component.
pub const fn offset_second_signed(&self) -> Option<i8> {
- if !self.get_flag(Self::OFFSET_SECOND_FLAG) {
- None
- } else {
- // SAFETY: We just checked if the field is present.
- let value = unsafe { self.offset_second.assume_init() };
-
- if self.get_flag(Self::OFFSET_IS_NEGATIVE_FLAG_IS_INITIALIZED)
- && (value.is_negative() != self.get_flag(Self::OFFSET_IS_NEGATIVE_FLAG))
- {
- Some(-value)
- } else {
- Some(value)
- }
+ match (self.offset_second.get_primitive(), self.offset_is_negative) {
+ (Some(offset_second), Some(true)) => Some(-offset_second),
+ (Some(offset_second), _) => Some(offset_second),
+ (None, _) => None,
}
}
+
+ /// Obtain the `unix_timestamp_nanos` component.
+ pub const fn unix_timestamp_nanos(&self) -> Option<i128> {
+ self.unix_timestamp_nanos.get_primitive()
+ }
}
-/// Generate setters for each of the fields.
-///
-/// This macro should only be used for fields where the value is not validated beyond its type.
+/// Generate setters based on the builders.
macro_rules! setters {
- ($($(@$flag:ident)? $setter_name:ident $name:ident: $ty:ty),+ $(,)?) => {$(
- setters!(! $(@$flag)? $setter_name $name: $ty);
- )*};
- (! $setter_name:ident $name:ident : $ty:ty) => {
- /// Set the named component.
- pub fn $setter_name(&mut self, value: $ty) -> Option<()> {
- self.$name = Some(value);
- Some(())
- }
- };
- (! @$flag:ident $setter_name:ident $name:ident : $ty:ty) => {
- /// Set the named component.
- pub fn $setter_name(&mut self, value: $ty) -> Option<()> {
- self.$name = MaybeUninit::new(value);
- self.set_flag(Self::$flag, true);
+ ($($name:ident $setter:ident $builder:ident $type:ty;)*) => {$(
+ #[doc = concat!("Set the `", stringify!($setter), "` component.")]
+ pub fn $setter(&mut self, value: $type) -> Option<()> {
+ *self = self.$builder(value)?;
Some(())
}
- };
+ )*};
}
/// Setter methods
@@ -503,28 +503,30 @@ macro_rules! setters {
/// setters _may_ fail if the value is invalid, though behavior is not guaranteed.
impl Parsed {
setters! {
- @YEAR_FLAG set_year year: i32,
- @YEAR_LAST_TWO_FLAG set_year_last_two year_last_two: u8,
- @ISO_YEAR_FLAG set_iso_year iso_year: i32,
- @ISO_YEAR_LAST_TWO_FLAG set_iso_year_last_two iso_year_last_two: u8,
- set_month month: Month,
- @SUNDAY_WEEK_NUMBER_FLAG set_sunday_week_number sunday_week_number: u8,
- @MONDAY_WEEK_NUMBER_FLAG set_monday_week_number monday_week_number: u8,
- set_iso_week_number iso_week_number: NonZeroU8,
- set_weekday weekday: Weekday,
- set_ordinal ordinal: NonZeroU16,
- set_day day: NonZeroU8,
- @HOUR_24_FLAG set_hour_24 hour_24: u8,
- set_hour_12 hour_12: NonZeroU8,
- set_hour_12_is_pm hour_12_is_pm: bool,
- @MINUTE_FLAG set_minute minute: u8,
- @SECOND_FLAG set_second second: u8,
- @SUBSECOND_FLAG set_subsecond subsecond: u32,
- @OFFSET_HOUR_FLAG set_offset_hour offset_hour: i8,
- @UNIX_TIMESTAMP_NANOS_FLAG set_unix_timestamp_nanos unix_timestamp_nanos: i128,
- }
-
- /// Set the named component.
+ year set_year with_year i32;
+ year_last_two set_year_last_two with_year_last_two u8;
+ iso_year set_iso_year with_iso_year i32;
+ iso_year_last_two set_iso_year_last_two with_iso_year_last_two u8;
+ month set_month with_month Month;
+ sunday_week_number set_sunday_week_number with_sunday_week_number u8;
+ monday_week_number set_monday_week_number with_monday_week_number u8;
+ iso_week_number set_iso_week_number with_iso_week_number NonZeroU8;
+ weekday set_weekday with_weekday Weekday;
+ ordinal set_ordinal with_ordinal NonZeroU16;
+ day set_day with_day NonZeroU8;
+ hour_24 set_hour_24 with_hour_24 u8;
+ hour_12 set_hour_12 with_hour_12 NonZeroU8;
+ hour_12_is_pm set_hour_12_is_pm with_hour_12_is_pm bool;
+ minute set_minute with_minute u8;
+ second set_second with_second u8;
+ subsecond set_subsecond with_subsecond u32;
+ offset_hour set_offset_hour with_offset_hour i8;
+ offset_minute set_offset_minute_signed with_offset_minute_signed i8;
+ offset_second set_offset_second_signed with_offset_second_signed i8;
+ unix_timestamp_nanos set_unix_timestamp_nanos with_unix_timestamp_nanos i128;
+ }
+
+ /// Set the `offset_minute` component.
#[doc(hidden)]
#[deprecated(
since = "0.3.8",
@@ -539,13 +541,6 @@ impl Parsed {
}
/// Set the `offset_minute` component.
- pub fn set_offset_minute_signed(&mut self, value: i8) -> Option<()> {
- self.offset_minute = MaybeUninit::new(value);
- self.set_flag(Self::OFFSET_MINUTE_FLAG, true);
- Some(())
- }
-
- /// Set the named component.
#[doc(hidden)]
#[deprecated(
since = "0.3.8",
@@ -558,37 +553,6 @@ impl Parsed {
self.set_offset_second_signed(value as _)
}
}
-
- /// Set the `offset_second` component.
- pub fn set_offset_second_signed(&mut self, value: i8) -> Option<()> {
- self.offset_second = MaybeUninit::new(value);
- self.set_flag(Self::OFFSET_SECOND_FLAG, true);
- Some(())
- }
-}
-
-/// Generate build methods for each of the fields.
-///
-/// This macro should only be used for fields where the value is not validated beyond its type.
-macro_rules! builders {
- ($($(@$flag:ident)? $builder_name:ident $name:ident: $ty:ty),+ $(,)?) => {$(
- builders!(! $(@$flag)? $builder_name $name: $ty);
- )*};
- (! $builder_name:ident $name:ident : $ty:ty) => {
- /// Set the named component and return `self`.
- pub const fn $builder_name(mut self, value: $ty) -> Option<Self> {
- self.$name = Some(value);
- Some(self)
- }
- };
- (! @$flag:ident $builder_name:ident $name:ident : $ty:ty) => {
- /// Set the named component and return `self`.
- pub const fn $builder_name(mut self, value: $ty) -> Option<Self> {
- self.$name = MaybeUninit::new(value);
- self.flags |= Self::$flag;
- Some(self)
- }
- };
}
/// Builder methods
@@ -596,29 +560,115 @@ macro_rules! builders {
/// All builder methods return `Option<Self>`, which is `Some` if the value was set, and `None` if
/// not. The builder methods _may_ fail if the value is invalid, though behavior is not guaranteed.
impl Parsed {
- builders! {
- @YEAR_FLAG with_year year: i32,
- @YEAR_LAST_TWO_FLAG with_year_last_two year_last_two: u8,
- @ISO_YEAR_FLAG with_iso_year iso_year: i32,
- @ISO_YEAR_LAST_TWO_FLAG with_iso_year_last_two iso_year_last_two: u8,
- with_month month: Month,
- @SUNDAY_WEEK_NUMBER_FLAG with_sunday_week_number sunday_week_number: u8,
- @MONDAY_WEEK_NUMBER_FLAG with_monday_week_number monday_week_number: u8,
- with_iso_week_number iso_week_number: NonZeroU8,
- with_weekday weekday: Weekday,
- with_ordinal ordinal: NonZeroU16,
- with_day day: NonZeroU8,
- @HOUR_24_FLAG with_hour_24 hour_24: u8,
- with_hour_12 hour_12: NonZeroU8,
- with_hour_12_is_pm hour_12_is_pm: bool,
- @MINUTE_FLAG with_minute minute: u8,
- @SECOND_FLAG with_second second: u8,
- @SUBSECOND_FLAG with_subsecond subsecond: u32,
- @OFFSET_HOUR_FLAG with_offset_hour offset_hour: i8,
- @UNIX_TIMESTAMP_NANOS_FLAG with_unix_timestamp_nanos unix_timestamp_nanos: i128,
- }
-
- /// Set the named component and return `self`.
+ /// Set the `year` component and return `self`.
+ pub const fn with_year(mut self, value: i32) -> Option<Self> {
+ self.year = OptionRangedI32::Some(const_try_opt!(RangedI32::new(value)));
+ Some(self)
+ }
+
+ /// Set the `year_last_two` component and return `self`.
+ pub const fn with_year_last_two(mut self, value: u8) -> Option<Self> {
+ self.year_last_two = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `iso_year` component and return `self`.
+ pub const fn with_iso_year(mut self, value: i32) -> Option<Self> {
+ self.iso_year = OptionRangedI32::Some(const_try_opt!(RangedI32::new(value)));
+ Some(self)
+ }
+
+ /// Set the `iso_year_last_two` component and return `self`.
+ pub const fn with_iso_year_last_two(mut self, value: u8) -> Option<Self> {
+ self.iso_year_last_two = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `month` component and return `self`.
+ pub const fn with_month(mut self, value: Month) -> Option<Self> {
+ self.month = Some(value);
+ Some(self)
+ }
+
+ /// Set the `sunday_week_number` component and return `self`.
+ pub const fn with_sunday_week_number(mut self, value: u8) -> Option<Self> {
+ self.sunday_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `monday_week_number` component and return `self`.
+ pub const fn with_monday_week_number(mut self, value: u8) -> Option<Self> {
+ self.monday_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `iso_week_number` component and return `self`.
+ pub const fn with_iso_week_number(mut self, value: NonZeroU8) -> Option<Self> {
+ self.iso_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
+ Some(self)
+ }
+
+ /// Set the `weekday` component and return `self`.
+ pub const fn with_weekday(mut self, value: Weekday) -> Option<Self> {
+ self.weekday = Some(value);
+ Some(self)
+ }
+
+ /// Set the `ordinal` component and return `self`.
+ pub const fn with_ordinal(mut self, value: NonZeroU16) -> Option<Self> {
+ self.ordinal = OptionRangedU16::Some(const_try_opt!(RangedU16::new(value.get())));
+ Some(self)
+ }
+
+ /// Set the `day` component and return `self`.
+ pub const fn with_day(mut self, value: NonZeroU8) -> Option<Self> {
+ self.day = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
+ Some(self)
+ }
+
+ /// Set the `hour_24` component and return `self`.
+ pub const fn with_hour_24(mut self, value: u8) -> Option<Self> {
+ self.hour_24 = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `hour_12` component and return `self`.
+ pub const fn with_hour_12(mut self, value: NonZeroU8) -> Option<Self> {
+ self.hour_12 = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
+ Some(self)
+ }
+
+ /// Set the `hour_12_is_pm` component and return `self`.
+ pub const fn with_hour_12_is_pm(mut self, value: bool) -> Option<Self> {
+ self.hour_12_is_pm = Some(value);
+ Some(self)
+ }
+
+ /// Set the `minute` component and return `self`.
+ pub const fn with_minute(mut self, value: u8) -> Option<Self> {
+ self.minute = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `second` component and return `self`.
+ pub const fn with_second(mut self, value: u8) -> Option<Self> {
+ self.second = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `subsecond` component and return `self`.
+ pub const fn with_subsecond(mut self, value: u32) -> Option<Self> {
+ self.subsecond = OptionRangedU32::Some(const_try_opt!(RangedU32::new(value)));
+ Some(self)
+ }
+
+ /// Set the `offset_hour` component and return `self`.
+ pub const fn with_offset_hour(mut self, value: i8) -> Option<Self> {
+ self.offset_hour = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `offset_minute` component and return `self`.
#[doc(hidden)]
#[deprecated(
since = "0.3.8",
@@ -634,12 +684,11 @@ impl Parsed {
/// Set the `offset_minute` component and return `self`.
pub const fn with_offset_minute_signed(mut self, value: i8) -> Option<Self> {
- self.offset_minute = MaybeUninit::new(value);
- self.flags |= Self::OFFSET_MINUTE_FLAG;
+ self.offset_minute = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
Some(self)
}
- /// Set the named component and return `self`.
+ /// Set the `offset_minute` component and return `self`.
#[doc(hidden)]
#[deprecated(
since = "0.3.8",
@@ -655,8 +704,13 @@ impl Parsed {
/// Set the `offset_second` component and return `self`.
pub const fn with_offset_second_signed(mut self, value: i8) -> Option<Self> {
- self.offset_second = MaybeUninit::new(value);
- self.flags |= Self::OFFSET_SECOND_FLAG;
+ self.offset_second = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `unix_timestamp_nanos` component and return `self`.
+ pub const fn with_unix_timestamp_nanos(mut self, value: i128) -> Option<Self> {
+ self.unix_timestamp_nanos = OptionRangedI128::Some(const_try_opt!(RangedI128::new(value)));
Some(self)
}
}
@@ -682,7 +736,8 @@ impl TryFrom<Parsed> for Date {
/// Get the value needed to adjust the ordinal day for Sunday and Monday-based week
/// numbering.
const fn adjustment(year: i32) -> i16 {
- match Date::__from_ordinal_date_unchecked(year, 1).weekday() {
+ // Safety: `ordinal` is not zero.
+ match unsafe { Date::__from_ordinal_date_unchecked(year, 1) }.weekday() {
Weekday::Monday => 7,
Weekday::Tuesday => 1,
Weekday::Wednesday => 2,
@@ -733,6 +788,7 @@ impl TryFrom<Parsed> for Time {
(_, Some(hour), Some(true)) => hour.get() + 12,
_ => return Err(InsufficientInformation),
};
+
if parsed.hour_24().is_none()
&& parsed.hour_12().is_some()
&& parsed.hour_12_is_pm().is_some()
@@ -742,10 +798,17 @@ impl TryFrom<Parsed> for Time {
{
return Ok(Self::from_hms_nano(hour, 0, 0, 0)?);
}
- let minute = parsed.minute().ok_or(InsufficientInformation)?;
- let second = parsed.second().unwrap_or(0);
- let subsecond = parsed.subsecond().unwrap_or(0);
- Ok(Self::from_hms_nano(hour, minute, second, subsecond)?)
+
+ // Reject combinations such as hour-second with minute omitted.
+ match (parsed.minute(), parsed.second(), parsed.subsecond()) {
+ (None, None, None) => Ok(Self::from_hms_nano(hour, 0, 0, 0)?),
+ (Some(minute), None, None) => Ok(Self::from_hms_nano(hour, minute, 0, 0)?),
+ (Some(minute), Some(second), None) => Ok(Self::from_hms_nano(hour, minute, second, 0)?),
+ (Some(minute), Some(second), Some(subsecond)) => {
+ Ok(Self::from_hms_nano(hour, minute, second, subsecond)?)
+ }
+ _ => Err(InsufficientInformation),
+ }
}
}
@@ -796,27 +859,31 @@ impl<O: MaybeOffset> TryFrom<Parsed> for DateTime<O> {
if let Some(timestamp) = parsed.unix_timestamp_nanos() {
let DateTime { date, time, offset } =
DateTime::<offset_kind::Fixed>::from_unix_timestamp_nanos(timestamp)?;
- return Ok(Self {
+
+ let mut value = Self {
date,
time,
offset: maybe_offset_from_offset::<O>(offset),
- });
+ };
+ if let Some(subsecond) = parsed.subsecond() {
+ value = value.replace_nanosecond(subsecond)?;
+ }
+ return Ok(value);
}
}
// Some well-known formats explicitly allow leap seconds. We don't currently support them,
// so treat it as the nearest preceding moment that can be represented. Because leap seconds
// always fall at the end of a month UTC, reject any that are at other times.
- let leap_second_input =
- if parsed.get_flag(Parsed::LEAP_SECOND_ALLOWED_FLAG) && parsed.second() == Some(60) {
- parsed.set_second(59).expect("59 is a valid second");
- parsed
- .set_subsecond(999_999_999)
- .expect("999_999_999 is a valid subsecond");
- true
- } else {
- false
- };
+ let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) {
+ parsed.set_second(59).expect("59 is a valid second");
+ parsed
+ .set_subsecond(999_999_999)
+ .expect("999_999_999 is a valid subsecond");
+ true
+ } else {
+ false
+ };
let dt = Self {
date: Date::try_from(parsed)?,
diff --git a/vendor/time/src/primitive_date_time.rs b/vendor/time/src/primitive_date_time.rs
index 9850f96d4..b985867d1 100644
--- a/vendor/time/src/primitive_date_time.rs
+++ b/vendor/time/src/primitive_date_time.rs
@@ -9,6 +9,7 @@ use std::io;
use crate::date_time::offset_kind;
#[cfg(feature = "formatting")]
use crate::formatting::Formattable;
+use crate::internal_macros::{const_try, const_try_opt};
#[cfg(feature = "parsing")]
use crate::parsing::Parsable;
use crate::{error, Date, DateTime, Duration, Month, OffsetDateTime, Time, UtcOffset, Weekday};
diff --git a/vendor/time/src/quickcheck.rs b/vendor/time/src/quickcheck.rs
index 4a788b517..02cc62282 100644
--- a/vendor/time/src/quickcheck.rs
+++ b/vendor/time/src/quickcheck.rs
@@ -2,7 +2,7 @@
//!
//! This enables users to write tests such as this, and have test values provided automatically:
//!
-//! ```
+//! ```ignore
//! # #![allow(dead_code)]
//! use quickcheck::quickcheck;
//! use time::Date;
@@ -38,7 +38,6 @@ use alloc::boxed::Box;
use quickcheck::{empty_shrinker, single_shrinker, Arbitrary, Gen};
-use crate::convert::*;
use crate::date_time::{DateTime, MaybeOffset};
use crate::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
@@ -73,25 +72,22 @@ impl Arbitrary for Date {
impl Arbitrary for Duration {
fn arbitrary(g: &mut Gen) -> Self {
- Self::nanoseconds_i128(arbitrary_between!(
- i128;
- g,
- Self::MIN.whole_nanoseconds(),
- Self::MAX.whole_nanoseconds()
- ))
+ Self::new_ranged(<_>::arbitrary(g), <_>::arbitrary(g))
}
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
Box::new(
- (self.subsec_nanoseconds(), self.whole_seconds())
+ (self.subsec_nanoseconds_ranged(), self.whole_seconds())
.shrink()
.map(|(mut nanoseconds, seconds)| {
// Coerce the sign if necessary.
- if (seconds > 0 && nanoseconds < 0) || (seconds < 0 && nanoseconds > 0) {
- nanoseconds *= -1;
+ if (seconds > 0 && nanoseconds.get() < 0)
+ || (seconds < 0 && nanoseconds.get() > 0)
+ {
+ nanoseconds = nanoseconds.neg();
}
- Self::new_unchecked(seconds, nanoseconds)
+ Self::new_ranged_unchecked(seconds, nanoseconds)
}),
)
}
@@ -99,20 +95,20 @@ impl Arbitrary for Duration {
impl Arbitrary for Time {
fn arbitrary(g: &mut Gen) -> Self {
- Self::__from_hms_nanos_unchecked(
- arbitrary_between!(u8; g, 0, Hour.per(Day) - 1),
- arbitrary_between!(u8; g, 0, Minute.per(Hour) - 1),
- arbitrary_between!(u8; g, 0, Second.per(Minute) - 1),
- arbitrary_between!(u32; g, 0, Nanosecond.per(Second) - 1),
+ Self::from_hms_nanos_ranged(
+ <_>::arbitrary(g),
+ <_>::arbitrary(g),
+ <_>::arbitrary(g),
+ <_>::arbitrary(g),
)
}
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
Box::new(
- self.as_hms_nano()
+ self.as_hms_nano_ranged()
.shrink()
.map(|(hour, minute, second, nanosecond)| {
- Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond)
+ Self::from_hms_nanos_ranged(hour, minute, second, nanosecond)
}),
)
}
@@ -130,20 +126,14 @@ impl Arbitrary for PrimitiveDateTime {
impl Arbitrary for UtcOffset {
fn arbitrary(g: &mut Gen) -> Self {
- let seconds =
- arbitrary_between!(i32; g, -(Second.per(Day) as i32 - 1), Second.per(Day) as i32 - 1);
- Self::__from_hms_unchecked(
- (seconds / Second.per(Hour) as i32) as _,
- ((seconds % Second.per(Hour) as i32) / Minute.per(Hour) as i32) as _,
- (seconds % Second.per(Minute) as i32) as _,
- )
+ Self::from_hms_ranged(<_>::arbitrary(g), <_>::arbitrary(g), <_>::arbitrary(g))
}
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
Box::new(
- self.as_hms().shrink().map(|(hours, minutes, seconds)| {
- Self::__from_hms_unchecked(hours, minutes, seconds)
- }),
+ self.as_hms_ranged()
+ .shrink()
+ .map(|(hours, minutes, seconds)| Self::from_hms_ranged(hours, minutes, seconds)),
)
}
}
diff --git a/vendor/time/src/rand.rs b/vendor/time/src/rand.rs
index e5181f9bd..eac6fe66d 100644
--- a/vendor/time/src/rand.rs
+++ b/vendor/time/src/rand.rs
@@ -3,17 +3,11 @@
use rand::distributions::{Distribution, Standard};
use rand::Rng;
-use crate::convert::*;
use crate::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
impl Distribution<Time> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Time {
- Time::__from_hms_nanos_unchecked(
- rng.gen_range(0..Hour.per(Day)),
- rng.gen_range(0..Minute.per(Hour)),
- rng.gen_range(0..Second.per(Minute)),
- rng.gen_range(0..Nanosecond.per(Second)),
- )
+ Time::from_hms_nanos_ranged(rng.gen(), rng.gen(), rng.gen(), rng.gen())
}
}
@@ -27,12 +21,7 @@ impl Distribution<Date> for Standard {
impl Distribution<UtcOffset> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> UtcOffset {
- let seconds = rng.gen_range(-(Second.per(Day) as i32 - 1)..=(Second.per(Day) as i32 - 1));
- UtcOffset::__from_hms_unchecked(
- (seconds / Second.per(Hour) as i32) as _,
- ((seconds % Second.per(Hour) as i32) / Minute.per(Hour) as i32) as _,
- (seconds % Second.per(Minute) as i32) as _,
- )
+ UtcOffset::from_hms_ranged(rng.gen(), rng.gen(), rng.gen())
}
}
@@ -51,9 +40,7 @@ impl Distribution<OffsetDateTime> for Standard {
impl Distribution<Duration> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Duration {
- Duration::nanoseconds_i128(
- rng.gen_range(Duration::MIN.whole_nanoseconds()..=Duration::MAX.whole_nanoseconds()),
- )
+ Duration::new_ranged(rng.gen(), rng.gen())
}
}
diff --git a/vendor/time/src/serde/mod.rs b/vendor/time/src/serde/mod.rs
index 844d7bdef..f94cf0445 100644
--- a/vendor/time/src/serde/mod.rs
+++ b/vendor/time/src/serde/mod.rs
@@ -403,11 +403,19 @@ impl<'a> Deserialize<'a> for Time {
/// The format used when serializing and deserializing a human-readable `UtcOffset`.
#[cfg(feature = "parsing")]
const UTC_OFFSET_FORMAT: &[FormatItem<'_>] = &[
- FormatItem::Component(Component::OffsetHour(modifier::OffsetHour::default())),
- FormatItem::Literal(b":"),
- FormatItem::Component(Component::OffsetMinute(modifier::OffsetMinute::default())),
- FormatItem::Literal(b":"),
- FormatItem::Component(Component::OffsetSecond(modifier::OffsetSecond::default())),
+ FormatItem::Component(Component::OffsetHour({
+ let mut m = modifier::OffsetHour::default();
+ m.sign_is_mandatory = true;
+ m
+ })),
+ FormatItem::Optional(&FormatItem::Compound(&[
+ FormatItem::Literal(b":"),
+ FormatItem::Component(Component::OffsetMinute(modifier::OffsetMinute::default())),
+ FormatItem::Optional(&FormatItem::Compound(&[
+ FormatItem::Literal(b":"),
+ FormatItem::Component(Component::OffsetSecond(modifier::OffsetSecond::default())),
+ ])),
+ ])),
];
impl Serialize for UtcOffset {
diff --git a/vendor/time/src/serde/visitor.rs b/vendor/time/src/serde/visitor.rs
index e61989afd..3a4311ecb 100644
--- a/vendor/time/src/serde/visitor.rs
+++ b/vendor/time/src/serde/visitor.rs
@@ -167,14 +167,21 @@ impl<'a> de::Visitor<'a> for Visitor<UtcOffset> {
fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<UtcOffset, A::Error> {
let hours = item!(seq, "offset hours")?;
- let minutes = item!(seq, "offset minutes")?;
- let seconds = item!(seq, "offset seconds")?;
+ let mut minutes = 0;
+ let mut seconds = 0;
+
+ if let Ok(Some(min)) = seq.next_element() {
+ minutes = min;
+ if let Ok(Some(sec)) = seq.next_element() {
+ seconds = sec;
+ }
+ };
UtcOffset::from_hms(hours, minutes, seconds).map_err(ComponentRange::into_de_error)
}
}
-impl<'a> de::Visitor<'a> for Visitor<Weekday> {
+impl de::Visitor<'_> for Visitor<Weekday> {
type Value = Weekday;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -211,7 +218,7 @@ impl<'a> de::Visitor<'a> for Visitor<Weekday> {
}
}
-impl<'a> de::Visitor<'a> for Visitor<Month> {
+impl de::Visitor<'_> for Visitor<Month> {
type Value = Month;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -262,7 +269,7 @@ impl<'a> de::Visitor<'a> for Visitor<Month> {
macro_rules! well_known {
($article:literal, $name:literal, $($ty:tt)+) => {
#[cfg(feature = "parsing")]
- impl<'a> de::Visitor<'a> for Visitor<$($ty)+> {
+ impl de::Visitor<'_> for Visitor<$($ty)+> {
type Value = OffsetDateTime;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/vendor/time/src/sys/local_offset_at/unix.rs b/vendor/time/src/sys/local_offset_at/unix.rs
index f4a808932..eddd8e2a9 100644
--- a/vendor/time/src/sys/local_offset_at/unix.rs
+++ b/vendor/time/src/sys/local_offset_at/unix.rs
@@ -15,9 +15,6 @@ const OS_HAS_THREAD_SAFE_ENVIRONMENT: bool = match std::env::consts::OS.as_bytes
// https://github.com/NetBSD/src/blob/f45028636a44111bc4af44d460924958a4460844/lib/libc/stdlib/getenv.c
// https://github.com/NetBSD/src/blob/f45028636a44111bc4af44d460924958a4460844/lib/libc/stdlib/setenv.c
| b"netbsd"
- // https://github.com/apple-oss-distributions/Libc/blob/d526593760f0f79dfaeb8b96c3c8a42c791156ff/stdlib/FreeBSD/getenv.c
- // https://github.com/apple-oss-distributions/Libc/blob/d526593760f0f79dfaeb8b96c3c8a42c791156ff/stdlib/FreeBSD/setenv.c
- | b"macos"
=> true,
_ => false,
};
diff --git a/vendor/time/src/sys/local_offset_at/wasm_js.rs b/vendor/time/src/sys/local_offset_at/wasm_js.rs
index dfbe063a2..a0b59ac86 100644
--- a/vendor/time/src/sys/local_offset_at/wasm_js.rs
+++ b/vendor/time/src/sys/local_offset_at/wasm_js.rs
@@ -7,7 +7,7 @@ pub(super) fn local_offset_at(datetime: OffsetDateTime) -> Option<UtcOffset> {
// The number of minutes returned by getTimezoneOffset() is positive if the local time zone
// is behind UTC, and negative if the local time zone is ahead of UTC. For example,
// for UTC+10, -600 will be returned.
- let timezone_offset = (js_date.get_timezone_offset() as i32) * -(Minute.per(Hour) as i32);
+ let timezone_offset = (js_date.get_timezone_offset() as i32) * -(Minute::per(Hour) as i32);
UtcOffset::from_whole_seconds(timezone_offset).ok()
}
diff --git a/vendor/time/src/sys/local_offset_at/windows.rs b/vendor/time/src/sys/local_offset_at/windows.rs
index a4d5882d6..7fb41e02a 100644
--- a/vendor/time/src/sys/local_offset_at/windows.rs
+++ b/vendor/time/src/sys/local_offset_at/windows.rs
@@ -57,7 +57,7 @@ fn systemtime_to_filetime(systime: &SystemTime) -> Option<FileTime> {
/// Convert a `FILETIME` to an `i64`, representing a number of seconds.
fn filetime_to_secs(filetime: &FileTime) -> i64 {
/// FILETIME represents 100-nanosecond intervals
- const FT_TO_SECS: i64 = Nanosecond.per(Second) as i64 / 100;
+ const FT_TO_SECS: i64 = Nanosecond::per(Second) as i64 / 100;
((filetime.dwHighDateTime as i64) << 32 | filetime.dwLowDateTime as i64) / FT_TO_SECS
}
diff --git a/vendor/time/src/tests.rs b/vendor/time/src/tests.rs
index 030c473be..e637ba03d 100644
--- a/vendor/time/src/tests.rs
+++ b/vendor/time/src/tests.rs
@@ -72,14 +72,6 @@ fn digit_count() {
}
#[test]
-fn default() {
- assert_eq!(
- duration::Padding::Optimize.clone(),
- duration::Padding::default()
- );
-}
-
-#[test]
fn debug() {
let _ = format!("{:?}", duration::Padding::Optimize);
let _ = format!("{:?}", parsing::ParsedItem(b"", 0));
diff --git a/vendor/time/src/time.rs b/vendor/time/src/time.rs
index 87b465bb9..74ab2a5ed 100644
--- a/vendor/time/src/time.rs
+++ b/vendor/time/src/time.rs
@@ -6,9 +6,12 @@ use core::time::Duration as StdDuration;
#[cfg(feature = "formatting")]
use std::io;
+use deranged::{RangedU32, RangedU8};
+
use crate::convert::*;
#[cfg(feature = "formatting")]
use crate::formatting::Formattable;
+use crate::internal_macros::{cascade, ensure_ranged, impl_add_assign, impl_sub_assign};
#[cfg(feature = "parsing")]
use crate::parsing::Parsable;
use crate::util::DateAdjustment;
@@ -23,27 +26,118 @@ pub(crate) enum Padding {
Optimize,
}
+/// The type of the `hour` field of `Time`.
+type Hours = RangedU8<0, { Hour::per(Day) - 1 }>;
+/// The type of the `minute` field of `Time`.
+type Minutes = RangedU8<0, { Minute::per(Hour) - 1 }>;
+/// The type of the `second` field of `Time`.
+type Seconds = RangedU8<0, { Second::per(Minute) - 1 }>;
+/// The type of the `nanosecond` field of `Time`.
+type Nanoseconds = RangedU32<0, { Nanosecond::per(Second) - 1 }>;
+
/// The clock time within a given date. Nanosecond precision.
///
/// All minutes are assumed to have exactly 60 seconds; no attempt is made to handle leap seconds
/// (either positive or negative).
///
/// When comparing two `Time`s, they are assumed to be in the same calendar date.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
+#[derive(Clone, Copy, Eq)]
+#[repr(C)]
pub struct Time {
+ // The order of this struct's fields matter!
+ // Do not change them.
+
+ // Little endian version
+ #[cfg(target_endian = "little")]
#[allow(clippy::missing_docs_in_private_items)]
- hour: u8,
+ nanosecond: Nanoseconds,
+ #[cfg(target_endian = "little")]
#[allow(clippy::missing_docs_in_private_items)]
- minute: u8,
+ second: Seconds,
+ #[cfg(target_endian = "little")]
#[allow(clippy::missing_docs_in_private_items)]
- second: u8,
+ minute: Minutes,
+ #[cfg(target_endian = "little")]
#[allow(clippy::missing_docs_in_private_items)]
- nanosecond: u32,
+ hour: Hours,
+ #[cfg(target_endian = "little")]
#[allow(clippy::missing_docs_in_private_items)]
padding: Padding,
+
+ // Big endian version
+ #[cfg(target_endian = "big")]
+ #[allow(clippy::missing_docs_in_private_items)]
+ padding: Padding,
+ #[cfg(target_endian = "big")]
+ #[allow(clippy::missing_docs_in_private_items)]
+ hour: Hours,
+ #[cfg(target_endian = "big")]
+ #[allow(clippy::missing_docs_in_private_items)]
+ minute: Minutes,
+ #[cfg(target_endian = "big")]
+ #[allow(clippy::missing_docs_in_private_items)]
+ second: Seconds,
+ #[cfg(target_endian = "big")]
+ #[allow(clippy::missing_docs_in_private_items)]
+ nanosecond: Nanoseconds,
+}
+
+impl core::hash::Hash for Time {
+ fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
+ self.as_u64().hash(state)
+ }
+}
+
+impl PartialEq for Time {
+ fn eq(&self, other: &Self) -> bool {
+ self.as_u64().eq(&other.as_u64())
+ }
+}
+
+impl PartialOrd for Time {
+ fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+ self.as_u64().partial_cmp(&other.as_u64())
+ }
+}
+
+impl Ord for Time {
+ fn cmp(&self, other: &Self) -> core::cmp::Ordering {
+ self.as_u64().cmp(&other.as_u64())
+ }
}
impl Time {
+ /// Provides an u64 based representation **of the correct endianness**
+ ///
+ /// This representation can be used to do comparisons equality testing or hashing.
+ const fn as_u64(self) -> u64 {
+ let nano_bytes = self.nanosecond.get().to_ne_bytes();
+
+ #[cfg(target_endian = "big")]
+ return u64::from_be_bytes([
+ self.padding as u8,
+ self.hour.get(),
+ self.minute.get(),
+ self.second.get(),
+ nano_bytes[0],
+ nano_bytes[1],
+ nano_bytes[2],
+ nano_bytes[3],
+ ]);
+
+ #[cfg(target_endian = "little")]
+ return u64::from_le_bytes([
+ nano_bytes[0],
+ nano_bytes[1],
+ nano_bytes[2],
+ nano_bytes[3],
+ self.second.get(),
+ self.minute.get(),
+ self.hour.get(),
+ self.padding as u8,
+ ]);
+ }
+
/// Create a `Time` that is exactly midnight.
///
/// ```rust
@@ -51,38 +145,44 @@ impl Time {
/// # use time_macros::time;
/// assert_eq!(Time::MIDNIGHT, time!(0:00));
/// ```
- pub const MIDNIGHT: Self = Self::__from_hms_nanos_unchecked(0, 0, 0, 0);
+ pub const MIDNIGHT: Self = Self::MIN;
/// The smallest value that can be represented by `Time`.
///
/// `00:00:00.0`
- pub(crate) const MIN: Self = Self::__from_hms_nanos_unchecked(0, 0, 0, 0);
+ pub(crate) const MIN: Self =
+ Self::from_hms_nanos_ranged(Hours::MIN, Minutes::MIN, Seconds::MIN, Nanoseconds::MIN);
/// The largest value that can be represented by `Time`.
///
/// `23:59:59.999_999_999`
- pub(crate) const MAX: Self = Self::__from_hms_nanos_unchecked(23, 59, 59, 999_999_999);
+ pub(crate) const MAX: Self =
+ Self::from_hms_nanos_ranged(Hours::MAX, Minutes::MAX, Seconds::MAX, Nanoseconds::MAX);
// region: constructors
/// Create a `Time` from its components.
+ ///
+ /// # Safety
+ ///
+ /// - `hours` must be in the range `0..=23`.
+ /// - `minutes` must be in the range `0..=59`.
+ /// - `seconds` must be in the range `0..=59`.
+ /// - `nanoseconds` must be in the range `0..=999_999_999`.
#[doc(hidden)]
- pub const fn __from_hms_nanos_unchecked(
+ pub const unsafe fn __from_hms_nanos_unchecked(
hour: u8,
minute: u8,
second: u8,
nanosecond: u32,
) -> Self {
- debug_assert!(hour < Hour.per(Day));
- debug_assert!(minute < Minute.per(Hour));
- debug_assert!(second < Second.per(Minute));
- debug_assert!(nanosecond < Nanosecond.per(Second));
-
- Self {
- hour,
- minute,
- second,
- nanosecond,
- padding: Padding::Optimize,
+ // Safety: The caller must uphold the safety invariants.
+ unsafe {
+ Self::from_hms_nanos_ranged(
+ Hours::new_unchecked(hour),
+ Minutes::new_unchecked(minute),
+ Seconds::new_unchecked(second),
+ Nanoseconds::new_unchecked(nanosecond),
+ )
}
}
@@ -100,10 +200,28 @@ impl Time {
/// assert!(Time::from_hms(0, 0, 60).is_err()); // 60 isn't a valid second.
/// ```
pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> {
- ensure_value_in_range!(hour in 0 => Hour.per(Day) - 1);
- ensure_value_in_range!(minute in 0 => Minute.per(Hour) - 1);
- ensure_value_in_range!(second in 0 => Second.per(Minute) - 1);
- Ok(Self::__from_hms_nanos_unchecked(hour, minute, second, 0))
+ Ok(Self::from_hms_nanos_ranged(
+ ensure_ranged!(Hours: hour),
+ ensure_ranged!(Minutes: minute),
+ ensure_ranged!(Seconds: second),
+ Nanoseconds::MIN,
+ ))
+ }
+
+ /// Create a `Time` from the hour, minute, second, and nanosecond.
+ pub(crate) const fn from_hms_nanos_ranged(
+ hour: Hours,
+ minute: Minutes,
+ second: Seconds,
+ nanosecond: Nanoseconds,
+ ) -> Self {
+ Self {
+ hour,
+ minute,
+ second,
+ nanosecond,
+ padding: Padding::Optimize,
+ }
}
/// Attempt to create a `Time` from the hour, minute, second, and millisecond.
@@ -126,15 +244,11 @@ impl Time {
second: u8,
millisecond: u16,
) -> Result<Self, error::ComponentRange> {
- ensure_value_in_range!(hour in 0 => Hour.per(Day) - 1);
- ensure_value_in_range!(minute in 0 => Minute.per(Hour) - 1);
- ensure_value_in_range!(second in 0 => Second.per(Minute) - 1);
- ensure_value_in_range!(millisecond in 0 => Millisecond.per(Second) - 1);
- Ok(Self::__from_hms_nanos_unchecked(
- hour,
- minute,
- second,
- millisecond as u32 * Nanosecond.per(Millisecond),
+ Ok(Self::from_hms_nanos_ranged(
+ ensure_ranged!(Hours: hour),
+ ensure_ranged!(Minutes: minute),
+ ensure_ranged!(Seconds: second),
+ ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per(Millisecond)),
))
}
@@ -158,15 +272,11 @@ impl Time {
second: u8,
microsecond: u32,
) -> Result<Self, error::ComponentRange> {
- ensure_value_in_range!(hour in 0 => Hour.per(Day) - 1);
- ensure_value_in_range!(minute in 0 => Minute.per(Hour) - 1);
- ensure_value_in_range!(second in 0 => Second.per(Minute) - 1);
- ensure_value_in_range!(microsecond in 0 => Microsecond.per(Second) - 1);
- Ok(Self::__from_hms_nanos_unchecked(
- hour,
- minute,
- second,
- microsecond * Nanosecond.per(Microsecond) as u32,
+ Ok(Self::from_hms_nanos_ranged(
+ ensure_ranged!(Hours: hour),
+ ensure_ranged!(Minutes: minute),
+ ensure_ranged!(Seconds: second),
+ ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per(Microsecond) as u32),
))
}
@@ -190,12 +300,11 @@ impl Time {
second: u8,
nanosecond: u32,
) -> Result<Self, error::ComponentRange> {
- ensure_value_in_range!(hour in 0 => Hour.per(Day) - 1);
- ensure_value_in_range!(minute in 0 => Minute.per(Hour) - 1);
- ensure_value_in_range!(second in 0 => Second.per(Minute) - 1);
- ensure_value_in_range!(nanosecond in 0 => Nanosecond.per(Second) - 1);
- Ok(Self::__from_hms_nanos_unchecked(
- hour, minute, second, nanosecond,
+ Ok(Self::from_hms_nanos_ranged(
+ ensure_ranged!(Hours: hour),
+ ensure_ranged!(Minutes: minute),
+ ensure_ranged!(Seconds: second),
+ ensure_ranged!(Nanoseconds: nanosecond),
))
}
// endregion constructors
@@ -209,7 +318,7 @@ impl Time {
/// assert_eq!(time!(23:59:59).as_hms(), (23, 59, 59));
/// ```
pub const fn as_hms(self) -> (u8, u8, u8) {
- (self.hour, self.minute, self.second)
+ (self.hour.get(), self.minute.get(), self.second.get())
}
/// Get the clock hour, minute, second, and millisecond.
@@ -221,10 +330,10 @@ impl Time {
/// ```
pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
(
- self.hour,
- self.minute,
- self.second,
- (self.nanosecond / Nanosecond.per(Millisecond)) as u16,
+ self.hour.get(),
+ self.minute.get(),
+ self.second.get(),
+ (self.nanosecond.get() / Nanosecond::per(Millisecond)) as u16,
)
}
@@ -240,10 +349,10 @@ impl Time {
/// ```
pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
(
- self.hour,
- self.minute,
- self.second,
- self.nanosecond / Nanosecond.per(Microsecond) as u32,
+ self.hour.get(),
+ self.minute.get(),
+ self.second.get(),
+ self.nanosecond.get() / Nanosecond::per(Microsecond) as u32,
)
}
@@ -258,6 +367,17 @@ impl Time {
/// );
/// ```
pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
+ (
+ self.hour.get(),
+ self.minute.get(),
+ self.second.get(),
+ self.nanosecond.get(),
+ )
+ }
+
+ /// Get the clock hour, minute, second, and nanosecond.
+ #[cfg(feature = "quickcheck")]
+ pub(crate) const fn as_hms_nano_ranged(self) -> (Hours, Minutes, Seconds, Nanoseconds) {
(self.hour, self.minute, self.second, self.nanosecond)
}
@@ -271,7 +391,7 @@ impl Time {
/// assert_eq!(time!(23:59:59).hour(), 23);
/// ```
pub const fn hour(self) -> u8 {
- self.hour
+ self.hour.get()
}
/// Get the minute within the hour.
@@ -284,7 +404,7 @@ impl Time {
/// assert_eq!(time!(23:59:59).minute(), 59);
/// ```
pub const fn minute(self) -> u8 {
- self.minute
+ self.minute.get()
}
/// Get the second within the minute.
@@ -297,7 +417,7 @@ impl Time {
/// assert_eq!(time!(23:59:59).second(), 59);
/// ```
pub const fn second(self) -> u8 {
- self.second
+ self.second.get()
}
/// Get the milliseconds within the second.
@@ -310,7 +430,7 @@ impl Time {
/// assert_eq!(time!(23:59:59.999).millisecond(), 999);
/// ```
pub const fn millisecond(self) -> u16 {
- (self.nanosecond / Nanosecond.per(Millisecond)) as _
+ (self.nanosecond.get() / Nanosecond::per(Millisecond)) as _
}
/// Get the microseconds within the second.
@@ -323,7 +443,7 @@ impl Time {
/// assert_eq!(time!(23:59:59.999_999).microsecond(), 999_999);
/// ```
pub const fn microsecond(self) -> u32 {
- self.nanosecond / Nanosecond.per(Microsecond) as u32
+ self.nanosecond.get() / Nanosecond::per(Microsecond) as u32
}
/// Get the nanoseconds within the second.
@@ -336,7 +456,7 @@ impl Time {
/// assert_eq!(time!(23:59:59.999_999_999).nanosecond(), 999_999_999);
/// ```
pub const fn nanosecond(self) -> u32 {
- self.nanosecond
+ self.nanosecond.get()
}
// endregion getters
@@ -344,116 +464,135 @@ impl Time {
/// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning whether
/// the date is different.
pub(crate) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) {
- let mut nanoseconds = self.nanosecond as i32 + duration.subsec_nanoseconds();
+ let mut nanoseconds = self.nanosecond.get() as i32 + duration.subsec_nanoseconds();
let mut seconds =
- self.second as i8 + (duration.whole_seconds() % Second.per(Minute) as i64) as i8;
+ self.second.get() as i8 + (duration.whole_seconds() % Second::per(Minute) as i64) as i8;
let mut minutes =
- self.minute as i8 + (duration.whole_minutes() % Minute.per(Hour) as i64) as i8;
- let mut hours = self.hour as i8 + (duration.whole_hours() % Hour.per(Day) as i64) as i8;
+ self.minute.get() as i8 + (duration.whole_minutes() % Minute::per(Hour) as i64) as i8;
+ let mut hours =
+ self.hour.get() as i8 + (duration.whole_hours() % Hour::per(Day) as i64) as i8;
let mut date_adjustment = DateAdjustment::None;
- cascade!(nanoseconds in 0..Nanosecond.per(Second) as _ => seconds);
- cascade!(seconds in 0..Second.per(Minute) as _ => minutes);
- cascade!(minutes in 0..Minute.per(Hour) as _ => hours);
- if hours >= Hour.per(Day) as _ {
- hours -= Hour.per(Day) as i8;
+ cascade!(nanoseconds in 0..Nanosecond::per(Second) as _ => seconds);
+ cascade!(seconds in 0..Second::per(Minute) as _ => minutes);
+ cascade!(minutes in 0..Minute::per(Hour) as _ => hours);
+ if hours >= Hour::per(Day) as _ {
+ hours -= Hour::per(Day) as i8;
date_adjustment = DateAdjustment::Next;
} else if hours < 0 {
- hours += Hour.per(Day) as i8;
+ hours += Hour::per(Day) as i8;
date_adjustment = DateAdjustment::Previous;
}
(
date_adjustment,
- Self::__from_hms_nanos_unchecked(
- hours as _,
- minutes as _,
- seconds as _,
- nanoseconds as _,
- ),
+ // Safety: The cascades above ensure the values are in range.
+ unsafe {
+ Self::__from_hms_nanos_unchecked(
+ hours as _,
+ minutes as _,
+ seconds as _,
+ nanoseconds as _,
+ )
+ },
)
}
/// Subtract the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning
/// whether the date is different.
pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
- let mut nanoseconds = self.nanosecond as i32 - duration.subsec_nanoseconds();
+ let mut nanoseconds = self.nanosecond.get() as i32 - duration.subsec_nanoseconds();
let mut seconds =
- self.second as i8 - (duration.whole_seconds() % Second.per(Minute) as i64) as i8;
+ self.second.get() as i8 - (duration.whole_seconds() % Second::per(Minute) as i64) as i8;
let mut minutes =
- self.minute as i8 - (duration.whole_minutes() % Minute.per(Hour) as i64) as i8;
- let mut hours = self.hour as i8 - (duration.whole_hours() % Hour.per(Day) as i64) as i8;
+ self.minute.get() as i8 - (duration.whole_minutes() % Minute::per(Hour) as i64) as i8;
+ let mut hours =
+ self.hour.get() as i8 - (duration.whole_hours() % Hour::per(Day) as i64) as i8;
let mut date_adjustment = DateAdjustment::None;
- cascade!(nanoseconds in 0..Nanosecond.per(Second) as _ => seconds);
- cascade!(seconds in 0..Second.per(Minute) as _ => minutes);
- cascade!(minutes in 0..Minute.per(Hour) as _ => hours);
- if hours >= Hour.per(Day) as _ {
- hours -= Hour.per(Day) as i8;
+ cascade!(nanoseconds in 0..Nanosecond::per(Second) as _ => seconds);
+ cascade!(seconds in 0..Second::per(Minute) as _ => minutes);
+ cascade!(minutes in 0..Minute::per(Hour) as _ => hours);
+ if hours >= Hour::per(Day) as _ {
+ hours -= Hour::per(Day) as i8;
date_adjustment = DateAdjustment::Next;
} else if hours < 0 {
- hours += Hour.per(Day) as i8;
+ hours += Hour::per(Day) as i8;
date_adjustment = DateAdjustment::Previous;
}
(
date_adjustment,
- Self::__from_hms_nanos_unchecked(
- hours as _,
- minutes as _,
- seconds as _,
- nanoseconds as _,
- ),
+ // Safety: The cascades above ensure the values are in range.
+ unsafe {
+ Self::__from_hms_nanos_unchecked(
+ hours as _,
+ minutes as _,
+ seconds as _,
+ nanoseconds as _,
+ )
+ },
)
}
/// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
/// returning whether the date is the previous date as the first element of the tuple.
pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
- let mut nanosecond = self.nanosecond + duration.subsec_nanos();
- let mut second = self.second + (duration.as_secs() % Second.per(Minute) as u64) as u8;
- let mut minute = self.minute
- + ((duration.as_secs() / Second.per(Minute) as u64) % Minute.per(Hour) as u64) as u8;
- let mut hour = self.hour
- + ((duration.as_secs() / Second.per(Hour) as u64) % Hour.per(Day) as u64) as u8;
+ let mut nanosecond = self.nanosecond.get() + duration.subsec_nanos();
+ let mut second =
+ self.second.get() + (duration.as_secs() % Second::per(Minute) as u64) as u8;
+ let mut minute = self.minute.get()
+ + ((duration.as_secs() / Second::per(Minute) as u64) % Minute::per(Hour) as u64) as u8;
+ let mut hour = self.hour.get()
+ + ((duration.as_secs() / Second::per(Hour) as u64) % Hour::per(Day) as u64) as u8;
let mut is_next_day = false;
- cascade!(nanosecond in 0..Nanosecond.per(Second) => second);
- cascade!(second in 0..Second.per(Minute) => minute);
- cascade!(minute in 0..Minute.per(Hour) => hour);
- if hour >= Hour.per(Day) {
- hour -= Hour.per(Day);
+ cascade!(nanosecond in 0..Nanosecond::per(Second) => second);
+ cascade!(second in 0..Second::per(Minute) => minute);
+ cascade!(minute in 0..Minute::per(Hour) => hour);
+ if hour >= Hour::per(Day) {
+ hour -= Hour::per(Day);
is_next_day = true;
}
(
is_next_day,
- Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond),
+ // Safety: The cascades above ensure the values are in range.
+ unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) },
)
}
/// Subtract the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
/// returning whether the date is the previous date as the first element of the tuple.
pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
- let mut nanosecond = self.nanosecond as i32 - duration.subsec_nanos() as i32;
- let mut second = self.second as i8 - (duration.as_secs() % Second.per(Minute) as u64) as i8;
- let mut minute = self.minute as i8
- - ((duration.as_secs() / Second.per(Minute) as u64) % Minute.per(Hour) as u64) as i8;
- let mut hour = self.hour as i8
- - ((duration.as_secs() / Second.per(Hour) as u64) % Hour.per(Day) as u64) as i8;
+ let mut nanosecond = self.nanosecond.get() as i32 - duration.subsec_nanos() as i32;
+ let mut second =
+ self.second.get() as i8 - (duration.as_secs() % Second::per(Minute) as u64) as i8;
+ let mut minute = self.minute.get() as i8
+ - ((duration.as_secs() / Second::per(Minute) as u64) % Minute::per(Hour) as u64) as i8;
+ let mut hour = self.hour.get() as i8
+ - ((duration.as_secs() / Second::per(Hour) as u64) % Hour::per(Day) as u64) as i8;
let mut is_previous_day = false;
- cascade!(nanosecond in 0..Nanosecond.per(Second) as _ => second);
- cascade!(second in 0..Second.per(Minute) as _ => minute);
- cascade!(minute in 0..Minute.per(Hour) as _ => hour);
+ cascade!(nanosecond in 0..Nanosecond::per(Second) as _ => second);
+ cascade!(second in 0..Second::per(Minute) as _ => minute);
+ cascade!(minute in 0..Minute::per(Hour) as _ => hour);
if hour < 0 {
- hour += Hour.per(Day) as i8;
+ hour += Hour::per(Day) as i8;
is_previous_day = true;
}
(
is_previous_day,
- Self::__from_hms_nanos_unchecked(hour as _, minute as _, second as _, nanosecond as _),
+ // Safety: The cascades above ensure the values are in range.
+ unsafe {
+ Self::__from_hms_nanos_unchecked(
+ hour as _,
+ minute as _,
+ second as _,
+ nanosecond as _,
+ )
+ },
)
}
// endregion arithmetic helpers
@@ -470,14 +609,9 @@ impl Time {
/// assert!(time!(01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
/// ```
#[must_use = "This method does not mutate the original `Time`."]
- pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> {
- ensure_value_in_range!(hour in 0 => Hour.per(Day) - 1);
- Ok(Self::__from_hms_nanos_unchecked(
- hour,
- self.minute,
- self.second,
- self.nanosecond,
- ))
+ pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
+ self.hour = ensure_ranged!(Hours: hour);
+ Ok(self)
}
/// Replace the minutes within the hour.
@@ -491,14 +625,9 @@ impl Time {
/// assert!(time!(01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
/// ```
#[must_use = "This method does not mutate the original `Time`."]
- pub const fn replace_minute(self, minute: u8) -> Result<Self, error::ComponentRange> {
- ensure_value_in_range!(minute in 0 => Minute.per(Hour) - 1);
- Ok(Self::__from_hms_nanos_unchecked(
- self.hour,
- minute,
- self.second,
- self.nanosecond,
- ))
+ pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
+ self.minute = ensure_ranged!(Minutes: minute);
+ Ok(self)
}
/// Replace the seconds within the minute.
@@ -512,14 +641,9 @@ impl Time {
/// assert!(time!(01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
/// ```
#[must_use = "This method does not mutate the original `Time`."]
- pub const fn replace_second(self, second: u8) -> Result<Self, error::ComponentRange> {
- ensure_value_in_range!(second in 0 => Second.per(Minute) - 1);
- Ok(Self::__from_hms_nanos_unchecked(
- self.hour,
- self.minute,
- second,
- self.nanosecond,
- ))
+ pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
+ self.second = ensure_ranged!(Seconds: second);
+ Ok(self)
}
/// Replace the milliseconds within the second.
@@ -534,16 +658,12 @@ impl Time {
/// ```
#[must_use = "This method does not mutate the original `Time`."]
pub const fn replace_millisecond(
- self,
+ mut self,
millisecond: u16,
) -> Result<Self, error::ComponentRange> {
- ensure_value_in_range!(millisecond in 0 => Millisecond.per(Second) - 1);
- Ok(Self::__from_hms_nanos_unchecked(
- self.hour,
- self.minute,
- self.second,
- millisecond as u32 * Nanosecond.per(Millisecond),
- ))
+ self.nanosecond =
+ ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per(Millisecond));
+ Ok(self)
}
/// Replace the microseconds within the second.
@@ -558,16 +678,12 @@ impl Time {
/// ```
#[must_use = "This method does not mutate the original `Time`."]
pub const fn replace_microsecond(
- self,
+ mut self,
microsecond: u32,
) -> Result<Self, error::ComponentRange> {
- ensure_value_in_range!(microsecond in 0 => Microsecond.per(Second) - 1);
- Ok(Self::__from_hms_nanos_unchecked(
- self.hour,
- self.minute,
- self.second,
- microsecond * Nanosecond.per(Microsecond) as u32,
- ))
+ self.nanosecond =
+ ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per(Microsecond) as u32);
+ Ok(self)
}
/// Replace the nanoseconds within the second.
@@ -581,14 +697,12 @@ impl Time {
/// assert!(time!(01:02:03.004_005_006).replace_nanosecond(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond
/// ```
#[must_use = "This method does not mutate the original `Time`."]
- pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
- ensure_value_in_range!(nanosecond in 0 => Nanosecond.per(Second) - 1);
- Ok(Self::__from_hms_nanos_unchecked(
- self.hour,
- self.minute,
- self.second,
- nanosecond,
- ))
+ pub const fn replace_nanosecond(
+ mut self,
+ nanosecond: u32,
+ ) -> Result<Self, error::ComponentRange> {
+ self.nanosecond = ensure_ranged!(Nanoseconds: nanosecond);
+ Ok(self)
}
// endregion replacement
}
@@ -754,24 +868,31 @@ impl Sub for Time {
/// assert_eq!(time!(0:00) - time!(23:00), (-23).hours());
/// ```
fn sub(self, rhs: Self) -> Self::Output {
- let hour_diff = (self.hour as i8) - (rhs.hour as i8);
- let minute_diff = (self.minute as i8) - (rhs.minute as i8);
- let second_diff = (self.second as i8) - (rhs.second as i8);
- let nanosecond_diff = (self.nanosecond as i32) - (rhs.nanosecond as i32);
+ let hour_diff = (self.hour.get() as i8) - (rhs.hour.get() as i8);
+ let minute_diff = (self.minute.get() as i8) - (rhs.minute.get() as i8);
+ let second_diff = (self.second.get() as i8) - (rhs.second.get() as i8);
+ let nanosecond_diff = (self.nanosecond.get() as i32) - (rhs.nanosecond.get() as i32);
- let seconds = hour_diff as i64 * Second.per(Hour) as i64
- + minute_diff as i64 * Second.per(Minute) as i64
+ let seconds = hour_diff as i64 * Second::per(Hour) as i64
+ + minute_diff as i64 * Second::per(Minute) as i64
+ second_diff as i64;
let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 {
- (seconds - 1, nanosecond_diff + Nanosecond.per(Second) as i32)
+ (
+ seconds - 1,
+ nanosecond_diff + Nanosecond::per(Second) as i32,
+ )
} else if seconds < 0 && nanosecond_diff > 0 {
- (seconds + 1, nanosecond_diff - Nanosecond.per(Second) as i32)
+ (
+ seconds + 1,
+ nanosecond_diff - Nanosecond::per(Second) as i32,
+ )
} else {
(seconds, nanosecond_diff)
};
- Duration::new_unchecked(seconds, nanoseconds)
+ // Safety: `nanoseconds` is in range due to the overflow handling.
+ unsafe { Duration::new_unchecked(seconds, nanoseconds) }
}
}
// endregion trait impls
diff --git a/vendor/time/src/utc_offset.rs b/vendor/time/src/utc_offset.rs
index af7fd1bf7..86a937d7a 100644
--- a/vendor/time/src/utc_offset.rs
+++ b/vendor/time/src/utc_offset.rs
@@ -5,10 +5,13 @@ use core::ops::Neg;
#[cfg(feature = "formatting")]
use std::io;
+use deranged::{RangedI32, RangedI8};
+
use crate::convert::*;
use crate::error;
#[cfg(feature = "formatting")]
use crate::formatting::Formattable;
+use crate::internal_macros::ensure_ranged;
#[cfg(feature = "parsing")]
use crate::parsing::Parsable;
#[cfg(feature = "local-offset")]
@@ -16,6 +19,13 @@ use crate::sys::local_offset_at;
#[cfg(feature = "local-offset")]
use crate::OffsetDateTime;
+/// The type of the `hours` field of `UtcOffset`.
+type Hours = RangedI8<{ -(Hour::per(Day) as i8 - 1) }, { Hour::per(Day) as i8 - 1 }>;
+/// The type of the `minutes` field of `UtcOffset`.
+type Minutes = RangedI8<{ -(Minute::per(Hour) as i8 - 1) }, { Minute::per(Hour) as i8 - 1 }>;
+/// The type of the `seconds` field of `UtcOffset`.
+type Seconds = RangedI8<{ -(Second::per(Minute) as i8 - 1) }, { Second::per(Minute) as i8 - 1 }>;
+
/// An offset from UTC.
///
/// This struct can store values up to ±23:59:59. If you need support outside this range, please
@@ -24,11 +34,11 @@ use crate::OffsetDateTime;
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct UtcOffset {
#[allow(clippy::missing_docs_in_private_items)]
- hours: i8,
+ hours: Hours,
#[allow(clippy::missing_docs_in_private_items)]
- minutes: i8,
+ minutes: Minutes,
#[allow(clippy::missing_docs_in_private_items)]
- seconds: i8,
+ seconds: Seconds,
}
impl UtcOffset {
@@ -39,34 +49,32 @@ impl UtcOffset {
/// # use time_macros::offset;
/// assert_eq!(UtcOffset::UTC, offset!(UTC));
/// ```
- pub const UTC: Self = Self::__from_hms_unchecked(0, 0, 0);
+ #[allow(clippy::undocumented_unsafe_blocks)] // rust-lang/rust-clippy#11246
+ // Safety: All values are in range.
+ pub const UTC: Self = unsafe { Self::__from_hms_unchecked(0, 0, 0) };
// region: constructors
/// Create a `UtcOffset` representing an offset of the hours, minutes, and seconds provided, the
/// validity of which must be guaranteed by the caller. All three parameters must have the same
/// sign.
+ ///
+ /// # Safety
+ ///
+ /// - Hours must be in the range `-23..=23`.
+ /// - Minutes must be in the range `-59..=59`.
+ /// - Seconds must be in the range `-59..=59`.
+ ///
+ /// While the signs of the parameters are required to match to avoid bugs, this is not a safety
+ /// invariant.
#[doc(hidden)]
- pub const fn __from_hms_unchecked(hours: i8, minutes: i8, seconds: i8) -> Self {
- if hours < 0 {
- debug_assert!(minutes <= 0);
- debug_assert!(seconds <= 0);
- } else if hours > 0 {
- debug_assert!(minutes >= 0);
- debug_assert!(seconds >= 0);
- }
- if minutes < 0 {
- debug_assert!(seconds <= 0);
- } else if minutes > 0 {
- debug_assert!(seconds >= 0);
- }
- debug_assert!(hours.unsigned_abs() < 24);
- debug_assert!(minutes.unsigned_abs() < Minute.per(Hour));
- debug_assert!(seconds.unsigned_abs() < Second.per(Minute));
-
- Self {
- hours,
- minutes,
- seconds,
+ pub const unsafe fn __from_hms_unchecked(hours: i8, minutes: i8, seconds: i8) -> Self {
+ // Safety: The caller must uphold the safety invariants.
+ unsafe {
+ Self::from_hms_ranged_unchecked(
+ Hours::new_unchecked(hours),
+ Minutes::new_unchecked(minutes),
+ Seconds::new_unchecked(seconds),
+ )
}
}
@@ -84,29 +92,71 @@ impl UtcOffset {
/// ```
pub const fn from_hms(
hours: i8,
- mut minutes: i8,
- mut seconds: i8,
+ minutes: i8,
+ seconds: i8,
) -> Result<Self, error::ComponentRange> {
- ensure_value_in_range!(hours in -23 => 23);
- ensure_value_in_range!(
- minutes in -(Minute.per(Hour) as i8 - 1) => Minute.per(Hour) as i8 - 1
- );
- ensure_value_in_range!(
- seconds in -(Second.per(Minute) as i8 - 1) => Second.per(Minute) as i8 - 1
- );
-
- if (hours > 0 && minutes < 0) || (hours < 0 && minutes > 0) {
- minutes *= -1;
+ Ok(Self::from_hms_ranged(
+ ensure_ranged!(Hours: hours),
+ ensure_ranged!(Minutes: minutes),
+ ensure_ranged!(Seconds: seconds),
+ ))
+ }
+
+ /// Create a `UtcOffset` representing an offset of the hours, minutes, and seconds provided. All
+ /// three parameters must have the same sign.
+ ///
+ /// While the signs of the parameters are required to match, this is not a safety invariant.
+ pub(crate) const fn from_hms_ranged_unchecked(
+ hours: Hours,
+ minutes: Minutes,
+ seconds: Seconds,
+ ) -> Self {
+ if hours.get() < 0 {
+ debug_assert!(minutes.get() <= 0);
+ debug_assert!(seconds.get() <= 0);
+ } else if hours.get() > 0 {
+ debug_assert!(minutes.get() >= 0);
+ debug_assert!(seconds.get() >= 0);
+ }
+ if minutes.get() < 0 {
+ debug_assert!(seconds.get() <= 0);
+ } else if minutes.get() > 0 {
+ debug_assert!(seconds.get() >= 0);
+ }
+
+ Self {
+ hours,
+ minutes,
+ seconds,
}
- if (hours > 0 && seconds < 0)
- || (hours < 0 && seconds > 0)
- || (minutes > 0 && seconds < 0)
- || (minutes < 0 && seconds > 0)
+ }
+
+ /// Create a `UtcOffset` representing an offset by the number of hours, minutes, and seconds
+ /// provided.
+ ///
+ /// The sign of all three components should match. If they do not, all smaller components will
+ /// have their signs flipped.
+ pub(crate) const fn from_hms_ranged(
+ hours: Hours,
+ mut minutes: Minutes,
+ mut seconds: Seconds,
+ ) -> Self {
+ if (hours.get() > 0 && minutes.get() < 0) || (hours.get() < 0 && minutes.get() > 0) {
+ minutes = minutes.neg();
+ }
+ if (hours.get() > 0 && seconds.get() < 0)
+ || (hours.get() < 0 && seconds.get() > 0)
+ || (minutes.get() > 0 && seconds.get() < 0)
+ || (minutes.get() < 0 && seconds.get() > 0)
{
- seconds *= -1;
+ seconds = seconds.neg();
}
- Ok(Self::__from_hms_unchecked(hours, minutes, seconds))
+ Self {
+ hours,
+ minutes,
+ seconds,
+ }
}
/// Create a `UtcOffset` representing an offset by the number of seconds provided.
@@ -117,15 +167,28 @@ impl UtcOffset {
/// # Ok::<_, time::Error>(())
/// ```
pub const fn from_whole_seconds(seconds: i32) -> Result<Self, error::ComponentRange> {
- ensure_value_in_range!(
- seconds in -24 * Second.per(Hour) as i32 - 1 => 24 * Second.per(Hour) as i32 - 1
- );
-
- Ok(Self::__from_hms_unchecked(
- (seconds / Second.per(Hour) as i32) as _,
- ((seconds % Second.per(Hour) as i32) / Minute.per(Hour) as i32) as _,
- (seconds % Second.per(Minute) as i32) as _,
- ))
+ type WholeSeconds = RangedI32<
+ {
+ Hours::MIN.get() as i32 * Second::per(Hour) as i32
+ + Minutes::MIN.get() as i32 * Second::per(Minute) as i32
+ + Seconds::MIN.get() as i32
+ },
+ {
+ Hours::MAX.get() as i32 * Second::per(Hour) as i32
+ + Minutes::MAX.get() as i32 * Second::per(Minute) as i32
+ + Seconds::MAX.get() as i32
+ },
+ >;
+ ensure_ranged!(WholeSeconds: seconds);
+
+ // Safety: The value was checked to be in range.
+ Ok(unsafe {
+ Self::__from_hms_unchecked(
+ (seconds / Second::per(Hour) as i32) as _,
+ ((seconds % Second::per(Hour) as i32) / Minute::per(Hour) as i32) as _,
+ (seconds % Second::per(Minute) as i32) as _,
+ )
+ })
}
// endregion constructors
@@ -139,6 +202,13 @@ impl UtcOffset {
/// assert_eq!(offset!(-1:02:03).as_hms(), (-1, -2, -3));
/// ```
pub const fn as_hms(self) -> (i8, i8, i8) {
+ (self.hours.get(), self.minutes.get(), self.seconds.get())
+ }
+
+ /// Obtain the UTC offset as its hours, minutes, and seconds. The sign of all three components
+ /// will always match. A positive value indicates an offset to the east; a negative to the west.
+ #[cfg(feature = "quickcheck")]
+ pub(crate) const fn as_hms_ranged(self) -> (Hours, Minutes, Seconds) {
(self.hours, self.minutes, self.seconds)
}
@@ -151,7 +221,7 @@ impl UtcOffset {
/// assert_eq!(offset!(-1:02:03).whole_hours(), -1);
/// ```
pub const fn whole_hours(self) -> i8 {
- self.hours
+ self.hours.get()
}
/// Obtain the number of whole minutes the offset is from UTC. A positive value indicates an
@@ -163,7 +233,7 @@ impl UtcOffset {
/// assert_eq!(offset!(-1:02:03).whole_minutes(), -62);
/// ```
pub const fn whole_minutes(self) -> i16 {
- self.hours as i16 * Minute.per(Hour) as i16 + self.minutes as i16
+ self.hours.get() as i16 * Minute::per(Hour) as i16 + self.minutes.get() as i16
}
/// Obtain the number of minutes past the hour the offset is from UTC. A positive value
@@ -175,7 +245,7 @@ impl UtcOffset {
/// assert_eq!(offset!(-1:02:03).minutes_past_hour(), -2);
/// ```
pub const fn minutes_past_hour(self) -> i8 {
- self.minutes
+ self.minutes.get()
}
/// Obtain the number of whole seconds the offset is from UTC. A positive value indicates an
@@ -189,9 +259,9 @@ impl UtcOffset {
// This may be useful for anyone manually implementing arithmetic, as it
// would let them construct a `Duration` directly.
pub const fn whole_seconds(self) -> i32 {
- self.hours as i32 * Second.per(Hour) as i32
- + self.minutes as i32 * Second.per(Minute) as i32
- + self.seconds as i32
+ self.hours.get() as i32 * Second::per(Hour) as i32
+ + self.minutes.get() as i32 * Second::per(Minute) as i32
+ + self.seconds.get() as i32
}
/// Obtain the number of seconds past the minute the offset is from UTC. A positive value
@@ -203,7 +273,7 @@ impl UtcOffset {
/// assert_eq!(offset!(-1:02:03).seconds_past_minute(), -3);
/// ```
pub const fn seconds_past_minute(self) -> i8 {
- self.seconds
+ self.seconds.get()
}
// endregion getters
@@ -218,7 +288,7 @@ impl UtcOffset {
/// assert!(offset!(UTC).is_utc());
/// ```
pub const fn is_utc(self) -> bool {
- self.hours == 0 && self.minutes == 0 && self.seconds == 0
+ self.hours.get() == 0 && self.minutes.get() == 0 && self.seconds.get() == 0
}
/// Check if the offset is positive, or east of UTC.
@@ -230,7 +300,7 @@ impl UtcOffset {
/// assert!(!offset!(UTC).is_positive());
/// ```
pub const fn is_positive(self) -> bool {
- self.hours > 0 || self.minutes > 0 || self.seconds > 0
+ self.hours.get() > 0 || self.minutes.get() > 0 || self.seconds.get() > 0
}
/// Check if the offset is negative, or west of UTC.
@@ -242,7 +312,7 @@ impl UtcOffset {
/// assert!(!offset!(UTC).is_negative());
/// ```
pub const fn is_negative(self) -> bool {
- self.hours < 0 || self.minutes < 0 || self.seconds < 0
+ self.hours.get() < 0 || self.minutes.get() < 0 || self.seconds.get() < 0
}
// endregion is_{sign}
@@ -334,7 +404,7 @@ impl fmt::Display for UtcOffset {
if self.is_negative() { '-' } else { '+' },
self.hours.abs(),
self.minutes.abs(),
- self.seconds.abs()
+ self.seconds.abs(),
)
}
}
@@ -350,6 +420,6 @@ impl Neg for UtcOffset {
type Output = Self;
fn neg(self) -> Self::Output {
- Self::__from_hms_unchecked(-self.hours, -self.minutes, -self.seconds)
+ Self::from_hms_ranged(self.hours.neg(), self.minutes.neg(), self.seconds.neg())
}
}
diff --git a/vendor/time/src/weekday.rs b/vendor/time/src/weekday.rs
index d530a2e4d..07642498d 100644
--- a/vendor/time/src/weekday.rs
+++ b/vendor/time/src/weekday.rs
@@ -13,19 +13,19 @@ use crate::error;
/// Friday), this type does not implement `PartialOrd` or `Ord`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Weekday {
- #[allow(clippy::missing_docs_in_private_items)]
+ #[allow(missing_docs)]
Monday,
- #[allow(clippy::missing_docs_in_private_items)]
+ #[allow(missing_docs)]
Tuesday,
- #[allow(clippy::missing_docs_in_private_items)]
+ #[allow(missing_docs)]
Wednesday,
- #[allow(clippy::missing_docs_in_private_items)]
+ #[allow(missing_docs)]
Thursday,
- #[allow(clippy::missing_docs_in_private_items)]
+ #[allow(missing_docs)]
Friday,
- #[allow(clippy::missing_docs_in_private_items)]
+ #[allow(missing_docs)]
Saturday,
- #[allow(clippy::missing_docs_in_private_items)]
+ #[allow(missing_docs)]
Sunday,
}
@@ -88,6 +88,28 @@ impl Weekday {
}
}
+ /// Get n-th previous day.
+ ///
+ /// ```rust
+ /// # use time::Weekday;
+ /// assert_eq!(Weekday::Monday.nth_prev(1), Weekday::Sunday);
+ /// assert_eq!(Weekday::Sunday.nth_prev(10), Weekday::Thursday);
+ /// ```
+ pub const fn nth_prev(self, n: u8) -> Self {
+ match self.number_days_from_monday() as i8 - (n % 7) as i8 {
+ 1 | -6 => Tuesday,
+ 2 | -5 => Wednesday,
+ 3 | -4 => Thursday,
+ 4 | -3 => Friday,
+ 5 | -2 => Saturday,
+ 6 | -1 => Sunday,
+ val => {
+ debug_assert!(val == 0);
+ Monday
+ }
+ }
+ }
+
/// Get the one-indexed number of days from Monday.
///
/// ```rust