datetime/
diesel_pg.rs

1//! Serialization to/from PostgreSQL
2
3use 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 };