rbdc_mysql/types/
timestamp.rs

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