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}