use core::{ num::TryFromIntError, ops::{Add, Sub}, }; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, Serialize, Deserialize)] #[serde(transparent)] pub struct NumericDate(pub i64); impl NumericDate { #[cfg(feature = "chrono")] pub fn from_chrono_date_time(dt: chrono::DateTime) -> Self { Self(dt.timestamp()) } #[cfg(feature = "chrono")] pub fn from_chrono_naive_date_time(ndt: chrono::NaiveDateTime) -> Self { Self(ndt.timestamp()) } #[cfg(feature = "time")] pub fn from_primitive_date_time(pdt: time::PrimitiveDateTime) -> Self { Self(pdt.assume_utc().unix_timestamp()) } } #[cfg(feature = "std")] impl NumericDate { pub fn now() -> Self { Self(std::time::UNIX_EPOCH.elapsed().unwrap().as_secs() as i64) } } #[cfg(feature = "time")] impl From for NumericDate { fn from(pdt: time::PrimitiveDateTime) -> Self { Self::from_primitive_date_time(pdt) } } #[cfg(feature = "chrono")] impl From for NumericDate { fn from(dt: chrono::NaiveDateTime) -> Self { Self::from_chrono_naive_date_time(dt) } } #[cfg(feature = "chrono")] impl From> for NumericDate { fn from(dt: chrono::DateTime) -> Self { Self::from_chrono_date_time(dt) } } #[cfg(feature = "chrono")] impl Add for NumericDate { type Output = Self; fn add(self, rhs: chrono::Duration) -> Self::Output { Self(self.0 + rhs.num_seconds()) } } #[cfg(feature = "time")] impl Add for NumericDate { type Output = Self; fn add(self, rhs: time::Duration) -> Self::Output { Self(self.0 + rhs.whole_seconds()) } } #[cfg(feature = "chrono")] impl Sub for NumericDate { type Output = Self; fn sub(self, rhs: chrono::Duration) -> Self::Output { Self(self.0 - rhs.num_seconds()) } } #[cfg(feature = "time")] impl Sub for NumericDate { type Output = Self; fn sub(self, rhs: time::Duration) -> Self::Output { Self(self.0 - rhs.whole_seconds()) } } impl From for NumericDate { fn from(i: i64) -> Self { Self(i) } } impl TryFrom for NumericDate { type Error = TryFromIntError; fn try_from(u: u64) -> Result { Ok(Self(u64::try_from(i64::try_from(u)?)? as i64)) } } impl Add for NumericDate { type Output = Self; fn add(self, rhs: core::time::Duration) -> Self::Output { // TODO: not a fan of this but at the same time, if the duration exceeds the // range of i64, something has likely gone incredibly wrong on the caller's end // that needs to be addressed. match i64::try_from(rhs.as_secs()) { Ok(i) => Self(self.0 + i), Err(err) => panic!("duration too large to convert to i64: {err}"), } } } impl Sub for NumericDate { type Output = Self; fn sub(self, rhs: core::time::Duration) -> Self::Output { // TODO: not a fan of this but at the same time, if the duration exceeds the // range of i64, something has likely gone incredibly wrong on the caller's end // that needs to be addressed. match i64::try_from(rhs.as_secs()) { Ok(i) => Self(self.0 - i), Err(err) => panic!("duration too large to convert to i64: {err}"), } } } impl PartialEq for NumericDate { fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } impl Eq for NumericDate {} impl PartialEq<&Self> for NumericDate { fn eq(&self, other: &&Self) -> bool { self.0 == other.0 } } impl PartialOrd for NumericDate { fn partial_cmp(&self, other: &Self) -> Option { self.0.partial_cmp(&other.0) } } impl PartialOrd<&Self> for NumericDate { fn partial_cmp(&self, other: &&Self) -> Option { self.0.partial_cmp(&other.0) } } impl Ord for NumericDate { fn cmp(&self, other: &Self) -> core::cmp::Ordering { self.0.cmp(&other.0) } } impl Sub for NumericDate { type Output = Self; fn sub(self, rhs: i64) -> Self::Output { Self(self.0 - rhs) } } impl Sub for NumericDate { type Output = Self; fn sub(self, rhs: u64) -> Self::Output { Self(self.0 - rhs as i64) } } impl Sub for NumericDate { type Output = Self; fn sub(self, rhs: i32) -> Self::Output { Self(self.0 - rhs as i64) } } impl Sub for NumericDate { type Output = Self; fn sub(self, rhs: usize) -> Self::Output { Self(self.0 - rhs as i64) } } impl Sub for NumericDate { type Output = Self; fn sub(self, rhs: u32) -> Self::Output { Self(self.0 - rhs as i64) } } impl Sub for NumericDate { type Output = Self; fn sub(self, rhs: i16) -> Self::Output { Self(self.0 - rhs as i64) } } impl Sub for NumericDate { type Output = Self; fn sub(self, rhs: u16) -> Self::Output { Self(self.0 - rhs as i64) } } impl Sub for NumericDate { type Output = Self; fn sub(self, rhs: i8) -> Self::Output { Self(self.0 - rhs as i64) } } impl Add for NumericDate { type Output = Self; fn add(self, rhs: i64) -> Self::Output { Self(self.0 + rhs) } } impl Sub for NumericDate { type Output = Self; fn sub(self, rhs: u8) -> Self::Output { Self(self.0 - rhs as i64) } } impl Add for NumericDate { type Output = Self; fn add(self, rhs: u64) -> Self::Output { Self(self.0 + rhs as i64) } } impl Add for NumericDate { type Output = Self; fn add(self, rhs: i32) -> Self::Output { Self(self.0 + rhs as i64) } } impl Add for NumericDate { type Output = Self; fn add(self, rhs: usize) -> Self::Output { Self(self.0 + rhs as i64) } } impl Add for NumericDate { type Output = Self; fn add(self, rhs: u32) -> Self::Output { Self(self.0 + rhs as i64) } } impl Add for NumericDate { type Output = Self; fn add(self, rhs: i16) -> Self::Output { Self(self.0 + rhs as i64) } } impl Add for NumericDate { type Output = Self; fn add(self, rhs: u16) -> Self::Output { Self(self.0 + rhs as i64) } } impl Add for NumericDate { type Output = Self; fn add(self, rhs: i8) -> Self::Output { Self(self.0 + rhs as i64) } } impl Add for NumericDate { type Output = Self; fn add(self, rhs: u8) -> Self::Output { Self(self.0 + rhs as i64) } }