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::try_days(i64::from(jd)).unwrap())
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        if jd > i64::from(i32::max_value()) || jd < i64::from(i32::min_value()) {
127            return Err("value too large to transmit".into());
128        }
129
130        types::date_to_sql(jd as i32, w);
131        Ok(IsNull::No)
132    }
133
134    accepts!(DATE);
135    to_sql_checked!();
136}
137
138impl<'a> FromSql<'a> for NaiveTime {
139    fn from_sql(_: &Type, raw: &[u8]) -> Result<NaiveTime, Box<dyn Error + Sync + Send>> {
140        let usec = types::time_from_sql(raw)?;
141        Ok(NaiveTime::from_hms_opt(0, 0, 0).unwrap() + Duration::microseconds(usec))
142    }
143
144    accepts!(TIME);
145}
146
147impl ToSql for NaiveTime {
148    fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
149        let delta = self.signed_duration_since(NaiveTime::from_hms_opt(0, 0, 0).unwrap());
150        let time = match delta.num_microseconds() {
151            Some(time) => time,
152            None => return Err("value too large to transmit".into()),
153        };
154        types::time_to_sql(time, w);
155        Ok(IsNull::No)
156    }
157
158    accepts!(TIME);
159    to_sql_checked!();
160}