mysql_common/value/convert/
chrono.rs

1// Copyright (c) 2021 Anatoly Ikorsky
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9//! This module implements conversion from/to `Value` for `chrono` types.
10
11#![cfg(feature = "chrono")]
12
13use std::convert::TryFrom;
14
15use chrono::{Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike};
16
17use crate::value::Value;
18
19use super::{
20    parse_mysql_datetime_string, parse_mysql_time_string, FromValue, FromValueError, ParseIr,
21};
22
23#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
24impl FromValue for NaiveDate {
25    type Intermediate = ParseIr<NaiveDate>;
26}
27
28#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
29impl FromValue for NaiveTime {
30    type Intermediate = ParseIr<NaiveTime>;
31}
32
33#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
34impl FromValue for NaiveDateTime {
35    type Intermediate = ParseIr<NaiveDateTime>;
36}
37
38#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
39impl TryFrom<Value> for ParseIr<NaiveDateTime> {
40    type Error = FromValueError;
41
42    fn try_from(v: Value) -> Result<Self, Self::Error> {
43        match v {
44            Value::Date(year, month, day, hour, minute, second, micros) => {
45                let date = NaiveDate::from_ymd_opt(year.into(), month.into(), day.into());
46                let time = NaiveTime::from_hms_micro_opt(
47                    hour.into(),
48                    minute.into(),
49                    second.into(),
50                    micros,
51                );
52                if let Some((date, time)) = date.zip(time) {
53                    Ok(ParseIr(NaiveDateTime::new(date, time), v))
54                } else {
55                    Err(FromValueError(v))
56                }
57            }
58            Value::Bytes(ref bytes) => {
59                if let Some((year, month, day, hour, minute, second, micros)) =
60                    parse_mysql_datetime_string(bytes)
61                {
62                    let date = NaiveDate::from_ymd_opt(year as i32, month, day);
63                    let time = NaiveTime::from_hms_micro_opt(hour, minute, second, micros);
64                    if let Some((date, time)) = date.zip(time) {
65                        Ok(ParseIr(NaiveDateTime::new(date, time), v))
66                    } else {
67                        Err(FromValueError(v))
68                    }
69                } else {
70                    Err(FromValueError(v))
71                }
72            }
73            _ => Err(FromValueError(v)),
74        }
75    }
76}
77
78#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
79impl TryFrom<Value> for ParseIr<NaiveDate> {
80    type Error = FromValueError;
81
82    fn try_from(v: Value) -> Result<Self, Self::Error> {
83        let result = match v {
84            Value::Date(year, month, day, hour, minute, second, micros) => {
85                let date = NaiveDate::from_ymd_opt(year.into(), month.into(), day.into());
86                Ok((
87                    date,
88                    Value::Date(year, month, day, hour, minute, second, micros),
89                ))
90            }
91            Value::Bytes(bytes) => {
92                if let Some((y, m, d, _, _, _, _)) = parse_mysql_datetime_string(&*bytes) {
93                    let date = NaiveDate::from_ymd_opt(y as i32, m, d);
94                    Ok((date, Value::Bytes(bytes)))
95                } else {
96                    Err(FromValueError(Value::Bytes(bytes)))
97                }
98            }
99            v => Err(FromValueError(v)),
100        };
101
102        let (date, value) = result?;
103
104        if let Some(output) = date {
105            Ok(ParseIr(output, value))
106        } else {
107            Err(FromValueError(value))
108        }
109    }
110}
111
112#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
113impl TryFrom<Value> for ParseIr<NaiveTime> {
114    type Error = FromValueError;
115
116    fn try_from(v: Value) -> Result<Self, Self::Error> {
117        let result = match v {
118            Value::Time(false, 0, h, m, s, u) => {
119                let time = NaiveTime::from_hms_micro_opt(h.into(), m.into(), s.into(), u);
120                Ok((time, Value::Time(false, 0, h, m, s, u)))
121            }
122            Value::Bytes(bytes) => {
123                if let Some((false, h, m, s, u)) = parse_mysql_time_string(&*bytes) {
124                    let time = NaiveTime::from_hms_micro_opt(h, m as u32, s as u32, u);
125                    Ok((time, Value::Bytes(bytes)))
126                } else {
127                    Err(FromValueError(Value::Bytes(bytes)))
128                }
129            }
130            v => Err(FromValueError(v)),
131        };
132
133        let (time, value) = result?;
134
135        if let Some(output) = time {
136            Ok(ParseIr(output, value))
137        } else {
138            Err(FromValueError(value))
139        }
140    }
141}
142
143#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
144impl From<ParseIr<NaiveDateTime>> for NaiveDateTime {
145    fn from(value: ParseIr<NaiveDateTime>) -> Self {
146        value.commit()
147    }
148}
149
150#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
151impl From<ParseIr<NaiveDate>> for NaiveDate {
152    fn from(value: ParseIr<NaiveDate>) -> Self {
153        value.commit()
154    }
155}
156
157#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
158impl From<ParseIr<NaiveTime>> for NaiveTime {
159    fn from(value: ParseIr<NaiveTime>) -> Self {
160        value.commit()
161    }
162}
163
164#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
165impl From<ParseIr<NaiveDateTime>> for Value {
166    fn from(value: ParseIr<NaiveDateTime>) -> Self {
167        value.rollback()
168    }
169}
170
171#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
172impl From<ParseIr<NaiveDate>> for Value {
173    fn from(value: ParseIr<NaiveDate>) -> Self {
174        value.rollback()
175    }
176}
177
178#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
179impl From<ParseIr<NaiveTime>> for Value {
180    fn from(value: ParseIr<NaiveTime>) -> Self {
181        value.rollback()
182    }
183}
184
185#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
186impl From<NaiveDateTime> for Value {
187    fn from(x: NaiveDateTime) -> Value {
188        if 1000 > x.year() || x.year() > 9999 {
189            panic!("Year `{}` not in supported range [1000, 9999]", x.year())
190        }
191        Value::Date(
192            x.year() as u16,
193            x.month() as u8,
194            x.day() as u8,
195            x.hour() as u8,
196            x.minute() as u8,
197            x.second() as u8,
198            x.nanosecond() / 1000,
199        )
200    }
201}
202
203#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
204impl From<NaiveDate> for Value {
205    fn from(x: NaiveDate) -> Value {
206        if 1000 > x.year() || x.year() > 9999 {
207            panic!("Year `{}` not in supported range [1000, 9999]", x.year())
208        }
209        Value::Date(x.year() as u16, x.month() as u8, x.day() as u8, 0, 0, 0, 0)
210    }
211}
212
213#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
214impl From<NaiveTime> for Value {
215    fn from(x: NaiveTime) -> Value {
216        Value::Time(
217            false,
218            0,
219            x.hour() as u8,
220            x.minute() as u8,
221            x.second() as u8,
222            x.nanosecond() / 1000,
223        )
224    }
225}