opensrv_clickhouse/types/column/
datetime64.rs1use 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}