use chrono::{DateTime, Duration, Local, TimeZone};
use rocket::serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
#[derive(Debug, Clone)]
pub struct StripeDate(DateTime<Local>);
impl StripeDate {
pub fn new(timestamp: i64) -> Self {
Self(Local.timestamp_opt(timestamp, 0).unwrap())
}
pub fn into_inner(self) -> DateTime<Local> {
self.0
}
pub fn relative_time(&self) -> String {
let duration = Local::now() - self.0;
match duration {
d if d < Duration::minutes(1) => "just now".to_string(),
d if d < Duration::hours(1) => format!("{} minutes ago", d.num_minutes()),
d if d < Duration::days(1) => format!("{} hours ago", d.num_hours()),
d if d < Duration::days(7) => format!("{} days ago", d.num_days()),
d if d < Duration::days(30) => format!("{} weeks ago", d.num_weeks()),
d if d < Duration::days(365) => format!("{} months ago", d.num_days() / 30),
d => format!("{} years ago", d.num_days() / 365),
}
}
}
impl fmt::Display for StripeDate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0.format("%Y-%m-%d %H:%M:%S %Z"))
}
}
impl<'de> Deserialize<'de> for StripeDate {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let timestamp = i64::deserialize(deserializer)?;
Ok(StripeDate::new(timestamp))
}
}
impl Serialize for StripeDate {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_i64(self.0.timestamp())
}
}