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 => Self(
47                fastdate::DateTime::from_str(value.as_str()?)
48                    .map_err(|e| Error::from(e.to_string()))?
49                    .unix_timestamp_millis(),
50            ),
51            MySqlValueFormat::Binary => {
52                let buf = value.as_bytes()?;
53                let len = buf[0];
54                let date = decode_date_buf(&buf[1..])?;
55                let time = if len > 4 {
56                    decode_time(&buf[5..])
57                } else {
58                    fastdate::Time {
59                        nano: 0,
60                        sec: 0,
61                        minute: 0,
62                        hour: 0,
63                    }
64                };
65                Self(fastdate::DateTime::from((date, time)).unix_timestamp_millis())
66            }
67        })
68    }
69}
70
71fn date_time_size_hint(hour: u8, min: u8, sec: u8, nano: u32) -> usize {
72    // to save space the packet can be compressed:
73    match (hour, min, sec, nano) {
74        // if hour, minutes, seconds and micro_seconds are all 0,
75        // length is 4 and no other field is sent
76        (0, 0, 0, 0) => 4,
77
78        // if micro_seconds is 0, length is 7
79        // and micro_seconds is not sent
80        (_, _, _, 0) => 7,
81
82        // otherwise length is 11
83        (_, _, _, _) => 11,
84    }
85}