diff options
Diffstat (limited to 'vendor/time/src/date_time.rs')
-rw-r--r-- | vendor/time/src/date_time.rs | 123 |
1 files changed, 77 insertions, 46 deletions
diff --git a/vendor/time/src/date_time.rs b/vendor/time/src/date_time.rs index 819f6d36b..53cae5eb4 100644 --- a/vendor/time/src/date_time.rs +++ b/vendor/time/src/date_time.rs @@ -16,10 +16,16 @@ use std::io; #[cfg(feature = "std")] use std::time::SystemTime; +use deranged::RangedI64; + use crate::convert::*; use crate::date::{MAX_YEAR, MIN_YEAR}; #[cfg(feature = "formatting")] use crate::formatting::Formattable; +use crate::internal_macros::{ + bug, cascade, const_try, const_try_opt, div_floor, ensure_ranged, expect_opt, impl_add_assign, + impl_sub_assign, +}; #[cfg(feature = "parsing")] use crate::parsing::{Parsable, Parsed}; use crate::{error, util, Date, Duration, Month, Time, UtcOffset, Weekday}; @@ -191,7 +197,10 @@ pub(crate) const fn maybe_offset_from_offset<O: MaybeOffset>( // endregion const trait methods hacks /// The Julian day of the Unix epoch. -const UNIX_EPOCH_JULIAN_DAY: i32 = Date::__from_ordinal_date_unchecked(1970, 1).to_julian_day(); +// Safety: `ordinal` is not zero. +#[allow(clippy::undocumented_unsafe_blocks)] +const UNIX_EPOCH_JULIAN_DAY: i32 = + unsafe { Date::__from_ordinal_date_unchecked(1970, 1) }.to_julian_day(); pub struct DateTime<O: MaybeOffset> { pub(crate) date: Date, @@ -226,7 +235,8 @@ impl DateTime<offset_kind::None> { impl DateTime<offset_kind::Fixed> { pub const UNIX_EPOCH: Self = Self { - date: Date::__from_ordinal_date_unchecked(1970, 1), + // Safety: `ordinal` is not zero. + date: unsafe { Date::__from_ordinal_date_unchecked(1970, 1) }, time: Time::MIDNIGHT, offset: UtcOffset::UTC, }; @@ -248,28 +258,27 @@ impl<O: MaybeOffset> DateTime<O> { where O: HasLogicalOffset, { - #[allow(clippy::missing_docs_in_private_items)] - const MIN_TIMESTAMP: i64 = Date::MIN.midnight().assume_utc().unix_timestamp(); - #[allow(clippy::missing_docs_in_private_items)] - const MAX_TIMESTAMP: i64 = Date::MAX - .with_time(Time::__from_hms_nanos_unchecked(23, 59, 59, 999_999_999)) - .assume_utc() - .unix_timestamp(); - - ensure_value_in_range!(timestamp in MIN_TIMESTAMP => MAX_TIMESTAMP); + type Timestamp = RangedI64< + { Date::MIN.midnight().assume_utc().unix_timestamp() }, + { Date::MAX.with_time(Time::MAX).assume_utc().unix_timestamp() }, + >; + ensure_ranged!(Timestamp: timestamp); // Use the unchecked method here, as the input validity has already been verified. let date = Date::from_julian_day_unchecked( - UNIX_EPOCH_JULIAN_DAY + div_floor!(timestamp, Second.per(Day) as i64) as i32, + UNIX_EPOCH_JULIAN_DAY + div_floor!(timestamp, Second::per(Day) as i64) as i32, ); - let seconds_within_day = timestamp.rem_euclid(Second.per(Day) as _); - let time = Time::__from_hms_nanos_unchecked( - (seconds_within_day / Second.per(Hour) as i64) as _, - ((seconds_within_day % Second.per(Hour) as i64) / Minute.per(Hour) as i64) as _, - (seconds_within_day % Second.per(Minute) as i64) as _, - 0, - ); + let seconds_within_day = timestamp.rem_euclid(Second::per(Day) as _); + // Safety: All values are in range. + let time = unsafe { + Time::__from_hms_nanos_unchecked( + (seconds_within_day / Second::per(Hour) as i64) as _, + ((seconds_within_day % Second::per(Hour) as i64) / Minute::per(Hour) as i64) as _, + (seconds_within_day % Second::per(Minute) as i64) as _, + 0, + ) + }; Ok(Self { date, @@ -284,17 +293,20 @@ impl<O: MaybeOffset> DateTime<O> { { let datetime = const_try!(Self::from_unix_timestamp(div_floor!( timestamp, - Nanosecond.per(Second) as i128 + Nanosecond::per(Second) as i128 ) as i64)); Ok(Self { date: datetime.date, - time: Time::__from_hms_nanos_unchecked( - datetime.hour(), - datetime.minute(), - datetime.second(), - timestamp.rem_euclid(Nanosecond.per(Second) as _) as u32, - ), + // Safety: `nanosecond` is in range due to `rem_euclid`. + time: unsafe { + Time::__from_hms_nanos_unchecked( + datetime.hour(), + datetime.minute(), + datetime.second(), + timestamp.rem_euclid(Nanosecond::per(Second) as _) as u32, + ) + }, offset: maybe_offset_from_offset::<O>(UtcOffset::UTC), }) } @@ -455,9 +467,9 @@ impl<O: MaybeOffset> DateTime<O> { let offset = maybe_offset_as_offset::<O>(self.offset).whole_seconds() as i64; let days = - (self.to_julian_day() as i64 - UNIX_EPOCH_JULIAN_DAY as i64) * Second.per(Day) as i64; - let hours = self.hour() as i64 * Second.per(Hour) as i64; - let minutes = self.minute() as i64 * Second.per(Minute) as i64; + (self.to_julian_day() as i64 - UNIX_EPOCH_JULIAN_DAY as i64) * Second::per(Day) as i64; + let hours = self.hour() as i64 * Second::per(Hour) as i64; + let minutes = self.minute() as i64 * Second::per(Minute) as i64; let seconds = self.second() as i64; days + hours + minutes + seconds - offset } @@ -466,7 +478,7 @@ impl<O: MaybeOffset> DateTime<O> { where O: HasLogicalOffset, { - self.unix_timestamp() as i128 * Nanosecond.per(Second) as i128 + self.nanosecond() as i128 + self.unix_timestamp() as i128 * Nanosecond::per(Second) as i128 + self.nanosecond() as i128 } // endregion unix timestamp getters // endregion: getters @@ -526,7 +538,8 @@ impl<O: MaybeOffset> DateTime<O> { } Some(DateTime { - date: Date::__from_ordinal_date_unchecked(year, ordinal), + // Safety: `ordinal` is not zero. + date: unsafe { Date::__from_ordinal_date_unchecked(year, ordinal) }, time, offset, }) @@ -558,12 +571,12 @@ impl<O: MaybeOffset> DateTime<O> { let mut ordinal = ordinal as i16; // Cascade the values twice. This is needed because the values are adjusted twice above. - cascade!(second in 0..Second.per(Minute) as i16 => minute); - cascade!(second in 0..Second.per(Minute) as i16 => minute); - cascade!(minute in 0..Minute.per(Hour) as i16 => hour); - cascade!(minute in 0..Minute.per(Hour) as i16 => hour); - cascade!(hour in 0..Hour.per(Day) as i8 => ordinal); - cascade!(hour in 0..Hour.per(Day) as i8 => ordinal); + cascade!(second in 0..Second::per(Minute) as i16 => minute); + cascade!(second in 0..Second::per(Minute) as i16 => minute); + cascade!(minute in 0..Minute::per(Hour) as i16 => hour); + cascade!(minute in 0..Minute::per(Hour) as i16 => hour); + cascade!(hour in 0..Hour::per(Day) as i8 => ordinal); + cascade!(hour in 0..Hour::per(Day) as i8 => ordinal); cascade!(ordinal => year); debug_assert!(ordinal > 0); @@ -572,12 +585,15 @@ impl<O: MaybeOffset> DateTime<O> { ( year, ordinal as _, - Time::__from_hms_nanos_unchecked( - hour as _, - minute as _, - second as _, - self.nanosecond(), - ), + // Safety: The cascades above ensure the values are in range. + unsafe { + Time::__from_hms_nanos_unchecked( + hour as _, + minute as _, + second as _, + self.nanosecond(), + ) + }, ) } // endregion to offset @@ -653,6 +669,7 @@ impl<O: MaybeOffset> DateTime<O> { // endregion saturating arithmetic // region: replacement + #[must_use = "this does not modify the original value"] pub const fn replace_time(self, time: Time) -> Self { Self { date: self.date, @@ -661,6 +678,7 @@ impl<O: MaybeOffset> DateTime<O> { } } + #[must_use = "this does not modify the original value"] pub const fn replace_date(self, date: Date) -> Self { Self { date, @@ -669,6 +687,7 @@ impl<O: MaybeOffset> DateTime<O> { } } + #[must_use = "this does not modify the original value"] pub const fn replace_date_time(self, date_time: DateTime<offset_kind::None>) -> Self where O: HasLogicalOffset, @@ -680,6 +699,7 @@ impl<O: MaybeOffset> DateTime<O> { } } + #[must_use = "this does not modify the original value"] pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> { Ok(Self { date: const_try!(self.date.replace_year(year)), @@ -688,6 +708,7 @@ impl<O: MaybeOffset> DateTime<O> { }) } + #[must_use = "this does not modify the original value"] pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> { Ok(Self { date: const_try!(self.date.replace_month(month)), @@ -696,6 +717,7 @@ impl<O: MaybeOffset> DateTime<O> { }) } + #[must_use = "this does not modify the original value"] pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> { Ok(Self { date: const_try!(self.date.replace_day(day)), @@ -704,6 +726,7 @@ impl<O: MaybeOffset> DateTime<O> { }) } + #[must_use = "this does not modify the original value"] pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> { Ok(Self { date: self.date, @@ -712,6 +735,7 @@ impl<O: MaybeOffset> DateTime<O> { }) } + #[must_use = "this does not modify the original value"] pub const fn replace_minute(self, minute: u8) -> Result<Self, error::ComponentRange> { Ok(Self { date: self.date, @@ -720,6 +744,7 @@ impl<O: MaybeOffset> DateTime<O> { }) } + #[must_use = "this does not modify the original value"] pub const fn replace_second(self, second: u8) -> Result<Self, error::ComponentRange> { Ok(Self { date: self.date, @@ -728,6 +753,7 @@ impl<O: MaybeOffset> DateTime<O> { }) } + #[must_use = "this does not modify the original value"] pub const fn replace_millisecond( self, millisecond: u16, @@ -739,6 +765,7 @@ impl<O: MaybeOffset> DateTime<O> { }) } + #[must_use = "this does not modify the original value"] pub const fn replace_microsecond( self, microsecond: u32, @@ -750,6 +777,7 @@ impl<O: MaybeOffset> DateTime<O> { }) } + #[must_use = "this does not modify the original value"] pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> { Ok(Self { date: self.date, @@ -760,6 +788,7 @@ impl<O: MaybeOffset> DateTime<O> { // Don't gate this on just having an offset, as `ZonedDateTime` cannot be set to an arbitrary // offset. + #[must_use = "this does not modify the original value"] pub const fn replace_offset(self, offset: UtcOffset) -> DateTime<offset_kind::Fixed> where O: IsOffsetKindFixed, @@ -822,7 +851,9 @@ impl<O: MaybeOffset> DateTime<O> { } let (year, ordinal, time) = self.to_offset_raw(UtcOffset::UTC); - let Ok(date) = Date::from_ordinal_date(year, ordinal) else { return false }; + let Ok(date) = Date::from_ordinal_date(year, ordinal) else { + return false; + }; time.hour() == 23 && time.minute() == 59 @@ -1156,7 +1187,7 @@ impl From<DateTime<offset_kind::Fixed>> for SystemTime { impl From<js_sys::Date> for DateTime<offset_kind::Fixed> { fn from(js_date: js_sys::Date) -> Self { // get_time() returns milliseconds - let timestamp_nanos = (js_date.get_time() * Nanosecond.per(Millisecond) as f64) as i128; + let timestamp_nanos = (js_date.get_time() * Nanosecond::per(Millisecond) as f64) as i128; Self::from_unix_timestamp_nanos(timestamp_nanos) .expect("invalid timestamp: Timestamp cannot fit in range") } @@ -1171,7 +1202,7 @@ impl From<DateTime<offset_kind::Fixed>> for js_sys::Date { fn from(datetime: DateTime<offset_kind::Fixed>) -> Self { // new Date() takes milliseconds let timestamp = - (datetime.unix_timestamp_nanos() / Nanosecond.per(Millisecond) as i128) as f64; + (datetime.unix_timestamp_nanos() / Nanosecond::per(Millisecond) as i128) as f64; js_sys::Date::new(×tamp.into()) } } |