postgres_types/
chrono_04.rs1use 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}