1use std::ops::{Add, AddAssign, Deref};
2
3use chrono::{DateTime, Duration, NaiveDateTime, TimeDelta, Utc};
4use chrono_tz::Tz;
5use diesel::backend::Backend;
6use diesel::deserialize::{self, FromSql, FromSqlRow};
7use diesel::expression::AsExpression;
8use diesel::mysql::Mysql;
9use diesel::serialize::{self, Output, ToSql};
10use diesel::sql_types::Datetime;
11use serde::{Deserialize, Serialize};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromSqlRow, AsExpression)]
15#[diesel(sql_type = Datetime)]
16pub struct CustomDateTime(NaiveDateTime);
17
18impl CustomDateTime {
20 pub fn inner(&self) -> NaiveDateTime {
22 self.0
23 }
24
25 pub fn now() -> Self {
27 CustomDateTime(chrono::Local::now().naive_local())
28 }
29}
30
31impl From<NaiveDateTime> for CustomDateTime {
33 fn from(dt: NaiveDateTime) -> Self {
35 CustomDateTime(dt)
36 }
37}
38
39impl FromSql<Datetime, Mysql> for CustomDateTime {
41 fn from_sql<'a>(bytes: <Mysql as Backend>::RawValue<'a>) -> deserialize::Result<Self> {
43 let utc_dt = <NaiveDateTime as FromSql<Datetime, Mysql>>::from_sql(bytes)?;
44 let barcelona_tz: Tz = "Europe/Madrid".parse().unwrap();
45 let utc_datetime: DateTime<Utc> = DateTime::from_naive_utc_and_offset(utc_dt, Utc);
46 let barcelona_datetime = utc_datetime.with_timezone(&barcelona_tz);
47 Ok(CustomDateTime(barcelona_datetime.naive_local()))
48 }
49}
50
51impl<DB> ToSql<Datetime, DB> for CustomDateTime
53where
54 DB: Backend,
55 NaiveDateTime: ToSql<Datetime, DB>,
56{
57 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
59 self.0.to_sql(out)
61 }
62}
63
64impl Deref for CustomDateTime {
66 type Target = NaiveDateTime;
68
69 fn deref(&self) -> &Self::Target {
71 &self.0
72 }
73}
74
75impl AddAssign<TimeDelta> for CustomDateTime {
77 fn add_assign(&mut self, other: TimeDelta) {
79 self.0 += other;
80 }
81}
82
83impl Add<Duration> for CustomDateTime {
85 type Output = Self;
87
88 fn add(mut self, other: Duration) -> Self {
90 self.0 += other;
91 self
92 }
93}
94
95impl Serialize for CustomDateTime {
97 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
99 where
100 S: serde::Serializer,
101 {
102 self.0.serialize(serializer)
103 }
104}
105
106impl<'de> Deserialize<'de> for CustomDateTime {
108 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
110 where
111 D: serde::Deserializer<'de>,
112 {
113 let naive_dt = NaiveDateTime::deserialize(deserializer)?;
114 let barcelona_tz: Tz = "Europe/Madrid".parse().unwrap();
115 let utc_datetime: DateTime<Utc> = DateTime::from_naive_utc_and_offset(naive_dt, Utc);
116 let barcelona_datetime = utc_datetime.with_timezone(&barcelona_tz);
117 Ok(CustomDateTime(barcelona_datetime.naive_local()))
118 }
119}