1use diesel::deserialize::FromSql;
4use diesel::deserialize::Result as DeserializeResult;
5use diesel::pg::Pg;
6use diesel::pg::PgValue;
7use diesel::pg::data_types::PgTimestamp;
8use diesel::serialize::Output;
9use diesel::serialize::Result as SerializeResult;
10use diesel::serialize::ToSql;
11use diesel::sql_types;
12
13use crate::DateTime;
14use crate::interval::TimeInterval;
15
16impl ToSql<sql_types::Timestamp, Pg> for DateTime {
17 fn to_sql<'se>(&'se self, out: &mut Output<'se, '_, Pg>) -> SerializeResult {
18 let micros_from_epoch = (*self - PG_EPOCH).as_microseconds();
19 ToSql::<sql_types::Timestamp, Pg>::to_sql(&PgTimestamp(micros_from_epoch), &mut out.reborrow())
20 }
21}
22
23impl ToSql<sql_types::Timestamptz, Pg> for DateTime {
24 fn to_sql<'se>(&'se self, out: &mut Output<'se, '_, Pg>) -> SerializeResult {
25 ToSql::<sql_types::Timestamp, Pg>::to_sql(self, out)
26 }
27}
28
29impl FromSql<sql_types::Timestamp, Pg> for DateTime {
30 fn from_sql(bytes: PgValue<'_>) -> DeserializeResult<Self> {
31 let PgTimestamp(micros) = FromSql::<diesel::sql_types::Timestamp, Pg>::from_sql(bytes)?;
32 let seconds = micros.div_euclid(1_000_000);
33 let micros = match micros.signum() {
34 0 => 0,
35 1 => micros % 1_000_000,
36 -1 => 1_000_000 - (micros % 1_000_000).abs(),
37 _ => unreachable!("signum always returns -1, 0, or 1"),
38 };
39 let duration = TimeInterval::new(seconds, micros as u32 * 1_000);
40 Ok(PG_EPOCH + duration)
41 }
42}
43
44impl FromSql<sql_types::Timestamptz, Pg> for DateTime {
45 fn from_sql(bytes: PgValue<'_>) -> DeserializeResult<Self> {
46 FromSql::<sql_types::Timestamp, Pg>::from_sql(bytes)
47 }
48}
49
50const PG_EPOCH: DateTime = datetime! { 2000-01-01 00:00:00 };