opensrv_clickhouse/types/column/
datetime64.rs

1// Copyright 2021 Datafuse Labs.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use chrono::prelude::*;
16use chrono_tz::Tz;
17
18use crate::binary::Encoder;
19use crate::binary::ReadEx;
20use crate::errors::Result;
21use crate::types::column::column_data::BoxColumnData;
22use crate::types::column::column_data::ColumnData;
23use crate::types::column::list::List;
24use crate::types::DateTimeType;
25use crate::types::SqlType;
26use crate::types::Value;
27use crate::types::ValueRef;
28
29pub struct DateTime64ColumnData {
30    data: List<i64>,
31    params: (u32, Tz),
32}
33
34impl DateTime64ColumnData {
35    pub(crate) fn load<R: ReadEx>(
36        reader: &mut R,
37        size: usize,
38        precision: u32,
39        tz: Tz,
40    ) -> Result<DateTime64ColumnData> {
41        let mut data = List::with_capacity(size);
42        unsafe {
43            data.set_len(size);
44        }
45        reader.read_bytes(data.as_mut())?;
46        Ok(DateTime64ColumnData {
47            data,
48            params: (precision, tz),
49        })
50    }
51
52    pub(crate) fn with_capacity(capacity: usize, precision: u32, timezone: Tz) -> Self {
53        DateTime64ColumnData {
54            data: List::with_capacity(capacity),
55            params: (precision, timezone),
56        }
57    }
58}
59
60impl ColumnData for DateTime64ColumnData {
61    fn sql_type(&self) -> SqlType {
62        let (precision, tz) = self.params;
63        SqlType::DateTime(DateTimeType::DateTime64(precision, tz))
64    }
65
66    fn save(&self, encoder: &mut Encoder, start: usize, end: usize) {
67        for i in start..end {
68            encoder.write(self.data.at(i));
69        }
70    }
71
72    fn len(&self) -> usize {
73        self.data.len()
74    }
75
76    fn push(&mut self, value: Value) {
77        let (precision, tz) = &self.params;
78        let time = DateTime::<Tz>::from(value);
79        let stamp = from_datetime(time.with_timezone(tz), *precision);
80        self.data.push(stamp)
81    }
82
83    fn at(&self, index: usize) -> ValueRef {
84        let value = self.data.at(index);
85        ValueRef::DateTime64(value, &self.params)
86    }
87
88    fn clone_instance(&self) -> BoxColumnData {
89        Box::new(Self {
90            data: self.data.clone(),
91            params: self.params,
92        })
93    }
94
95    unsafe fn get_internal(&self, pointers: &[*mut *const u8], level: u8) -> Result<()> {
96        assert_eq!(level, 0);
97        let (precision, tz) = &self.params;
98        *pointers[0] = self.data.as_ptr() as *const u8;
99        *pointers[1] = tz as *const Tz as *const u8;
100        *(pointers[2] as *mut usize) = self.len();
101        *(pointers[3] as *mut Option<u32>) = Some(*precision);
102        Ok(())
103    }
104}
105
106pub fn from_datetime<T: chrono::offset::TimeZone>(time: DateTime<T>, precision: u32) -> i64 {
107    let base10: i64 = 10;
108    let timestamp = time.timestamp_nanos_opt().unwrap();
109    timestamp / base10.pow(9 - precision)
110}
111
112#[inline(always)]
113pub fn to_datetime(value: i64, precision: u32, tz: Tz) -> DateTime<Tz> {
114    let base10: i64 = 10;
115
116    let nano = if precision < 19 {
117        value * base10.pow(9 - precision)
118    } else {
119        0_i64
120    };
121
122    let sec = nano / 1_000_000_000;
123    let nsec = nano - sec * 1_000_000_000;
124
125    tz.timestamp_opt(sec, nsec as u32).unwrap()
126}