#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
#[allow(clippy::exhaustive_structs)] pub struct DateDuration {
pub is_negative: bool,
pub years: u32,
pub months: u32,
pub weeks: u32,
pub days: u64,
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[allow(clippy::exhaustive_enums)] pub enum DateDurationUnit {
Years,
Months,
Weeks,
Days,
}
impl DateDuration {
pub fn for_years(years: i32) -> Self {
Self {
is_negative: years.is_negative(),
years: years.unsigned_abs(),
..Default::default()
}
}
pub fn for_months(months: i32) -> Self {
Self {
is_negative: months.is_negative(),
months: months.unsigned_abs(),
..Default::default()
}
}
pub fn for_weeks(weeks: i32) -> Self {
Self {
is_negative: weeks.is_negative(),
weeks: weeks.unsigned_abs(),
..Default::default()
}
}
pub fn for_days(days: i64) -> Self {
Self {
is_negative: days.is_negative(),
days: days.unsigned_abs(),
..Default::default()
}
}
pub(crate) fn from_signed_ymwd(years: i64, months: i64, weeks: i64, days: i64) -> Self {
let is_negative = years.is_negative()
|| months.is_negative()
|| weeks.is_negative()
|| days.is_negative();
if is_negative
&& (years.is_positive()
|| months.is_positive()
|| weeks.is_positive()
|| days.is_positive())
{
debug_assert!(false, "mixed signs in from_signed_ymd");
}
Self {
is_negative,
years: match u32::try_from(years.unsigned_abs()) {
Ok(x) => x,
Err(_) => {
debug_assert!(false, "years out of range");
u32::MAX
}
},
months: match u32::try_from(months.unsigned_abs()) {
Ok(x) => x,
Err(_) => {
debug_assert!(false, "months out of range");
u32::MAX
}
},
weeks: match u32::try_from(weeks.unsigned_abs()) {
Ok(x) => x,
Err(_) => {
debug_assert!(false, "weeks out of range");
u32::MAX
}
},
days: days.unsigned_abs(),
}
}
#[inline]
pub(crate) fn add_years_to(&self, year: i32) -> i32 {
if !self.is_negative {
match year.checked_add_unsigned(self.years) {
Some(x) => x,
None => {
debug_assert!(false, "{year} + {self:?} out of year range");
i32::MAX
}
}
} else {
match year.checked_sub_unsigned(self.years) {
Some(x) => x,
None => {
debug_assert!(false, "{year} - {self:?} out of year range");
i32::MIN
}
}
}
}
#[inline]
pub(crate) fn add_months_to(&self, month: u8) -> i64 {
if !self.is_negative {
i64::from(month) + i64::from(self.months)
} else {
i64::from(month) - i64::from(self.months)
}
}
#[inline]
pub(crate) fn add_weeks_and_days_to(&self, day: u8) -> i64 {
if !self.is_negative {
let day = i64::from(day) + i64::from(self.weeks) * 7;
match day.checked_add_unsigned(self.days) {
Some(x) => x,
None => {
debug_assert!(false, "{day} + {self:?} out of day range");
i64::MAX
}
}
} else {
let day = i64::from(day) - i64::from(self.weeks) * 7;
match day.checked_sub_unsigned(self.days) {
Some(x) => x,
None => {
debug_assert!(false, "{day} - {self:?} out of day range");
i64::MIN
}
}
}
}
}