use std::{
fmt,
time::{Duration, SystemTime, UNIX_EPOCH},
};
use diesel::deserialize::FromSql;
use diesel::serialize::ToSql;
use diesel::{AsExpression, FromSqlRow, pg, sql_types};
use salvo::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(
ToSchema,
FromSqlRow,
AsExpression,
Default,
Clone,
Copy,
Hash,
PartialEq,
Eq,
PartialOrd,
Ord,
Deserialize,
Serialize,
)]
#[diesel(sql_type = sql_types::Bigint)]
#[allow(clippy::exhaustive_structs)]
#[serde(transparent)]
pub struct UnixMillis(pub u64);
impl fmt::Display for UnixMillis {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl UnixMillis {
pub fn from_system_time(time: SystemTime) -> Option<Self> {
let duration = time.duration_since(UNIX_EPOCH).ok()?;
let millis = duration.as_millis().try_into().ok()?;
Some(Self(millis))
}
pub fn now() -> Self {
Self::from_system_time(SystemTime::now()).expect("date out of range")
}
pub fn to_system_time(self) -> Option<SystemTime> {
UNIX_EPOCH.checked_add(Duration::from_millis(self.0.into()))
}
pub fn get(&self) -> u64 {
self.0
}
pub fn as_secs(&self) -> u64 {
self.0 / 1000
}
}
impl fmt::Debug for UnixMillis {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "UnixMillis({})", self.0)
}
}
impl FromSql<sql_types::BigInt, pg::Pg> for UnixMillis {
fn from_sql(bytes: diesel::pg::PgValue<'_>) -> diesel::deserialize::Result<Self> {
let value = <i64 as diesel::deserialize::FromSql<diesel::sql_types::BigInt, diesel::pg::Pg>>::from_sql(bytes)?;
Ok(Self(value as u64))
}
}
impl ToSql<sql_types::BigInt, pg::Pg> for UnixMillis {
fn to_sql(&self, out: &mut diesel::serialize::Output<'_, '_, pg::Pg>) -> diesel::serialize::Result {
ToSql::<sql_types::BigInt, pg::Pg>::to_sql(&(self.0 as i64), &mut out.reborrow())
}
}
#[derive(
ToSchema, FromSqlRow, AsExpression, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize,
)]
#[diesel(sql_type = sql_types::Bigint)]
#[allow(clippy::exhaustive_structs)]
#[serde(transparent)]
pub struct UnixSeconds(pub u64);
impl UnixSeconds {
pub fn from_system_time(time: SystemTime) -> Option<Self> {
let duration = time.duration_since(UNIX_EPOCH).ok()?;
let millis = duration.as_secs().try_into().ok()?;
Some(Self(millis))
}
pub fn now() -> Self {
return Self::from_system_time(SystemTime::now()).expect("date out of range");
}
pub fn to_system_time(self) -> Option<SystemTime> {
UNIX_EPOCH.checked_add(Duration::from_secs(self.0.into()))
}
pub fn get(&self) -> u64 {
self.0
}
}
impl fmt::Debug for UnixSeconds {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "UnixSeconds({})", self.0)
}
}
impl FromSql<sql_types::BigInt, pg::Pg> for UnixSeconds {
fn from_sql(bytes: diesel::pg::PgValue<'_>) -> diesel::deserialize::Result<Self> {
let value = <i64 as diesel::deserialize::FromSql<diesel::sql_types::BigInt, diesel::pg::Pg>>::from_sql(bytes)?;
Ok(Self(value as u64))
}
}
impl ToSql<sql_types::BigInt, pg::Pg> for UnixSeconds {
fn to_sql(&self, out: &mut diesel::serialize::Output<'_, '_, pg::Pg>) -> diesel::serialize::Result {
ToSql::<sql_types::BigInt, pg::Pg>::to_sql(&(self.0 as i64), &mut out.reborrow())
}
}