diff options
Diffstat (limited to 'vendor/time/src')
25 files changed, 836 insertions, 492 deletions
diff --git a/vendor/time/src/date.rs b/vendor/time/src/date.rs index b3023e0c0..9f194b434 100644 --- a/vendor/time/src/date.rs +++ b/vendor/time/src/date.rs @@ -6,6 +6,7 @@ use core::time::Duration as StdDuration; #[cfg(feature = "formatting")] use std::io; +use crate::convert::*; #[cfg(feature = "formatting")] use crate::formatting::Formattable; #[cfg(feature = "parsing")] @@ -1013,8 +1014,10 @@ 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() / 86_400) as i32) - .expect("overflow adding duration to date") + Self::from_julian_day( + self.to_julian_day() + (duration.as_secs() / Second.per(Day) as u64) as i32, + ) + .expect("overflow adding duration to date") } } @@ -1033,8 +1036,10 @@ 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() / 86_400) as i32) - .expect("overflow subtracting duration from date") + Self::from_julian_day( + self.to_julian_day() - (duration.as_secs() / Second.per(Day) as u64) as i32, + ) + .expect("overflow subtracting duration from date") } } diff --git a/vendor/time/src/date_time.rs b/vendor/time/src/date_time.rs index 592ced1fb..819f6d36b 100644 --- a/vendor/time/src/date_time.rs +++ b/vendor/time/src/date_time.rs @@ -16,6 +16,7 @@ use std::io; #[cfg(feature = "std")] use std::time::SystemTime; +use crate::convert::*; use crate::date::{MAX_YEAR, MIN_YEAR}; #[cfg(feature = "formatting")] use crate::formatting::Formattable; @@ -146,6 +147,7 @@ const fn maybe_offset_as_offset_opt<O: MaybeOffset>( if O::STATIC_OFFSET.is_some() { O::STATIC_OFFSET } else if O::HAS_MEMORY_OFFSET { + #[repr(C)] // needed to guarantee they align at the start union Convert<O: MaybeOffset> { input: O::MemoryOffsetType, output: UtcOffset, @@ -171,6 +173,7 @@ const fn maybe_offset_as_offset<O: MaybeOffset + HasLogicalOffset>( pub(crate) const fn maybe_offset_from_offset<O: MaybeOffset>( offset: UtcOffset, ) -> O::MemoryOffsetType { + #[repr(C)] // needed to guarantee the types align at the start union Convert<O: MaybeOffset> { input: UtcOffset, output: O::MemoryOffsetType, @@ -257,14 +260,14 @@ impl<O: MaybeOffset> DateTime<O> { // 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, 86_400) as i32, + UNIX_EPOCH_JULIAN_DAY + div_floor!(timestamp, Second.per(Day) as i64) as i32, ); - let seconds_within_day = timestamp.rem_euclid(86_400); + let seconds_within_day = timestamp.rem_euclid(Second.per(Day) as _); let time = Time::__from_hms_nanos_unchecked( - (seconds_within_day / 3_600) as _, - ((seconds_within_day % 3_600) / 60) as _, - (seconds_within_day % 60) as _, + (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, ); @@ -279,9 +282,10 @@ impl<O: MaybeOffset> DateTime<O> { where O: HasLogicalOffset, { - let datetime = const_try!(Self::from_unix_timestamp( - div_floor!(timestamp, 1_000_000_000) as i64 - )); + let datetime = const_try!(Self::from_unix_timestamp(div_floor!( + timestamp, + Nanosecond.per(Second) as i128 + ) as i64)); Ok(Self { date: datetime.date, @@ -289,7 +293,7 @@ impl<O: MaybeOffset> DateTime<O> { datetime.hour(), datetime.minute(), datetime.second(), - timestamp.rem_euclid(1_000_000_000) as u32, + timestamp.rem_euclid(Nanosecond.per(Second) as _) as u32, ), offset: maybe_offset_from_offset::<O>(UtcOffset::UTC), }) @@ -450,9 +454,10 @@ 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) * 86_400; - let hours = self.hour() as i64 * 3_600; - let minutes = self.minute() as i64 * 60; + 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; let seconds = self.second() as i64; days + hours + minutes + seconds - offset } @@ -461,7 +466,7 @@ impl<O: MaybeOffset> DateTime<O> { where O: HasLogicalOffset, { - self.unix_timestamp() as i128 * 1_000_000_000 + self.nanosecond() as i128 + self.unix_timestamp() as i128 * Nanosecond.per(Second) as i128 + self.nanosecond() as i128 } // endregion unix timestamp getters // endregion: getters @@ -491,39 +496,49 @@ impl<O: MaybeOffset> DateTime<O> { where O: HasLogicalOffset, { + expect_opt!( + self.checked_to_offset(offset), + "local datetime out of valid range" + ) + } + + pub const fn checked_to_offset(self, offset: UtcOffset) -> Option<DateTime<offset_kind::Fixed>> + where + O: HasLogicalOffset, + { let self_offset = maybe_offset_as_offset::<O>(self.offset); if self_offset.whole_hours() == offset.whole_hours() && self_offset.minutes_past_hour() == offset.minutes_past_hour() && self_offset.seconds_past_minute() == offset.seconds_past_minute() { - return DateTime { + return Some(DateTime { date: self.date, time: self.time, offset, - }; + }); } let (year, ordinal, time) = self.to_offset_raw(offset); if year > MAX_YEAR || year < MIN_YEAR { - panic!("local datetime out of valid range"); + return None; } - DateTime { + Some(DateTime { date: Date::__from_ordinal_date_unchecked(year, ordinal), time, offset, - } + }) } /// Equivalent to `.to_offset(UtcOffset::UTC)`, but returning the year, ordinal, and time. This /// avoids constructing an invalid [`Date`] if the new value is out of range. pub(crate) const fn to_offset_raw(self, offset: UtcOffset) -> (i32, u16, Time) { - guard!(let Some(from) = maybe_offset_as_offset_opt::<O>(self.offset) else { + let Some(from) = maybe_offset_as_offset_opt::<O>(self.offset) else { // No adjustment is needed because there is no offset. return (self.year(), self.ordinal(), self.time); - }); + }; let to = offset; // Fast path for when no conversion is necessary. @@ -543,12 +558,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..60 => minute); - cascade!(second in 0..60 => minute); - cascade!(minute in 0..60 => hour); - cascade!(minute in 0..60 => hour); - cascade!(hour in 0..24 => ordinal); - cascade!(hour in 0..24 => 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); @@ -807,7 +822,7 @@ impl<O: MaybeOffset> DateTime<O> { } let (year, ordinal, time) = self.to_offset_raw(UtcOffset::UTC); - guard!(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 @@ -823,6 +838,7 @@ impl<O: MaybeOffset> DateTime<O> { // `OffsetDateTime` is made an alias of `DateTime<Fixed>`. Consider hiding these methods from // documentation in the future. + #[doc(hidden)] #[allow(dead_code)] // while functionally private #[deprecated(since = "0.3.18", note = "use `as_hms` instead")] pub const fn to_hms(self) -> (u8, u8, u8) @@ -832,6 +848,7 @@ impl<O: MaybeOffset> DateTime<O> { self.time.as_hms() } + #[doc(hidden)] #[allow(dead_code)] // while functionally private #[deprecated(since = "0.3.18", note = "use `as_hms_milli` instead")] pub const fn to_hms_milli(self) -> (u8, u8, u8, u16) @@ -841,6 +858,7 @@ impl<O: MaybeOffset> DateTime<O> { self.time.as_hms_milli() } + #[doc(hidden)] #[allow(dead_code)] // while functionally private #[deprecated(since = "0.3.18", note = "use `as_hms_micro` instead")] pub const fn to_hms_micro(self) -> (u8, u8, u8, u32) @@ -850,6 +868,7 @@ impl<O: MaybeOffset> DateTime<O> { self.time.as_hms_micro() } + #[doc(hidden)] #[allow(dead_code)] // while functionally private #[deprecated(since = "0.3.18", note = "use `as_hms_nano` instead")] pub const fn to_hms_nano(self) -> (u8, u8, u8, u32) @@ -1137,7 +1156,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() * 1_000_000.0) 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") } @@ -1151,7 +1170,8 @@ impl From<js_sys::Date> for DateTime<offset_kind::Fixed> { 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() / 1_000_000) as f64; + let timestamp = + (datetime.unix_timestamp_nanos() / Nanosecond.per(Millisecond) as i128) as f64; js_sys::Date::new(×tamp.into()) } } diff --git a/vendor/time/src/duration.rs b/vendor/time/src/duration.rs index 47c3f1516..453d2254d 100644 --- a/vendor/time/src/duration.rs +++ b/vendor/time/src/duration.rs @@ -6,6 +6,7 @@ use core::iter::Sum; use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign}; use core::time::Duration as StdDuration; +use crate::convert::*; use crate::error; #[cfg(feature = "std")] use crate::Instant; @@ -50,6 +51,124 @@ impl fmt::Debug for Duration { } } +/// This is adapted from the `std` implementation, 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. +#[rustfmt::skip] // Skip `rustfmt` because it reformats the arguments of the macro weirdly. +macro_rules! try_from_secs { + ( + secs = $secs: expr, + mantissa_bits = $mant_bits: literal, + exponent_bits = $exp_bits: literal, + offset = $offset: literal, + bits_ty = $bits_ty:ty, + bits_ty_signed = $bits_ty_signed:ty, + double_ty = $double_ty:ty, + float_ty = $float_ty:ty, + is_nan = $is_nan:expr, + is_overflow = $is_overflow:expr, + ) => {{ + 'value: { + const MIN_EXP: i16 = 1 - (1i16 << $exp_bits) / 2; + const MANT_MASK: $bits_ty = (1 << $mant_bits) - 1; + const EXP_MASK: $bits_ty = (1 << $exp_bits) - 1; + + // Change from std: No error check for negative values necessary. + + let bits = $secs.to_bits(); + let mant = (bits & MANT_MASK) | (MANT_MASK + 1); + let exp = ((bits >> $mant_bits) & EXP_MASK) as i16 + MIN_EXP; + + let (secs, nanos) = if exp < -31 { + // the input represents less than 1ns and can not be rounded to it + (0u64, 0u32) + } else if exp < 0 { + // 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 = (nanos_tmp >> nanos_offset) as u32; + + let rem_mask = (1 << nanos_offset) - 1; + let rem_msb_mask = 1 << (nanos_offset - 1); + let rem = nanos_tmp & rem_mask; + let is_tie = rem == rem_msb_mask; + let is_even = (nanos & 1) == 0; + let rem_msb = nanos_tmp & rem_msb_mask == 0; + let add_ns = !(rem_msb || (is_even && is_tie)); + + // 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)) { + (0, nanos) + } else { + (1, 0) + } + } else if exp < $mant_bits { + 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 = (nanos_tmp >> nanos_offset) as u32; + + let rem_mask = (1 << nanos_offset) - 1; + let rem_msb_mask = 1 << (nanos_offset - 1); + let rem = nanos_tmp & rem_mask; + let is_tie = rem == rem_msb_mask; + let is_even = (nanos & 1) == 0; + let rem_msb = nanos_tmp & rem_msb_mask == 0; + let add_ns = !(rem_msb || (is_even && is_tie)); + + // f32 does not have enough precision to trigger the second branch. + // For example, it can not represent numbers between 1.999_999_880... + // 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)) { + (secs, nanos) + } else { + (secs + 1, 0) + } + } else if exp < 63 { + // Change from std: The exponent here is 63 instead of 64, + // because i64::MAX + 1 is 2^63. + + // the input has no fractional part + let secs = u64::from(mant) << (exp - $mant_bits); + (secs, 0) + } else if bits == (i64::MIN as $float_ty).to_bits() { + // Change from std: Signed integers are asymmetrical in that + // iN::MIN is -iN::MAX - 1. So for example i8 covers the + // 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); + } else if $secs.is_nan() { + // Change from std: std doesn't differentiate between the error + // cases. + $is_nan + } else { + $is_overflow + }; + + // Change from std: All the code is mostly unmodified in that it + // simply calculates an unsigned integer. Here we extract the sign + // bit and assign it to the number. We basically manually do two's + // complement here, we could also use an if and just negate the + // numbers based on the sign, but it turns out to be quite a bit + // slower. + let mask = (bits as $bits_ty_signed) >> ($mant_bits + $exp_bits); + #[allow(trivial_numeric_casts)] + 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) + } + }}; +} + impl Duration { // region: constants /// Equivalent to `0.seconds()`. @@ -125,10 +244,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, -999_999_999); + pub const MIN: Self = Self::new_unchecked(i64::MIN, -((Nanosecond.per(Second) - 1) as i32)); /// The maximum possible duration. Adding any positive duration to this will cause an overflow. - pub const MAX: Self = Self::new_unchecked(i64::MAX, 999_999_999); + pub const MAX: Self = Self::new_unchecked(i64::MAX, (Nanosecond.per(Second) - 1) as _); // endregion constants // region: is_{sign} @@ -202,12 +321,12 @@ impl Duration { pub(crate) const fn new_unchecked(seconds: i64, nanoseconds: i32) -> Self { if seconds < 0 { debug_assert!(nanoseconds <= 0); - debug_assert!(nanoseconds > -1_000_000_000); + debug_assert!(nanoseconds > -(Nanosecond.per(Second) as i32)); } else if seconds > 0 { debug_assert!(nanoseconds >= 0); - debug_assert!(nanoseconds < 1_000_000_000); + debug_assert!(nanoseconds < Nanosecond.per(Second) as _); } else { - debug_assert!(nanoseconds.unsigned_abs() < 1_000_000_000); + debug_assert!(nanoseconds.unsigned_abs() < Nanosecond.per(Second)); } Self { @@ -228,19 +347,19 @@ impl Duration { /// ``` pub const fn new(mut seconds: i64, mut nanoseconds: i32) -> Self { seconds = expect_opt!( - seconds.checked_add(nanoseconds as i64 / 1_000_000_000), + seconds.checked_add(nanoseconds as i64 / Nanosecond.per(Second) as i64), "overflow constructing `time::Duration`" ); - nanoseconds %= 1_000_000_000; + nanoseconds %= Nanosecond.per(Second) as i32; if seconds > 0 && nanoseconds < 0 { // `seconds` cannot overflow here because it is positive. seconds -= 1; - nanoseconds += 1_000_000_000; + nanoseconds += Nanosecond.per(Second) as i32; } else if seconds < 0 && nanoseconds > 0 { // `seconds` cannot overflow here because it is negative. seconds += 1; - nanoseconds -= 1_000_000_000; + nanoseconds -= Nanosecond.per(Second) as i32; } Self::new_unchecked(seconds, nanoseconds) @@ -255,7 +374,7 @@ impl Duration { /// ``` pub const fn weeks(weeks: i64) -> Self { Self::seconds(expect_opt!( - weeks.checked_mul(604_800), + weeks.checked_mul(Second.per(Week) as _), "overflow constructing `time::Duration`" )) } @@ -269,7 +388,7 @@ impl Duration { /// ``` pub const fn days(days: i64) -> Self { Self::seconds(expect_opt!( - days.checked_mul(86_400), + days.checked_mul(Second.per(Day) as _), "overflow constructing `time::Duration`" )) } @@ -283,7 +402,7 @@ impl Duration { /// ``` pub const fn hours(hours: i64) -> Self { Self::seconds(expect_opt!( - hours.checked_mul(3_600), + hours.checked_mul(Second.per(Hour) as _), "overflow constructing `time::Duration`" )) } @@ -297,7 +416,7 @@ impl Duration { /// ``` pub const fn minutes(minutes: i64) -> Self { Self::seconds(expect_opt!( - minutes.checked_mul(60), + minutes.checked_mul(Second.per(Minute) as _), "overflow constructing `time::Duration`" )) } @@ -320,16 +439,18 @@ impl Duration { /// assert_eq!(Duration::seconds_f64(-0.5), -0.5.seconds()); /// ``` pub fn seconds_f64(seconds: f64) -> Self { - if seconds > i64::MAX as f64 || seconds < i64::MIN as f64 { - crate::expect_failed("overflow constructing `time::Duration`"); - } - if seconds.is_nan() { - crate::expect_failed("passed NaN to `time::Duration::seconds_f64`"); - } - let seconds_truncated = seconds as i64; - // This only works because we handle the overflow condition above. - let nanoseconds = ((seconds - seconds_truncated as f64) * 1_000_000_000.) as i32; - Self::new_unchecked(seconds_truncated, nanoseconds) + try_from_secs!( + secs = seconds, + mantissa_bits = 52, + exponent_bits = 11, + offset = 44, + bits_ty = u64, + bits_ty_signed = i64, + double_ty = u128, + float_ty = f64, + is_nan = crate::expect_failed("passed NaN to `time::Duration::seconds_f64`"), + is_overflow = crate::expect_failed("overflow constructing `time::Duration`"), + ) } /// Creates a new `Duration` from the specified number of seconds represented as `f32`. @@ -340,16 +461,146 @@ impl Duration { /// assert_eq!(Duration::seconds_f32(-0.5), (-0.5).seconds()); /// ``` pub fn seconds_f32(seconds: f32) -> Self { - if seconds > i64::MAX as f32 || seconds < i64::MIN as f32 { - crate::expect_failed("overflow constructing `time::Duration`"); - } - if seconds.is_nan() { - crate::expect_failed("passed NaN to `time::Duration::seconds_f32`"); - } - let seconds_truncated = seconds as i64; - // This only works because we handle the overflow condition above. - let nanoseconds = ((seconds - seconds_truncated as f32) * 1_000_000_000.) as i32; - Self::new_unchecked(seconds_truncated, nanoseconds) + try_from_secs!( + secs = seconds, + mantissa_bits = 23, + exponent_bits = 8, + offset = 41, + bits_ty = u32, + bits_ty_signed = i32, + double_ty = u64, + float_ty = f32, + is_nan = crate::expect_failed("passed NaN to `time::Duration::seconds_f32`"), + is_overflow = crate::expect_failed("overflow constructing `time::Duration`"), + ) + } + + /// Creates a new `Duration` from the specified number of seconds + /// represented as `f64`. Any values that are out of bounds are saturated at + /// the minimum or maximum respectively. `NaN` gets turned into a `Duration` + /// of 0 seconds. + /// + /// ```rust + /// # use time::{Duration, ext::NumericalDuration}; + /// assert_eq!(Duration::saturating_seconds_f64(0.5), 0.5.seconds()); + /// assert_eq!(Duration::saturating_seconds_f64(-0.5), -0.5.seconds()); + /// assert_eq!( + /// Duration::saturating_seconds_f64(f64::NAN), + /// Duration::new(0, 0), + /// ); + /// assert_eq!( + /// Duration::saturating_seconds_f64(f64::NEG_INFINITY), + /// Duration::MIN, + /// ); + /// assert_eq!( + /// Duration::saturating_seconds_f64(f64::INFINITY), + /// Duration::MAX, + /// ); + /// ``` + pub fn saturating_seconds_f64(seconds: f64) -> Self { + try_from_secs!( + secs = seconds, + mantissa_bits = 52, + exponent_bits = 11, + offset = 44, + bits_ty = u64, + bits_ty_signed = i64, + double_ty = u128, + float_ty = f64, + is_nan = return Self::ZERO, + is_overflow = return if seconds < 0.0 { Self::MIN } else { Self::MAX }, + ) + } + + /// Creates a new `Duration` from the specified number of seconds + /// represented as `f32`. Any values that are out of bounds are saturated at + /// the minimum or maximum respectively. `NaN` gets turned into a `Duration` + /// of 0 seconds. + /// + /// ```rust + /// # use time::{Duration, ext::NumericalDuration}; + /// assert_eq!(Duration::saturating_seconds_f32(0.5), 0.5.seconds()); + /// assert_eq!(Duration::saturating_seconds_f32(-0.5), (-0.5).seconds()); + /// assert_eq!( + /// Duration::saturating_seconds_f32(f32::NAN), + /// Duration::new(0, 0), + /// ); + /// assert_eq!( + /// Duration::saturating_seconds_f32(f32::NEG_INFINITY), + /// Duration::MIN, + /// ); + /// assert_eq!( + /// Duration::saturating_seconds_f32(f32::INFINITY), + /// Duration::MAX, + /// ); + /// ``` + pub fn saturating_seconds_f32(seconds: f32) -> Self { + try_from_secs!( + secs = seconds, + mantissa_bits = 23, + exponent_bits = 8, + offset = 41, + bits_ty = u32, + bits_ty_signed = i32, + double_ty = u64, + float_ty = f32, + is_nan = return Self::ZERO, + is_overflow = return if seconds < 0.0 { Self::MIN } else { Self::MAX }, + ) + } + + /// Creates a new `Duration` from the specified number of seconds + /// represented as `f64`. Returns `None` if the `Duration` can't be + /// represented. + /// + /// ```rust + /// # use time::{Duration, ext::NumericalDuration}; + /// assert_eq!(Duration::checked_seconds_f64(0.5), Some(0.5.seconds())); + /// assert_eq!(Duration::checked_seconds_f64(-0.5), Some(-0.5.seconds())); + /// assert_eq!(Duration::checked_seconds_f64(f64::NAN), None); + /// assert_eq!(Duration::checked_seconds_f64(f64::NEG_INFINITY), None); + /// assert_eq!(Duration::checked_seconds_f64(f64::INFINITY), None); + /// ``` + pub fn checked_seconds_f64(seconds: f64) -> Option<Self> { + Some(try_from_secs!( + secs = seconds, + mantissa_bits = 52, + exponent_bits = 11, + offset = 44, + bits_ty = u64, + bits_ty_signed = i64, + double_ty = u128, + float_ty = f64, + is_nan = return None, + is_overflow = return None, + )) + } + + /// Creates a new `Duration` from the specified number of seconds + /// represented as `f32`. Returns `None` if the `Duration` can't be + /// represented. + /// + /// ```rust + /// # use time::{Duration, ext::NumericalDuration}; + /// assert_eq!(Duration::checked_seconds_f32(0.5), Some(0.5.seconds())); + /// assert_eq!(Duration::checked_seconds_f32(-0.5), Some(-0.5.seconds())); + /// assert_eq!(Duration::checked_seconds_f32(f32::NAN), None); + /// assert_eq!(Duration::checked_seconds_f32(f32::NEG_INFINITY), None); + /// assert_eq!(Duration::checked_seconds_f32(f32::INFINITY), None); + /// ``` + pub fn checked_seconds_f32(seconds: f32) -> Option<Self> { + Some(try_from_secs!( + secs = seconds, + mantissa_bits = 23, + exponent_bits = 8, + offset = 41, + bits_ty = u32, + bits_ty_signed = i32, + double_ty = u64, + float_ty = f32, + is_nan = return None, + is_overflow = return None, + )) } /// Create a new `Duration` with the given number of milliseconds. @@ -361,8 +612,9 @@ impl Duration { /// ``` pub const fn milliseconds(milliseconds: i64) -> Self { Self::new_unchecked( - milliseconds / 1_000, - ((milliseconds % 1_000) * 1_000_000) as _, + milliseconds / Millisecond.per(Second) as i64, + (milliseconds % Millisecond.per(Second) as i64 * Nanosecond.per(Millisecond) as i64) + as _, ) } @@ -375,8 +627,9 @@ impl Duration { /// ``` pub const fn microseconds(microseconds: i64) -> Self { Self::new_unchecked( - microseconds / 1_000_000, - ((microseconds % 1_000_000) * 1_000) as _, + microseconds / Microsecond.per(Second) as i64, + (microseconds % Microsecond.per(Second) as i64 * Nanosecond.per(Microsecond) as i64) + as _, ) } @@ -389,8 +642,8 @@ impl Duration { /// ``` pub const fn nanoseconds(nanoseconds: i64) -> Self { Self::new_unchecked( - nanoseconds / 1_000_000_000, - (nanoseconds % 1_000_000_000) as _, + nanoseconds / Nanosecond.per(Second) as i64, + (nanoseconds % Nanosecond.per(Second) as i64) as _, ) } @@ -399,8 +652,8 @@ 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 / 1_000_000_000; - let nanoseconds = nanoseconds % 1_000_000_000; + 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`"); @@ -421,7 +674,7 @@ impl Duration { /// assert_eq!((-6).days().whole_weeks(), 0); /// ``` pub const fn whole_weeks(self) -> i64 { - self.whole_seconds() / 604_800 + self.whole_seconds() / Second.per(Week) as i64 } /// Get the number of whole days in the duration. @@ -434,7 +687,7 @@ impl Duration { /// assert_eq!((-23).hours().whole_days(), 0); /// ``` pub const fn whole_days(self) -> i64 { - self.whole_seconds() / 86_400 + self.whole_seconds() / Second.per(Day) as i64 } /// Get the number of whole hours in the duration. @@ -447,7 +700,7 @@ impl Duration { /// assert_eq!((-59).minutes().whole_hours(), 0); /// ``` pub const fn whole_hours(self) -> i64 { - self.whole_seconds() / 3_600 + self.whole_seconds() / Second.per(Hour) as i64 } /// Get the number of whole minutes in the duration. @@ -460,7 +713,7 @@ impl Duration { /// assert_eq!((-59).seconds().whole_minutes(), 0); /// ``` pub const fn whole_minutes(self) -> i64 { - self.whole_seconds() / 60 + self.whole_seconds() / Second.per(Minute) as i64 } /// Get the number of whole seconds in the duration. @@ -484,7 +737,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 / 1_000_000_000. + self.seconds as f64 + self.nanoseconds as f64 / Nanosecond.per(Second) as f64 } /// Get the number of fractional seconds in the duration. @@ -495,7 +748,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 / 1_000_000_000. + self.seconds as f32 + self.nanoseconds as f32 / Nanosecond.per(Second) as f32 } /// Get the number of whole milliseconds in the duration. @@ -508,7 +761,8 @@ impl Duration { /// assert_eq!((-1).milliseconds().whole_milliseconds(), -1); /// ``` pub const fn whole_milliseconds(self) -> i128 { - self.seconds as i128 * 1_000 + self.nanoseconds as i128 / 1_000_000 + self.seconds as i128 * Millisecond.per(Second) as i128 + + self.nanoseconds as i128 / Nanosecond.per(Millisecond) as i128 } /// Get the number of milliseconds past the number of whole seconds. @@ -522,7 +776,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 / 1_000_000) as _ + (self.nanoseconds / Nanosecond.per(Millisecond) as i32) as _ } /// Get the number of whole microseconds in the duration. @@ -535,7 +789,8 @@ impl Duration { /// assert_eq!((-1).microseconds().whole_microseconds(), -1); /// ``` pub const fn whole_microseconds(self) -> i128 { - self.seconds as i128 * 1_000_000 + self.nanoseconds as i128 / 1_000 + self.seconds as i128 * Microsecond.per(Second) as i128 + + self.nanoseconds as i128 / Nanosecond.per(Microsecond) as i128 } /// Get the number of microseconds past the number of whole seconds. @@ -548,7 +803,7 @@ impl Duration { /// assert_eq!((-1.0004).seconds().subsec_microseconds(), -400); /// ``` pub const fn subsec_microseconds(self) -> i32 { - self.nanoseconds / 1_000 + self.nanoseconds / Nanosecond.per(Microsecond) as i32 } /// Get the number of nanoseconds in the duration. @@ -561,7 +816,7 @@ impl Duration { /// assert_eq!((-1).nanoseconds().whole_nanoseconds(), -1); /// ``` pub const fn whole_nanoseconds(self) -> i128 { - self.seconds as i128 * 1_000_000_000 + self.nanoseconds as i128 + self.seconds as i128 * Nanosecond.per(Second) as i128 + self.nanoseconds as i128 } /// Get the number of nanoseconds past the number of whole seconds. @@ -591,11 +846,12 @@ impl Duration { let mut seconds = const_try_opt!(self.seconds.checked_add(rhs.seconds)); let mut nanoseconds = self.nanoseconds + rhs.nanoseconds; - if nanoseconds >= 1_000_000_000 || seconds < 0 && nanoseconds > 0 { - nanoseconds -= 1_000_000_000; + 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 <= -1_000_000_000 || seconds > 0 && nanoseconds < 0 { - nanoseconds += 1_000_000_000; + } else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0 + { + nanoseconds += Nanosecond.per(Second) as i32; seconds = const_try_opt!(seconds.checked_sub(1)); } @@ -614,11 +870,12 @@ impl Duration { let mut seconds = const_try_opt!(self.seconds.checked_sub(rhs.seconds)); let mut nanoseconds = self.nanoseconds - rhs.nanoseconds; - if nanoseconds >= 1_000_000_000 || seconds < 0 && nanoseconds > 0 { - nanoseconds -= 1_000_000_000; + 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 <= -1_000_000_000 || seconds > 0 && nanoseconds < 0 { - nanoseconds += 1_000_000_000; + } else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0 + { + nanoseconds += Nanosecond.per(Second) as i32; seconds = const_try_opt!(seconds.checked_sub(1)); } @@ -638,8 +895,8 @@ 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 / 1_000_000_000; - let nanoseconds = (total_nanos % 1_000_000_000) as _; + 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) ); @@ -658,7 +915,8 @@ impl Duration { 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 * 1_000_000_000).checked_div(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); Some(Self::new_unchecked(seconds, nanoseconds)) @@ -688,14 +946,15 @@ impl Duration { } let mut nanoseconds = self.nanoseconds + rhs.nanoseconds; - if nanoseconds >= 1_000_000_000 || seconds < 0 && nanoseconds > 0 { - nanoseconds -= 1_000_000_000; + 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 <= -1_000_000_000 || seconds > 0 && nanoseconds < 0 { - nanoseconds += 1_000_000_000; + } else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0 + { + nanoseconds += Nanosecond.per(Second) as i32; seconds = match seconds.checked_sub(1) { Some(seconds) => seconds, None => return Self::MIN, @@ -727,14 +986,15 @@ impl Duration { } let mut nanoseconds = self.nanoseconds - rhs.nanoseconds; - if nanoseconds >= 1_000_000_000 || seconds < 0 && nanoseconds > 0 { - nanoseconds -= 1_000_000_000; + 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 <= -1_000_000_000 || seconds > 0 && nanoseconds < 0 { - nanoseconds += 1_000_000_000; + } else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0 + { + nanoseconds += Nanosecond.per(Second) as i32; seconds = match seconds.checked_sub(1) { Some(seconds) => seconds, None => return Self::MIN, @@ -759,8 +1019,8 @@ 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 / 1_000_000_000; - let nanoseconds = (total_nanos % 1_000_000_000) as _; + 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 { @@ -834,13 +1094,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 / 86_400.); - item!("h", seconds / 3_600.); - item!("m", seconds / 60.); + 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 * 1_000.); - item!("µs", seconds * 1_000_000.); - item!("ns", seconds * 1_000_000_000.); + 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. @@ -861,13 +1121,23 @@ impl fmt::Display for Duration { let seconds = self.seconds.unsigned_abs(); let nanoseconds = self.nanoseconds.unsigned_abs(); - item!("d", seconds / 86_400)?; - item!("h", seconds / 3_600 % 24)?; - item!("m", seconds / 60 % 60)?; - item!("s", seconds % 60)?; - item!("ms", nanoseconds / 1_000_000)?; - item!("µs", nanoseconds / 1_000 % 1_000)?; - item!("ns", nanoseconds % 1_000)?; + item!("d", seconds / Second.per(Day) as u64)?; + item!( + "h", + seconds / Second.per(Hour) as u64 % Hour.per(Day) as u64 + )?; + item!( + "m", + 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", + nanoseconds / Nanosecond.per(Microsecond) as u32 + % Microsecond.per(Millisecond) as u32 + )?; + item!("ns", nanoseconds % Nanosecond.per(Microsecond) as u32)?; } Ok(()) diff --git a/vendor/time/src/ext.rs b/vendor/time/src/ext.rs index 5a1393d86..8b7759d8e 100644 --- a/vendor/time/src/ext.rs +++ b/vendor/time/src/ext.rs @@ -2,6 +2,7 @@ use core::time::Duration as StdDuration; +use crate::convert::*; use crate::Duration; /// Sealed trait to prevent downstream implementations. @@ -116,31 +117,31 @@ impl NumericalDuration for f64 { } fn microseconds(self) -> Duration { - Duration::nanoseconds((self * 1_000.) as _) + Duration::nanoseconds((self * Nanosecond.per(Microsecond) as Self) as _) } fn milliseconds(self) -> Duration { - Duration::nanoseconds((self * 1_000_000.) as _) + Duration::nanoseconds((self * Nanosecond.per(Millisecond) as Self) as _) } fn seconds(self) -> Duration { - Duration::nanoseconds((self * 1_000_000_000.) as _) + Duration::nanoseconds((self * Nanosecond.per(Second) as Self) as _) } fn minutes(self) -> Duration { - Duration::nanoseconds((self * 60_000_000_000.) as _) + Duration::nanoseconds((self * Nanosecond.per(Minute) as Self) as _) } fn hours(self) -> Duration { - Duration::nanoseconds((self * 3_600_000_000_000.) as _) + Duration::nanoseconds((self * Nanosecond.per(Hour) as Self) as _) } fn days(self) -> Duration { - Duration::nanoseconds((self * 86_400_000_000_000.) as _) + Duration::nanoseconds((self * Nanosecond.per(Day) as Self) as _) } fn weeks(self) -> Duration { - Duration::nanoseconds((self * 604_800_000_000_000.) as _) + Duration::nanoseconds((self * Nanosecond.per(Week) as Self) as _) } } // endregion NumericalDuration @@ -219,19 +220,19 @@ impl NumericalStdDuration for u64 { } fn std_minutes(self) -> StdDuration { - StdDuration::from_secs(self * 60) + StdDuration::from_secs(self * Second.per(Minute) as Self) } fn std_hours(self) -> StdDuration { - StdDuration::from_secs(self * 3_600) + StdDuration::from_secs(self * Second.per(Hour) as Self) } fn std_days(self) -> StdDuration { - StdDuration::from_secs(self * 86_400) + StdDuration::from_secs(self * Second.per(Day) as Self) } fn std_weeks(self) -> StdDuration { - StdDuration::from_secs(self * 604_800) + StdDuration::from_secs(self * Second.per(Week) as Self) } } @@ -243,37 +244,37 @@ impl NumericalStdDuration for f64 { fn std_microseconds(self) -> StdDuration { assert!(self >= 0.); - StdDuration::from_nanos((self * 1_000.) as _) + StdDuration::from_nanos((self * Nanosecond.per(Microsecond) as Self) as _) } fn std_milliseconds(self) -> StdDuration { assert!(self >= 0.); - StdDuration::from_nanos((self * 1_000_000.) as _) + StdDuration::from_nanos((self * Nanosecond.per(Millisecond) as Self) as _) } fn std_seconds(self) -> StdDuration { assert!(self >= 0.); - StdDuration::from_nanos((self * 1_000_000_000.) as _) + StdDuration::from_nanos((self * Nanosecond.per(Second) as Self) as _) } fn std_minutes(self) -> StdDuration { assert!(self >= 0.); - StdDuration::from_nanos((self * 60_000_000_000.) as _) + StdDuration::from_nanos((self * Nanosecond.per(Minute) as Self) as _) } fn std_hours(self) -> StdDuration { assert!(self >= 0.); - StdDuration::from_nanos((self * 3_600_000_000_000.) as _) + StdDuration::from_nanos((self * Nanosecond.per(Hour) as Self) as _) } fn std_days(self) -> StdDuration { assert!(self >= 0.); - StdDuration::from_nanos((self * 86_400_000_000_000.) as _) + StdDuration::from_nanos((self * Nanosecond.per(Day) as Self) as _) } fn std_weeks(self) -> StdDuration { assert!(self >= 0.); - StdDuration::from_nanos((self * 604_800_000_000_000.) as _) + StdDuration::from_nanos((self * Nanosecond.per(Week) as Self) as _) } } // endregion NumericalStdDuration diff --git a/vendor/time/src/format_description/mod.rs b/vendor/time/src/format_description/mod.rs index 4d328f675..befae8b56 100644 --- a/vendor/time/src/format_description/mod.rs +++ b/vendor/time/src/format_description/mod.rs @@ -3,6 +3,9 @@ //! The formatted value will be output to the provided writer. Format descriptions can be //! [well-known](crate::format_description::well_known) or obtained by using the //! [`format_description!`](crate::macros::format_description) macro or a function listed below. +//! +//! For examples, see the implementors of [Formattable](crate::formatting::Formattable), +//! e.g. [`well_known::Rfc3339`]. mod borrowed_format_item; mod component; diff --git a/vendor/time/src/format_description/parse/ast.rs b/vendor/time/src/format_description/parse/ast.rs index f7b0ab78c..12fc5d55d 100644 --- a/vendor/time/src/format_description/parse/ast.rs +++ b/vendor/time/src/format_description/parse/ast.rs @@ -184,7 +184,7 @@ fn parse_component< validate_version!(VERSION); let leading_whitespace = tokens.next_if_whitespace(); - guard!(let Some(name) = tokens.next_if_not_whitespace() else { + let Some(name) = tokens.next_if_not_whitespace() else { let span = match leading_whitespace { Some(Spanned { value: _, span }) => span, None => opening_bracket.to(opening_bracket), @@ -195,10 +195,10 @@ fn parse_component< index: span.start.byte as _, }, }); - }); + }; if *name == b"optional" { - guard!(let Some(whitespace) = tokens.next_if_whitespace() else { + let Some(whitespace) = tokens.next_if_whitespace() else { return Err(Error { _inner: unused(name.span.error("expected whitespace after `optional`")), public: crate::error::InvalidFormatDescription::Expected { @@ -206,18 +206,18 @@ fn parse_component< index: name.span.end.byte as _, }, }); - }); + }; let nested = parse_nested::<_, VERSION>(whitespace.span.end, tokens)?; - guard!(let Some(closing_bracket) = tokens.next_if_closing_bracket() else { + let Some(closing_bracket) = tokens.next_if_closing_bracket() else { return Err(Error { _inner: unused(opening_bracket.error("unclosed bracket")), public: crate::error::InvalidFormatDescription::UnclosedOpeningBracket { index: opening_bracket.byte as _, }, }); - }); + }; return Ok(Item::Optional { opening_bracket, @@ -230,7 +230,7 @@ fn parse_component< } if *name == b"first" { - guard!(let Some(whitespace) = tokens.next_if_whitespace() else { + let Some(whitespace) = tokens.next_if_whitespace() else { return Err(Error { _inner: unused(name.span.error("expected whitespace after `first`")), public: crate::error::InvalidFormatDescription::Expected { @@ -238,21 +238,21 @@ fn parse_component< index: name.span.end.byte as _, }, }); - }); + }; let mut nested_format_descriptions = Vec::new(); while let Ok(description) = parse_nested::<_, VERSION>(whitespace.span.end, tokens) { nested_format_descriptions.push(description); } - guard!(let Some(closing_bracket) = tokens.next_if_closing_bracket() else { + let Some(closing_bracket) = tokens.next_if_closing_bracket() else { return Err(Error { _inner: unused(opening_bracket.error("unclosed bracket")), public: crate::error::InvalidFormatDescription::UnclosedOpeningBracket { index: opening_bracket.byte as _, }, }); - }); + }; return Ok(Item::First { opening_bracket, @@ -266,7 +266,7 @@ fn parse_component< let mut modifiers = Vec::new(); let trailing_whitespace = loop { - guard!(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. @@ -284,11 +284,11 @@ fn parse_component< }); } - guard!(let Some(Spanned { value, span }) = tokens.next_if_not_whitespace() else { + let Some(Spanned { value, span }) = tokens.next_if_not_whitespace() else { break Some(whitespace); - }); + }; - guard!(let Some(colon_index) = value.iter().position(|&b| b == b':') else { + let Some(colon_index) = value.iter().position(|&b| b == b':') else { return Err(Error { _inner: unused(span.error("modifier must be of the form `key:value`")), public: crate::error::InvalidFormatDescription::InvalidModifier { @@ -296,7 +296,7 @@ fn parse_component< index: span.start.byte as _, }, }); - }); + }; let key = &value[..colon_index]; let value = &value[colon_index + 1..]; @@ -327,14 +327,14 @@ fn parse_component< }); }; - guard!(let Some(closing_bracket) = tokens.next_if_closing_bracket() else { + let Some(closing_bracket) = tokens.next_if_closing_bracket() else { return Err(Error { _inner: unused(opening_bracket.error("unclosed bracket")), public: crate::error::InvalidFormatDescription::UnclosedOpeningBracket { index: opening_bracket.byte as _, }, }); - }); + }; Ok(Item::Component { _opening_bracket: unused(opening_bracket), @@ -352,7 +352,7 @@ fn parse_nested<'a, I: Iterator<Item = Result<lexer::Token<'a>, Error>>, const V tokens: &mut lexer::Lexed<I>, ) -> Result<NestedFormatDescription<'a>, Error> { validate_version!(VERSION); - guard!(let Some(opening_bracket) = tokens.next_if_opening_bracket() else { + let Some(opening_bracket) = tokens.next_if_opening_bracket() else { return Err(Error { _inner: unused(last_location.error("expected opening bracket")), public: crate::error::InvalidFormatDescription::Expected { @@ -360,16 +360,16 @@ fn parse_nested<'a, I: Iterator<Item = Result<lexer::Token<'a>, Error>>, const V index: last_location.byte as _, }, }); - }); + }; let items = parse_inner::<_, true, VERSION>(tokens).collect::<Result<_, _>>()?; - guard!(let Some(closing_bracket) = tokens.next_if_closing_bracket() else { + let Some(closing_bracket) = tokens.next_if_closing_bracket() else { return Err(Error { _inner: unused(opening_bracket.error("unclosed bracket")), public: crate::error::InvalidFormatDescription::UnclosedOpeningBracket { index: opening_bracket.byte as _, }, }); - }); + }; let trailing_whitespace = tokens.next_if_whitespace(); Ok(NestedFormatDescription { 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 757a68b18..1fdecaf26 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 @@ -11,7 +11,7 @@ use super::{Config, DateKind, FormattedComponents as FC, OffsetPrecision, TimePr #[doc(hidden)] pub type DoNotRelyOnWhatThisIs = u128; -/// An encoded [`Config`] that can be used as a const parameter to [`Iso8601`]. +/// An encoded [`Config`] that can be used as a const parameter to [`Iso8601`](super::Iso8601). /// /// The type this is aliased to must not be relied upon. It can change in any release without /// notice. @@ -49,10 +49,11 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> { } impl Config { - /// Encode the configuration, permitting it to be used as a const parameter of [`Iso8601`]. + /// Encode the configuration, permitting it to be used as a const parameter of + /// [`Iso8601`](super::Iso8601). /// - /// The value returned by this method must only be used as a const parameter to [`Iso8601`]. Any - /// other usage is unspecified behavior. + /// The value returned by this method must only be used as a const parameter to + /// [`Iso8601`](super::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 2c0d7badf..2b4b35088 100644 --- a/vendor/time/src/formatting/formattable.rs +++ b/vendor/time/src/formatting/formattable.rs @@ -11,7 +11,12 @@ use crate::formatting::{ }; use crate::{error, Date, Time, UtcOffset}; -/// A type that can be formatted. +/// A type that describes a format. +/// +/// Implementors of [`Formattable`] are [format descriptions](crate::format_description). +/// +/// [`Date::format`] and [`Time::format`] each use a format description to generate +/// a String from their data. See the respective methods for usage examples. #[cfg_attr(__time_03_docs, doc(notable_trait))] pub trait Formattable: sealed::Sealed {} impl Formattable for FormatItem<'_> {} diff --git a/vendor/time/src/formatting/iso8601.rs b/vendor/time/src/formatting/iso8601.rs index 229a07ebc..29d443ef4 100644 --- a/vendor/time/src/formatting/iso8601.rs +++ b/vendor/time/src/formatting/iso8601.rs @@ -2,6 +2,7 @@ use std::io; +use crate::convert::*; use crate::format_description::well_known::iso8601::{ DateKind, EncodedConfig, OffsetPrecision, TimePrecision, }; @@ -84,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) / 60. - + (seconds as f64) / 3_600. - + (nanoseconds as f64) / 3_600. / 1_000_000_000.; + + (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) / 60. - + (nanoseconds as f64) / 60. / 1_000_000_000.; + + (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 } => { @@ -102,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) / 1_000_000_000.; + 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 1df4478a8..e5017063a 100644 --- a/vendor/time/src/formatting/mod.rs +++ b/vendor/time/src/formatting/mod.rs @@ -7,6 +7,7 @@ use core::num::NonZeroU8; use std::io; pub use self::formattable::Formattable; +use crate::convert::*; use crate::format_description::{modifier, Component}; use crate::{error, Date, OffsetDateTime, Time, UtcOffset}; @@ -531,11 +532,11 @@ fn fmt_unix_timestamp( } modifier::UnixTimestampPrecision::Millisecond => format_number_pad_none( output, - (date_time.unix_timestamp_nanos() / 1_000_000).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() / 1_000).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/lib.rs b/vendor/time/src/lib.rs index ed4042e03..2ab59cf8e 100644 --- a/vendor/time/src/lib.rs +++ b/vendor/time/src/lib.rs @@ -204,13 +204,15 @@ macro_rules! cascade { (@year year) => {}; // Cascade an out-of-bounds value from "from" to "to". - ($from:ident in $min:literal.. $max:literal => $to:tt) => { + ($from:ident in $min:literal.. $max:expr => $to:tt) => { #[allow(unused_comparisons, unused_assignments)] - if $from >= $max { - $from -= $max - $min; + let min = $min; + let max = $max; + if $from >= max { + $from -= max - min; $to += 1; - } else if $from < $min { - $from += $max - $min; + } else if $from < min { + $from += max - min; $to -= 1; } }; @@ -310,9 +312,6 @@ macro_rules! bug { } // endregion macros -#[macro_use] -mod shim; - mod date; mod date_time; mod duration; @@ -346,6 +345,9 @@ mod utc_offset; pub mod util; mod weekday; +// Not public yet. +use time_core::convert; + pub use crate::date::Date; use crate::date_time::DateTime; pub use crate::duration::Duration; diff --git a/vendor/time/src/offset_date_time.rs b/vendor/time/src/offset_date_time.rs index 1e342ca8e..d979174e1 100644 --- a/vendor/time/src/offset_date_time.rs +++ b/vendor/time/src/offset_date_time.rs @@ -97,6 +97,30 @@ impl OffsetDateTime { Self(self.0.to_offset(offset)) } + /// Convert the `OffsetDateTime` from the current [`UtcOffset`] to the provided [`UtcOffset`], + /// returning `None` if the date-time in the resulting offset is invalid. + /// + /// ```rust + /// # use time::PrimitiveDateTime; + /// # use time_macros::{datetime, offset}; + /// assert_eq!( + /// datetime!(2000-01-01 0:00 UTC) + /// .checked_to_offset(offset!(-1)) + /// .unwrap() + /// .year(), + /// 1999, + /// ); + /// assert_eq!( + /// PrimitiveDateTime::MAX + /// .assume_utc() + /// .checked_to_offset(offset!(+1)), + /// None, + /// ); + /// ``` + pub const fn checked_to_offset(self, offset: UtcOffset) -> Option<Self> { + Some(Self(const_try_opt!(self.0.checked_to_offset(offset)))) + } + // region: constructors /// Create an `OffsetDateTime` from the provided Unix timestamp. Calling `.offset()` on the /// resulting value is guaranteed to return UTC. diff --git a/vendor/time/src/parsing/component.rs b/vendor/time/src/parsing/component.rs index e7b852706..23035893e 100644 --- a/vendor/time/src/parsing/component.rs +++ b/vendor/time/src/parsing/component.rs @@ -2,6 +2,7 @@ use core::num::{NonZeroU16, NonZeroU8}; +use crate::convert::*; use crate::format_description::modifier; #[cfg(feature = "large-dates")] use crate::parsing::combinator::n_to_m_digits_padded; @@ -315,14 +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 * 1_000_000_000) - } - modifier::UnixTimestampPrecision::Millisecond => { - n_to_m_digits::<1, 17, u128>(input)?.map(|val| val * 1_000_000) - } - modifier::UnixTimestampPrecision::Microsecond => { - n_to_m_digits::<1, 20, u128>(input)?.map(|val| val * 1_000) + 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), + modifier::UnixTimestampPrecision::Microsecond => n_to_m_digits::<1, 20, u128>(input)? + .map(|val| val * Nanosecond.per(Microsecond) as u128), modifier::UnixTimestampPrecision::Nanosecond => n_to_m_digits::<1, 23, _>(input)?, }; diff --git a/vendor/time/src/parsing/iso8601.rs b/vendor/time/src/parsing/iso8601.rs index 21c89bab3..1afee4e31 100644 --- a/vendor/time/src/parsing/iso8601.rs +++ b/vendor/time/src/parsing/iso8601.rs @@ -1,5 +1,6 @@ //! Parse parts of an ISO 8601-formatted value. +use crate::convert::*; use crate::error; use crate::error::ParseFromDescription::{InvalidComponent, InvalidLiteral}; use crate::format_description::well_known::iso8601::EncodedConfig; @@ -124,12 +125,16 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> { *parsed = parsed .with_hour_24(hour) .ok_or(InvalidComponent("hour"))? - .with_minute((fractional_part * 60.0) as _) + .with_minute((fractional_part * Second.per(Minute) as f64) as _) .ok_or(InvalidComponent("minute"))? - .with_second((fractional_part * 3600.0 % 60.) as _) + .with_second( + (fractional_part * Second.per(Hour) as f64 % Minute.per(Hour) as f64) + as _, + ) .ok_or(InvalidComponent("second"))? .with_subsecond( - (fractional_part * 3_600. * 1_000_000_000. % 1_000_000_000.) as _, + (fractional_part * Nanosecond.per(Hour) as f64 + % Nanosecond.per(Second) as f64) as _, ) .ok_or(InvalidComponent("subsecond"))?; return Ok(input); @@ -157,10 +162,11 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> { *parsed = parsed .with_minute(minute) .ok_or(InvalidComponent("minute"))? - .with_second((fractional_part * 60.) as _) + .with_second((fractional_part * Second.per(Minute) as f64) as _) .ok_or(InvalidComponent("second"))? .with_subsecond( - (fractional_part * 60. * 1_000_000_000. % 1_000_000_000.) as _, + (fractional_part * Nanosecond.per(Minute) as f64 + % Nanosecond.per(Second) as f64) as _, ) .ok_or(InvalidComponent("subsecond"))?; return Ok(input); @@ -200,9 +206,11 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> { let (input, second, subsecond) = match float(input) { Some(ParsedItem(input, (second, None))) => (input, second, 0), - Some(ParsedItem(input, (second, Some(fractional_part)))) => { - (input, second, round(fractional_part * 1_000_000_000.) as _) - } + Some(ParsedItem(input, (second, Some(fractional_part)))) => ( + input, + second, + round(fractional_part * Nanosecond.per(Second) as f64) as _, + ), None if extended_kind.is_extended() => { return Err(error::Parse::ParseFromDescription(InvalidComponent( "second", diff --git a/vendor/time/src/parsing/parsed.rs b/vendor/time/src/parsing/parsed.rs index 26405cb11..04c74a720 100644 --- a/vendor/time/src/parsing/parsed.rs +++ b/vendor/time/src/parsing/parsed.rs @@ -423,6 +423,7 @@ impl Parsed { } /// Obtain the absolute value of the offset minute. + #[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()) @@ -447,6 +448,7 @@ impl Parsed { } /// Obtain the absolute value of the offset second. + #[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()) @@ -523,6 +525,7 @@ impl Parsed { } /// Set the named component. + #[doc(hidden)] #[deprecated( since = "0.3.8", note = "use `parsed.set_offset_minute_signed()` instead" @@ -543,6 +546,7 @@ impl Parsed { } /// Set the named component. + #[doc(hidden)] #[deprecated( since = "0.3.8", note = "use `parsed.set_offset_second_signed()` instead" @@ -615,6 +619,7 @@ impl Parsed { } /// Set the named component and return `self`. + #[doc(hidden)] #[deprecated( since = "0.3.8", note = "use `parsed.with_offset_minute_signed()` instead" @@ -635,6 +640,7 @@ impl Parsed { } /// Set the named component and return `self`. + #[doc(hidden)] #[deprecated( since = "0.3.8", note = "use `parsed.with_offset_second_signed()` instead" diff --git a/vendor/time/src/quickcheck.rs b/vendor/time/src/quickcheck.rs index 2304dc89e..4a788b517 100644 --- a/vendor/time/src/quickcheck.rs +++ b/vendor/time/src/quickcheck.rs @@ -38,6 +38,7 @@ 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}; @@ -99,10 +100,10 @@ impl Arbitrary for Duration { impl Arbitrary for Time { fn arbitrary(g: &mut Gen) -> Self { Self::__from_hms_nanos_unchecked( - arbitrary_between!(u8; g, 0, 23), - arbitrary_between!(u8; g, 0, 59), - arbitrary_between!(u8; g, 0, 59), - arbitrary_between!(u32; g, 0, 999_999_999), + 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), ) } @@ -129,11 +130,12 @@ impl Arbitrary for PrimitiveDateTime { impl Arbitrary for UtcOffset { fn arbitrary(g: &mut Gen) -> Self { - let seconds = arbitrary_between!(i32; g, -86_399, 86_399); + let seconds = + arbitrary_between!(i32; g, -(Second.per(Day) as i32 - 1), Second.per(Day) as i32 - 1); Self::__from_hms_unchecked( - (seconds / 3600) as _, - ((seconds % 3600) / 60) as _, - (seconds % 60) as _, + (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 _, ) } diff --git a/vendor/time/src/rand.rs b/vendor/time/src/rand.rs index 8afefe507..e5181f9bd 100644 --- a/vendor/time/src/rand.rs +++ b/vendor/time/src/rand.rs @@ -3,15 +3,16 @@ 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..24), - rng.gen_range(0..60), - rng.gen_range(0..60), - rng.gen_range(0..1_000_000_000), + 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)), ) } } @@ -26,11 +27,11 @@ 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(-86399..=86399); + let seconds = rng.gen_range(-(Second.per(Day) as i32 - 1)..=(Second.per(Day) as i32 - 1)); UtcOffset::__from_hms_unchecked( - (seconds / 3600) as _, - ((seconds % 3600) / 60) as _, - (seconds % 60) as _, + (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 _, ) } } diff --git a/vendor/time/src/serde/mod.rs b/vendor/time/src/serde/mod.rs index 248356e1a..844d7bdef 100644 --- a/vendor/time/src/serde/mod.rs +++ b/vendor/time/src/serde/mod.rs @@ -27,17 +27,31 @@ use core::marker::PhantomData; #[cfg(feature = "serde-human-readable")] use serde::ser::Error as _; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -/// Generate a custom serializer and deserializer from the provided string. +/// Generate a custom serializer and deserializer from a format string or an existing format. /// /// The syntax accepted by this macro is the same as [`format_description::parse()`], which can /// be found in [the book](https://time-rs.github.io/book/api/format-description.html). /// /// # Usage /// -/// Invoked as `serde::format_description!(mod_name, Date, "<format string>")`. This puts a -/// module named `mod_name` in the current scope that can be used to format `Date` structs. A -/// submodule (`mod_name::option`) is also generated for `Option<Date>`. Both modules are only -/// visible in the current scope. +/// Invoked as `serde::format_description!(mod_name, Date, FORMAT)` where `FORMAT` is either a +/// `"<format string>"` or something that implements +#[cfg_attr( + all(feature = "formatting", feature = "parsing"), + doc = "[`Formattable`](crate::formatting::Formattable) and \ + [`Parsable`](crate::parsing::Parsable)." +)] +#[cfg_attr( + all(feature = "formatting", not(feature = "parsing")), + doc = "[`Formattable`](crate::formatting::Formattable)." +)] +#[cfg_attr( + all(not(feature = "formatting"), feature = "parsing"), + doc = "[`Parsable`](crate::parsing::Parsable)." +)] +/// This puts a module named `mod_name` in the current scope that can be used to format `Date` +/// structs. A submodule (`mod_name::option`) is also generated for `Option<Date>`. Both +/// modules are only visible in the current scope. /// /// The returned `Option` will contain a deserialized value if present and `None` if the field /// is present but the value is `null` (or the equivalent in other formats). To return `None` @@ -45,6 +59,8 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; /// /// # Examples /// +/// Using a format string: +/// /// ```rust,no_run /// # use time::OffsetDateTime; #[cfg_attr( @@ -63,6 +79,8 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; /// /// // Makes a module `mod my_format { ... }`. /// serde::format_description!(my_format, OffsetDateTime, "hour=[hour], minute=[minute]"); +/// +/// # #[allow(dead_code)] #[cfg_attr( all(feature = "formatting", feature = "parsing"), doc = "#[derive(Serialize, Deserialize)]" @@ -75,13 +93,111 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; all(not(feature = "formatting"), feature = "parsing"), doc = "#[derive(Deserialize)]" )] +/// struct SerializesWithCustom { +/// #[serde(with = "my_format")] +/// dt: OffsetDateTime, +/// #[serde(with = "my_format::option")] +/// maybe_dt: Option<OffsetDateTime>, +/// } +/// ``` +/// +/// Define the format separately to be used in multiple places: +/// ```rust,no_run +/// # use time::OffsetDateTime; +#[cfg_attr( + all(feature = "formatting", feature = "parsing"), + doc = "use ::serde::{Serialize, Deserialize};" +)] +#[cfg_attr( + all(feature = "formatting", not(feature = "parsing")), + doc = "use ::serde::Serialize;" +)] +#[cfg_attr( + all(not(feature = "formatting"), feature = "parsing"), + doc = "use ::serde::Deserialize;" +)] +/// use time::serde; +/// use time::format_description::FormatItem; +/// +/// const DATE_TIME_FORMAT: &[FormatItem<'_>] = time::macros::format_description!( +/// "hour=[hour], minute=[minute]" +/// ); +/// +/// // Makes a module `mod my_format { ... }`. +/// serde::format_description!(my_format, OffsetDateTime, DATE_TIME_FORMAT); +/// /// # #[allow(dead_code)] +#[cfg_attr( + all(feature = "formatting", feature = "parsing"), + doc = "#[derive(Serialize, Deserialize)]" +)] +#[cfg_attr( + all(feature = "formatting", not(feature = "parsing")), + doc = "#[derive(Serialize)]" +)] +#[cfg_attr( + all(not(feature = "formatting"), feature = "parsing"), + doc = "#[derive(Deserialize)]" +)] +/// struct SerializesWithCustom { +/// #[serde(with = "my_format")] +/// dt: OffsetDateTime, +/// #[serde(with = "my_format::option")] +/// maybe_dt: Option<OffsetDateTime>, +/// } +/// +/// fn main() { +/// # #[allow(unused_variables)] +/// let str_ts = OffsetDateTime::now_utc().format(DATE_TIME_FORMAT).unwrap(); +/// } +/// ``` +/// +/// Customize the configuration of ISO 8601 formatting/parsing: +/// ```rust,no_run +/// # use time::OffsetDateTime; +#[cfg_attr( + all(feature = "formatting", feature = "parsing"), + doc = "use ::serde::{Serialize, Deserialize};" +)] +#[cfg_attr( + all(feature = "formatting", not(feature = "parsing")), + doc = "use ::serde::Serialize;" +)] +#[cfg_attr( + all(not(feature = "formatting"), feature = "parsing"), + doc = "use ::serde::Deserialize;" +)] +/// use time::serde; +/// use time::format_description::well_known::{iso8601, Iso8601}; +/// +/// const CONFIG: iso8601::EncodedConfig = iso8601::Config::DEFAULT +/// .set_year_is_six_digits(false) +/// .encode(); +/// const FORMAT: Iso8601<CONFIG> = Iso8601::<CONFIG>; +/// +/// // Makes a module `mod my_format { ... }`. +/// serde::format_description!(my_format, OffsetDateTime, FORMAT); +/// +/// # #[allow(dead_code)] +#[cfg_attr( + all(feature = "formatting", feature = "parsing"), + doc = "#[derive(Serialize, Deserialize)]" +)] +#[cfg_attr( + all(feature = "formatting", not(feature = "parsing")), + doc = "#[derive(Serialize)]" +)] +#[cfg_attr( + all(not(feature = "formatting"), feature = "parsing"), + doc = "#[derive(Deserialize)]" +)] /// struct SerializesWithCustom { /// #[serde(with = "my_format")] /// dt: OffsetDateTime, /// #[serde(with = "my_format::option")] /// maybe_dt: Option<OffsetDateTime>, /// } +/// # fn main() {} /// ``` /// /// [`format_description::parse()`]: crate::format_description::parse() @@ -108,9 +224,9 @@ impl Serialize for Date { fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { #[cfg(feature = "serde-human-readable")] if serializer.is_human_readable() { - guard!(let Ok(s) = self.format(&DATE_FORMAT) else { + let Ok(s) = self.format(&DATE_FORMAT) else { return Err(S::Error::custom("failed formatting `Date`")); - }); + }; return serializer.serialize_str(&s); } @@ -171,9 +287,9 @@ impl Serialize for OffsetDateTime { fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { #[cfg(feature = "serde-human-readable")] if serializer.is_human_readable() { - guard!(let Ok(s) = self.format(&OFFSET_DATE_TIME_FORMAT) else { + let Ok(s) = self.format(&OFFSET_DATE_TIME_FORMAT) else { return Err(S::Error::custom("failed formatting `OffsetDateTime`")); - }); + }; return serializer.serialize_str(&s); } @@ -216,9 +332,9 @@ impl Serialize for PrimitiveDateTime { fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { #[cfg(feature = "serde-human-readable")] if serializer.is_human_readable() { - guard!(let Ok(s) = self.format(&PRIMITIVE_DATE_TIME_FORMAT) else { + let Ok(s) = self.format(&PRIMITIVE_DATE_TIME_FORMAT) else { return Err(S::Error::custom("failed formatting `PrimitiveDateTime`")); - }); + }; return serializer.serialize_str(&s); } @@ -262,9 +378,9 @@ impl Serialize for Time { fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { #[cfg(feature = "serde-human-readable")] if serializer.is_human_readable() { - guard!(let Ok(s) = self.format(&TIME_FORMAT) else { + let Ok(s) = self.format(&TIME_FORMAT) else { return Err(S::Error::custom("failed formatting `Time`")); - }); + }; return serializer.serialize_str(&s); } @@ -298,9 +414,9 @@ impl Serialize for UtcOffset { fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { #[cfg(feature = "serde-human-readable")] if serializer.is_human_readable() { - guard!(let Ok(s) = self.format(&UTC_OFFSET_FORMAT) else { + let Ok(s) = self.format(&UTC_OFFSET_FORMAT) else { return Err(S::Error::custom("failed formatting `UtcOffset`")); - }); + }; return serializer.serialize_str(&s); } diff --git a/vendor/time/src/shim.rs b/vendor/time/src/shim.rs deleted file mode 100644 index b9ac97a16..000000000 --- a/vendor/time/src/shim.rs +++ /dev/null @@ -1,180 +0,0 @@ -//! Macro for simulating let-else on older compilers. -//! -//! This module and its macros will be removed once the MSRV is 1.65 (NET 2023-05-03). - -#![allow(unused_macros)] -#![allow(clippy::missing_docs_in_private_items)] - -// The following code is copyright 2016 Alex Burka. Available under the MIT OR Apache-2.0 license. -// Some adaptations have been made to the original code. - -pub(crate) enum LetElseBodyMustDiverge {} - -#[allow(clippy::missing_docs_in_private_items)] -macro_rules! __guard_output { - ((($($imms:ident)*) ($($muts:ident)*)), - [($($pattern:tt)*) ($rhs:expr) ($diverge:expr)]) => { - __guard_impl!(@as_stmt - let ($($imms,)* $(mut $muts,)*) = { - #[allow(unused_mut)] - match $rhs { - $($pattern)* => { - ($($imms,)* $($muts,)*) - }, - _ => { - let _: $crate::shim::LetElseBodyMustDiverge = $diverge; - }, - } - } - ) - }; -} - -macro_rules! __guard_impl { - // 0. cast a series of token trees to a statement - (@as_stmt $s:stmt) => { $s }; - - // 1. output stage - (@collect () -> $($rest:tt)*) => { - __guard_output!($($rest)*) - }; - - - // 2. identifier collection stage - // The pattern is scanned destructively. Anything that looks like a capture (including - // false positives, like un-namespaced/empty structs or enum variants) is copied into the - // appropriate identifier list. Irrelevant symbols are discarded. The scanning descends - // recursively into bracketed structures. - - // unwrap brackets and prepend their contents to the pattern remainder, in case there are captures inside - (@collect (($($inside:tt)*) $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) - }; - (@collect ({$($inside:tt)*} $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) - }; - (@collect ([$($inside:tt)*] $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) - }; - - // discard irrelevant symbols - (@collect (, $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - (@collect (.. $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - (@collect (@ $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - (@collect (_ $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - (@collect (& $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - - // ignore generic parameters - (@collect (:: <$($generic:tt),*> $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - // a path can't be a capture, and a path can't end with ::, so the ident after :: is never a capture - (@collect (:: $pathend:ident $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - - // alternative patterns may be given with | as long as the same captures (including type) appear on each side - // due to this property, if we see a | we've already parsed all the captures and can simply stop - (@collect (| $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect () -> $idents, $thru) // discard the rest of the pattern, proceed to output stage - }; - - // throw away some identifiers that do not represent captures - - // an ident followed by a colon is the name of a structure member - (@collect ($id:ident: $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - // paths do not represent captures - (@collect ($pathcomp:ident :: $pathend:ident $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - // an ident followed by parentheses is the name of a tuple-like struct or enum variant - // (unwrap the parens to parse the contents) - (@collect ($id:ident ($($inside:tt)*) $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) - }; - // an ident followed by curly braces is the name of a struct or struct-like enum variant - // (unwrap the braces to parse the contents) - (@collect ($id:ident {$($inside:tt)*} $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) - }; - - // actually identifier collection happens here! - - // capture by mutable reference! - (@collect (ref mut $id:ident $($tail:tt)*) -> (($($imms:ident)*) $muts:tt), $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> (($($imms)* $id) $muts), $thru) - }; - // capture by immutable reference! - (@collect (ref $id:ident $($tail:tt)*) -> (($($imms:ident)*) $muts:tt), $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> (($($imms)* $id) $muts), $thru) - }; - // capture by move into mutable binding! - (@collect (mut $id:ident $($tail:tt)*) -> ($imms:tt ($($muts:ident)*)), $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> ($imms ($($muts)* $id)), $thru) - }; - // capture by move into an immutable binding! - (@collect ($id:ident $($tail:tt)*) -> (($($imms:ident)*) $muts:tt), $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> (($($imms)* $id) $muts), $thru) - }; - - // 3. splitting (for new syntax) - - // done with pattern (and it's LPED=X) - (@split (else { $($diverge:tt)* } = $($tail:tt)*) -> ($pat:tt)) => { - __guard_impl!(@collect $pat -> (() ()), [$pat ($($tail)*) ({ $($diverge)* })]) - }; - - // done with pattern (and it's LP=XED) - (@split (= $($tail:tt)*) -> ($pat:tt)) => { - __guard_impl!(@split expr ($($tail)*) -> ($pat ())) - }; - - // found a token in the pattern - (@split ($head:tt $($tail:tt)*) -> (($($pat:tt)*))) => { - __guard_impl!(@split ($($tail)*) -> (($($pat)* $head))) - }; - - // found an "else DIVERGE" in the expr - (@split expr (else { $($tail:tt)* }) -> ($pat:tt $expr:tt)) => { - __guard_impl!(@collect $pat -> (() ()), [$pat $expr ({ $($tail)* })]) - }; - - // found an else in the expr with more stuff after it - (@split expr (else { $($body:tt)* } $($tail:tt)*) -> ($pat:tt ($($expr:tt)*))) => { - __guard_impl!(@split expr ($($tail)*) -> ($pat ($($expr)* else { $($body)* }))) - }; - - // found another token in the expr - (@split expr ($head:tt $($tail:tt)*) -> ($pat:tt ($($expr:tt)*))) => { - __guard_impl!(@split expr ($($tail)*) -> ($pat ($($expr)* $head))) - }; - - // 4. entry points - - // new syntax - (let $($tail:tt)*) => { - __guard_impl!(@split ($($tail)*) -> (())) - // | | | - // | | ^ pattern - // | ^ tail to be split into "PAT = EXPR else DIVERGE" - // ^ first pass will do the parsing - }; -} - -macro_rules! guard { - ($($input:tt)*) => { - __guard_impl!($($input)*) - }; -} 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 fcea4b0f5..dfbe063a2 100644 --- a/vendor/time/src/sys/local_offset_at/wasm_js.rs +++ b/vendor/time/src/sys/local_offset_at/wasm_js.rs @@ -1,3 +1,4 @@ +use crate::convert::*; use crate::{OffsetDateTime, UtcOffset}; /// Obtain the system's UTC offset. @@ -6,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) * -60; + 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 69b422314..a4d5882d6 100644 --- a/vendor/time/src/sys/local_offset_at/windows.rs +++ b/vendor/time/src/sys/local_offset_at/windows.rs @@ -2,6 +2,7 @@ use core::mem::MaybeUninit; +use crate::convert::*; use crate::{OffsetDateTime, UtcOffset}; // ffi: WINAPI FILETIME struct @@ -56,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 = 10_000_000; + 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/time.rs b/vendor/time/src/time.rs index 32fa97790..87b465bb9 100644 --- a/vendor/time/src/time.rs +++ b/vendor/time/src/time.rs @@ -6,6 +6,7 @@ use core::time::Duration as StdDuration; #[cfg(feature = "formatting")] use std::io; +use crate::convert::*; #[cfg(feature = "formatting")] use crate::formatting::Formattable; #[cfg(feature = "parsing")] @@ -71,10 +72,10 @@ impl Time { second: u8, nanosecond: u32, ) -> Self { - debug_assert!(hour < 24); - debug_assert!(minute < 60); - debug_assert!(second < 60); - debug_assert!(nanosecond < 1_000_000_000); + 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, @@ -99,9 +100,9 @@ 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 => 23); - ensure_value_in_range!(minute in 0 => 59); - ensure_value_in_range!(second in 0 => 59); + 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)) } @@ -125,15 +126,15 @@ impl Time { second: u8, millisecond: u16, ) -> Result<Self, error::ComponentRange> { - ensure_value_in_range!(hour in 0 => 23); - ensure_value_in_range!(minute in 0 => 59); - ensure_value_in_range!(second in 0 => 59); - ensure_value_in_range!(millisecond in 0 => 999); + 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 * 1_000_000, + millisecond as u32 * Nanosecond.per(Millisecond), )) } @@ -157,15 +158,15 @@ impl Time { second: u8, microsecond: u32, ) -> Result<Self, error::ComponentRange> { - ensure_value_in_range!(hour in 0 => 23); - ensure_value_in_range!(minute in 0 => 59); - ensure_value_in_range!(second in 0 => 59); - ensure_value_in_range!(microsecond in 0 => 999_999); + 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 * 1_000, + microsecond * Nanosecond.per(Microsecond) as u32, )) } @@ -189,10 +190,10 @@ impl Time { second: u8, nanosecond: u32, ) -> Result<Self, error::ComponentRange> { - ensure_value_in_range!(hour in 0 => 23); - ensure_value_in_range!(minute in 0 => 59); - ensure_value_in_range!(second in 0 => 59); - ensure_value_in_range!(nanosecond in 0 => 999_999_999); + 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, )) @@ -223,7 +224,7 @@ impl Time { self.hour, self.minute, self.second, - (self.nanosecond / 1_000_000) as u16, + (self.nanosecond / Nanosecond.per(Millisecond)) as u16, ) } @@ -238,7 +239,12 @@ impl Time { /// ); /// ``` pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) { - (self.hour, self.minute, self.second, self.nanosecond / 1_000) + ( + self.hour, + self.minute, + self.second, + self.nanosecond / Nanosecond.per(Microsecond) as u32, + ) } /// Get the clock hour, minute, second, and nanosecond. @@ -304,7 +310,7 @@ impl Time { /// assert_eq!(time!(23:59:59.999).millisecond(), 999); /// ``` pub const fn millisecond(self) -> u16 { - (self.nanosecond / 1_000_000) as _ + (self.nanosecond / Nanosecond.per(Millisecond)) as _ } /// Get the microseconds within the second. @@ -317,7 +323,7 @@ impl Time { /// assert_eq!(time!(23:59:59.999_999).microsecond(), 999_999); /// ``` pub const fn microsecond(self) -> u32 { - self.nanosecond / 1_000 + self.nanosecond / Nanosecond.per(Microsecond) as u32 } /// Get the nanoseconds within the second. @@ -339,19 +345,21 @@ impl Time { /// 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 seconds = self.second as i8 + (duration.whole_seconds() % 60) as i8; - let mut minutes = self.minute as i8 + (duration.whole_minutes() % 60) as i8; - let mut hours = self.hour as i8 + (duration.whole_hours() % 24) as i8; + let mut seconds = + self.second 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; let mut date_adjustment = DateAdjustment::None; - cascade!(nanoseconds in 0..1_000_000_000 => seconds); - cascade!(seconds in 0..60 => minutes); - cascade!(minutes in 0..60 => hours); - if hours >= 24 { - hours -= 24; + 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 += 24; + hours += Hour.per(Day) as i8; date_adjustment = DateAdjustment::Previous; } @@ -370,19 +378,21 @@ impl Time { /// 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 seconds = self.second as i8 - (duration.whole_seconds() % 60) as i8; - let mut minutes = self.minute as i8 - (duration.whole_minutes() % 60) as i8; - let mut hours = self.hour as i8 - (duration.whole_hours() % 24) as i8; + let mut seconds = + self.second 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; let mut date_adjustment = DateAdjustment::None; - cascade!(nanoseconds in 0..1_000_000_000 => seconds); - cascade!(seconds in 0..60 => minutes); - cascade!(minutes in 0..60 => hours); - if hours >= 24 { - hours -= 24; + 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 += 24; + hours += Hour.per(Day) as i8; date_adjustment = DateAdjustment::Previous; } @@ -401,16 +411,18 @@ impl Time { /// 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() % 60) as u8; - let mut minute = self.minute + ((duration.as_secs() / 60) % 60) as u8; - let mut hour = self.hour + ((duration.as_secs() / 3_600) % 24) as u8; + 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 is_next_day = false; - cascade!(nanosecond in 0..1_000_000_000 => second); - cascade!(second in 0..60 => minute); - cascade!(minute in 0..60 => hour); - if hour >= 24 { - hour -= 24; + 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; } @@ -424,16 +436,18 @@ impl Time { /// 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() % 60) as i8; - let mut minute = self.minute as i8 - ((duration.as_secs() / 60) % 60) as i8; - let mut hour = self.hour as i8 - ((duration.as_secs() / 3_600) % 24) as i8; + 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 is_previous_day = false; - cascade!(nanosecond in 0..1_000_000_000 => second); - cascade!(second in 0..60 => minute); - cascade!(minute in 0..60 => 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 += 24; + hour += Hour.per(Day) as i8; is_previous_day = true; } @@ -457,7 +471,7 @@ impl Time { /// ``` #[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 => 23); + ensure_value_in_range!(hour in 0 => Hour.per(Day) - 1); Ok(Self::__from_hms_nanos_unchecked( hour, self.minute, @@ -478,7 +492,7 @@ impl Time { /// ``` #[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 => 59); + ensure_value_in_range!(minute in 0 => Minute.per(Hour) - 1); Ok(Self::__from_hms_nanos_unchecked( self.hour, minute, @@ -499,7 +513,7 @@ impl Time { /// ``` #[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 => 59); + ensure_value_in_range!(second in 0 => Second.per(Minute) - 1); Ok(Self::__from_hms_nanos_unchecked( self.hour, self.minute, @@ -523,12 +537,12 @@ impl Time { self, millisecond: u16, ) -> Result<Self, error::ComponentRange> { - ensure_value_in_range!(millisecond in 0 => 999); + 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 * 1_000_000, + millisecond as u32 * Nanosecond.per(Millisecond), )) } @@ -547,12 +561,12 @@ impl Time { self, microsecond: u32, ) -> Result<Self, error::ComponentRange> { - ensure_value_in_range!(microsecond in 0 => 999_999); + ensure_value_in_range!(microsecond in 0 => Microsecond.per(Second) - 1); Ok(Self::__from_hms_nanos_unchecked( self.hour, self.minute, self.second, - microsecond * 1000, + microsecond * Nanosecond.per(Microsecond) as u32, )) } @@ -568,7 +582,7 @@ impl Time { /// ``` #[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 => 999_999_999); + ensure_value_in_range!(nanosecond in 0 => Nanosecond.per(Second) - 1); Ok(Self::__from_hms_nanos_unchecked( self.hour, self.minute, @@ -745,12 +759,14 @@ impl Sub for Time { let second_diff = (self.second as i8) - (rhs.second as i8); let nanosecond_diff = (self.nanosecond as i32) - (rhs.nanosecond as i32); - let seconds = hour_diff as i64 * 3_600 + minute_diff as i64 * 60 + second_diff 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 + 1_000_000_000) + (seconds - 1, nanosecond_diff + Nanosecond.per(Second) as i32) } else if seconds < 0 && nanosecond_diff > 0 { - (seconds + 1, nanosecond_diff - 1_000_000_000) + (seconds + 1, nanosecond_diff - Nanosecond.per(Second) as i32) } else { (seconds, nanosecond_diff) }; diff --git a/vendor/time/src/utc_offset.rs b/vendor/time/src/utc_offset.rs index d69f0c1e3..af7fd1bf7 100644 --- a/vendor/time/src/utc_offset.rs +++ b/vendor/time/src/utc_offset.rs @@ -5,6 +5,7 @@ use core::ops::Neg; #[cfg(feature = "formatting")] use std::io; +use crate::convert::*; use crate::error; #[cfg(feature = "formatting")] use crate::formatting::Formattable; @@ -59,8 +60,8 @@ impl UtcOffset { debug_assert!(seconds >= 0); } debug_assert!(hours.unsigned_abs() < 24); - debug_assert!(minutes.unsigned_abs() < 60); - debug_assert!(seconds.unsigned_abs() < 60); + debug_assert!(minutes.unsigned_abs() < Minute.per(Hour)); + debug_assert!(seconds.unsigned_abs() < Second.per(Minute)); Self { hours, @@ -87,8 +88,12 @@ impl UtcOffset { mut seconds: i8, ) -> Result<Self, error::ComponentRange> { ensure_value_in_range!(hours in -23 => 23); - ensure_value_in_range!(minutes in -59 => 59); - ensure_value_in_range!(seconds in -59 => 59); + 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; @@ -112,12 +117,14 @@ impl UtcOffset { /// # Ok::<_, time::Error>(()) /// ``` pub const fn from_whole_seconds(seconds: i32) -> Result<Self, error::ComponentRange> { - ensure_value_in_range!(seconds in -86_399 => 86_399); + 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 / 3_600) as _, - ((seconds / 60) % 60) as _, - (seconds % 60) as _, + (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 @@ -156,7 +163,7 @@ impl UtcOffset { /// assert_eq!(offset!(-1:02:03).whole_minutes(), -62); /// ``` pub const fn whole_minutes(self) -> i16 { - self.hours as i16 * 60 + self.minutes as i16 + self.hours as i16 * Minute.per(Hour) as i16 + self.minutes as i16 } /// Obtain the number of minutes past the hour the offset is from UTC. A positive value @@ -182,7 +189,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 * 3_600 + self.minutes as i32 * 60 + self.seconds as i32 + self.hours as i32 * Second.per(Hour) as i32 + + self.minutes as i32 * Second.per(Minute) as i32 + + self.seconds as i32 } /// Obtain the number of seconds past the minute the offset is from UTC. A positive value diff --git a/vendor/time/src/util.rs b/vendor/time/src/util.rs index b41068384..857f5f20b 100644 --- a/vendor/time/src/util.rs +++ b/vendor/time/src/util.rs @@ -44,30 +44,40 @@ pub mod local_offset { /// Obtaining the local UTC offset is required to be sound. Undefined behavior will never /// occur. This is the default. Sound, - /// Obtaining the local UTC offset is allowed to invoke undefined behavior. Setting this - /// value is strongly discouraged. To do so, you must comply with the safety requirements + /// Obtaining the local UTC offset is allowed to invoke undefined behavior. **Setting this + /// value is strongly discouraged.** To do so, you must comply with the safety requirements /// of [`time::local_offset::set_soundness`](set_soundness). Unsound, } - /// Set whether obtaining the local UTC offset is allowed to invoke undefined behavior. + /// Set whether obtaining the local UTC offset is allowed to invoke undefined behavior. **Use of + /// this function is heavily discouraged.** /// /// # Safety /// /// If this method is called with [`Soundness::Sound`], the call is always sound. If this method /// is called with [`Soundness::Unsound`], the following conditions apply. /// - /// - If the operating system is not Unix-like, the call is sound. + /// - If the operating system provides a thread-safe environment, the call is sound. /// - If the process is single-threaded, the call is sound. /// - If the process is multi-threaded, no other thread may mutate the environment in any way at /// the same time a call to a method that obtains the local UTC offset. This includes adding, /// removing, or modifying an environment variable. /// + /// The first two conditions are automatically checked by `time`, such that you do not need to + /// declare your code unsound. Currently, the only known operating systems that does _not_ + /// provide a thread-safe environment are some Unix-like OS's. All other operating systems + /// should succeed when attempting to obtain the local UTC offset. + /// /// Note that you must not only verify this safety condition for your code, but for **all** code /// that will be included in the final binary. Notably, it applies to both direct and transitive - /// dependencies and to both Rust and non-Rust code. For this reason it is not possible to + /// dependencies and to both Rust and non-Rust code. **For this reason it is not possible to /// soundly pass [`Soundness::Unsound`] to this method if you are writing a library that may - /// used by others. + /// used by others.** + /// + /// If using this method is absolutely necessary, it is recommended to keep the time between + /// setting the soundness to [`Soundness::Unsound`] and setting it back to [`Soundness::Sound`] + /// as short as possible. /// /// The following methods currently obtain the local UTC offset: /// diff --git a/vendor/time/src/weekday.rs b/vendor/time/src/weekday.rs index f499c30ee..d530a2e4d 100644 --- a/vendor/time/src/weekday.rs +++ b/vendor/time/src/weekday.rs @@ -66,6 +66,28 @@ impl Weekday { } } + /// Get n-th next day. + /// + /// ```rust + /// # use time::Weekday; + /// assert_eq!(Weekday::Monday.nth_next(1), Weekday::Tuesday); + /// assert_eq!(Weekday::Sunday.nth_next(10), Weekday::Wednesday); + /// ``` + pub const fn nth_next(self, n: u8) -> Self { + match (self.number_days_from_monday() + n % 7) % 7 { + 0 => Monday, + 1 => Tuesday, + 2 => Wednesday, + 3 => Thursday, + 4 => Friday, + 5 => Saturday, + val => { + debug_assert!(val == 6); + Sunday + } + } + } + /// Get the one-indexed number of days from Monday. /// /// ```rust |