postgres_types/
chrono_04.rs

1use bytes::BytesMut;
2use chrono_04::{
3    DateTime, Duration, FixedOffset, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc,
4};
5use postgres_protocol::types;
6use std::error::Error;
7
8use crate::{FromSql, IsNull, ToSql, Type};
9
10fn base() -> NaiveDateTime {
11    NaiveDate::from_ymd_opt(2000, 1, 1)
12        .unwrap()
13        .and_hms_opt(0, 0, 0)
14        .unwrap()
15}
16
17impl<'a> FromSql<'a> for NaiveDateTime {
18    fn from_sql(_: &Type, raw: &[u8]) -> Result<NaiveDateTime, Box<dyn Error + Sync + Send>> {
19        let t = types::timestamp_from_sql(raw)?;
20        base()
21            .checked_add_signed(Duration::microseconds(t))
22            .ok_or_else(|| "value too large to decode".into())
23    }
24
25    accepts!(TIMESTAMP);
26}
27
28impl ToSql for NaiveDateTime {
29    fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
30        let time = match self.signed_duration_since(base()).num_microseconds() {
31            Some(time) => time,
32            None => return Err("value too large to transmit".into()),
33        };
34        types::timestamp_to_sql(time, w);
35        Ok(IsNull::No)
36    }
37
38    accepts!(TIMESTAMP);
39    to_sql_checked!();
40}
41
42impl<'a> FromSql<'a> for DateTime<Utc> {
43    fn from_sql(type_: &Type, raw: &[u8]) -> Result<DateTime<Utc>, Box<dyn Error + Sync + Send>> {
44        let naive = NaiveDateTime::from_sql(type_, raw)?;
45        Ok(Utc.from_utc_datetime(&naive))
46    }
47
48    accepts!(TIMESTAMPTZ);
49}
50
51impl ToSql for DateTime<Utc> {
52    fn to_sql(
53        &self,
54        type_: &Type,
55        w: &mut BytesMut,
56    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
57        self.naive_utc().to_sql(type_, w)
58    }
59
60    accepts!(TIMESTAMPTZ);
61    to_sql_checked!();
62}
63
64impl<'a> FromSql<'a> for DateTime<Local> {
65    fn from_sql(type_: &Type, raw: &[u8]) -> Result<DateTime<Local>, Box<dyn Error + Sync + Send>> {
66        let utc = DateTime::<Utc>::from_sql(type_, raw)?;
67        Ok(utc.with_timezone(&Local))
68    }
69
70    accepts!(TIMESTAMPTZ);
71}
72
73impl ToSql for DateTime<Local> {
74    fn to_sql(
75        &self,
76        type_: &Type,
77        w: &mut BytesMut,
78    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
79        self.with_timezone(&Utc).to_sql(type_, w)
80    }
81
82    accepts!(TIMESTAMPTZ);
83    to_sql_checked!();
84}
85
86impl<'a> FromSql<'a> for DateTime<FixedOffset> {
87    fn from_sql(
88        type_: &Type,
89        raw: &[u8],
90    ) -> Result<DateTime<FixedOffset>, Box<dyn Error + Sync + Send>> {
91        let utc = DateTime::<Utc>::from_sql(type_, raw)?;
92        Ok(utc.with_timezone(&FixedOffset::east_opt(0).unwrap()))
93    }
94
95    accepts!(TIMESTAMPTZ);
96}
97
98impl ToSql for DateTime<FixedOffset> {
99    fn to_sql(
100        &self,
101        type_: &Type,
102        w: &mut BytesMut,
103    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
104        self.with_timezone(&Utc).to_sql(type_, w)
105    }
106
107    accepts!(TIMESTAMPTZ);
108    to_sql_checked!();
109}
110
111impl<'a> FromSql<'a> for NaiveDate {
112    fn from_sql(_: &Type, raw: &[u8]) -> Result<NaiveDate, Box<dyn Error + Sync + Send>> {
113        let jd = types::date_from_sql(raw)?;
114        base()
115            .date()
116            .checked_add_signed(Duration::days(i64::from(jd)))
117            .ok_or_else(|| "value too large to decode".into())
118    }
119
120    accepts!(DATE);
121}
122
123impl ToSql for NaiveDate {
124    fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
125        let jd = self.signed_duration_since(base().date()).num_days();
126        let jd = i32::try_from(jd).map_err(|_| "value too large to transmit")?;
127
128        types::date_to_sql(jd, w);
129        Ok(IsNull::No)
130    }
131
132    accepts!(DATE);
133    to_sql_checked!();
134}
135
136impl<'a> FromSql<'a> for NaiveTime {
137    fn from_sql(_: &Type, raw: &[u8]) -> Result<NaiveTime, Box<dyn Error + Sync + Send>> {
138        let usec = types::time_from_sql(raw)?;
139        Ok(NaiveTime::from_hms_opt(0, 0, 0).unwrap() + Duration::microseconds(usec))
140    }
141
142    accepts!(TIME);
143}
144
145impl ToSql for NaiveTime {
146    fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
147        let delta = self.signed_duration_since(NaiveTime::from_hms_opt(0, 0, 0).unwrap());
148        let time = match delta.num_microseconds() {
149            Some(time) => time,
150            None => return Err("value too large to transmit".into()),
151        };
152        types::time_to_sql(time, w);
153        Ok(IsNull::No)
154    }
155
156    accepts!(TIME);
157    to_sql_checked!();
158}