rbdc_mysql/types/
datetime.rs

1use crate::types::date::decode_date_buf;
2use crate::types::time::decode_time;
3use crate::types::{Decode, Encode};
4use crate::value::{MySqlValue, MySqlValueFormat};
5use rbdc::datetime::DateTime;
6use rbdc::Error;
7
8impl Encode for DateTime {
9    fn encode(self, buf: &mut Vec<u8>) -> Result<usize, Error> {
10        let datetime = self.0;
11        let datetime_size = date_time_size_hint(
12            datetime.hour(),
13            datetime.minute(),
14            datetime.sec(),
15            datetime.nano(),
16        );
17        buf.push(datetime_size as u8);
18        let date = rbdc::date::Date(fastdate::Date {
19            day: datetime.day(),
20            mon: datetime.mon(),
21            year: datetime.year(),
22        });
23        let mut size = date.encode(buf)?;
24        buf.remove(buf.len() - (size + 1));
25        if datetime_size > 4 {
26            let time = fastdate::Time {
27                nano: datetime.nano(),
28                sec: datetime.sec(),
29                minute: datetime.minute(),
30                hour: datetime.hour(),
31            };
32            let before_len = buf.len();
33            let encode_len = time.encode(buf)?;
34            if encode_len > 6 {
35                for _ in 0..6 {
36                    buf.remove(before_len);
37                }
38            }
39            let after_len = buf.len();
40            size += after_len - before_len;
41        }
42        Ok(1 + size)
43    }
44}
45
46impl Decode for DateTime {
47    fn decode(value: MySqlValue) -> Result<Self, Error> {
48        Ok(match value.format() {
49            MySqlValueFormat::Text => Self({
50                let s = value.as_str()?;
51                fastdate::DateTime::from_str_default(s, value.option.offset_sec)
52                    .map_err(|e| Error::from(e.to_string()))?
53            }),
54            MySqlValueFormat::Binary => {
55                let buf = value.as_bytes()?;
56                let len = buf[0];
57                let date = decode_date_buf(&buf[1..])?;
58                let time = if len > 4 {
59                    decode_time(&buf[5..])
60                } else {
61                    fastdate::Time {
62                        nano: 0,
63                        sec: 0,
64                        minute: 0,
65                        hour: 0,
66                    }
67                };
68                let v = fastdate::DateTime::from((date, time, value.option.offset_sec));
69                Self(v)
70            }
71        })
72    }
73}
74
75fn date_time_size_hint(hour: u8, min: u8, sec: u8, nano: u32) -> usize {
76    // to save space the packet can be compressed:
77    match (hour, min, sec, nano) {
78        // if hour, minutes, seconds and micro_seconds are all 0,
79        // length is 4 and no other field is sent
80        (0, 0, 0, 0) => 4,
81
82        // if micro_seconds is 0, length is 7
83        // and micro_seconds is not sent
84        (_, _, _, 0) => 7,
85
86        // otherwise length is 11
87        (_, _, _, _) => 11,
88    }
89}