common_function/scalars/date/
date_format.rs1use std::fmt;
16
17use common_error::ext::BoxedError;
18use common_query::error::{self, InvalidFuncArgsSnafu, Result, UnsupportedInputDataTypeSnafu};
19use datafusion_expr::Signature;
20use datatypes::arrow::datatypes::{DataType, TimeUnit};
21use datatypes::prelude::{ConcreteDataType, MutableVector, ScalarVectorBuilder};
22use datatypes::vectors::{StringVectorBuilder, VectorRef};
23use snafu::{ResultExt, ensure};
24
25use crate::function::{Function, FunctionContext};
26use crate::helper;
27
28#[derive(Clone, Debug, Default)]
30pub struct DateFormatFunction;
31
32const NAME: &str = "date_format";
33
34impl Function for DateFormatFunction {
35 fn name(&self) -> &str {
36 NAME
37 }
38
39 fn return_type(&self, _: &[DataType]) -> Result<DataType> {
40 Ok(DataType::Utf8)
41 }
42
43 fn signature(&self) -> Signature {
44 helper::one_of_sigs2(
45 vec![
46 DataType::Date32,
47 DataType::Timestamp(TimeUnit::Second, None),
48 DataType::Timestamp(TimeUnit::Millisecond, None),
49 DataType::Timestamp(TimeUnit::Microsecond, None),
50 DataType::Timestamp(TimeUnit::Nanosecond, None),
51 ],
52 vec![DataType::Utf8],
53 )
54 }
55
56 fn eval(&self, func_ctx: &FunctionContext, columns: &[VectorRef]) -> Result<VectorRef> {
57 ensure!(
58 columns.len() == 2,
59 InvalidFuncArgsSnafu {
60 err_msg: format!(
61 "The length of the args is not correct, expect 2, have: {}",
62 columns.len()
63 ),
64 }
65 );
66
67 let left = &columns[0];
68 let formats = &columns[1];
69
70 let size = left.len();
71 let left_datatype = columns[0].data_type();
72 let mut results = StringVectorBuilder::with_capacity(size);
73
74 match left_datatype {
75 ConcreteDataType::Timestamp(_) => {
76 for i in 0..size {
77 let ts = left.get(i).as_timestamp();
78 let format = formats.get(i).as_string();
79
80 let result = match (ts, format) {
81 (Some(ts), Some(fmt)) => Some(
82 ts.as_formatted_string(&fmt, Some(&func_ctx.query_ctx.timezone()))
83 .map_err(BoxedError::new)
84 .context(error::ExecuteSnafu)?,
85 ),
86 _ => None,
87 };
88
89 results.push(result.as_deref());
90 }
91 }
92 ConcreteDataType::Date(_) => {
93 for i in 0..size {
94 let date = left.get(i).as_date();
95 let format = formats.get(i).as_string();
96
97 let result = match (date, format) {
98 (Some(date), Some(fmt)) => date
99 .as_formatted_string(&fmt, Some(&func_ctx.query_ctx.timezone()))
100 .map_err(BoxedError::new)
101 .context(error::ExecuteSnafu)?,
102 _ => None,
103 };
104
105 results.push(result.as_deref());
106 }
107 }
108 _ => {
109 return UnsupportedInputDataTypeSnafu {
110 function: NAME,
111 datatypes: columns.iter().map(|c| c.data_type()).collect::<Vec<_>>(),
112 }
113 .fail();
114 }
115 }
116
117 Ok(results.to_vector())
118 }
119}
120
121impl fmt::Display for DateFormatFunction {
122 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
123 write!(f, "DATE_FORMAT")
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use std::sync::Arc;
130
131 use datafusion_expr::{TypeSignature, Volatility};
132 use datatypes::prelude::ScalarVector;
133 use datatypes::value::Value;
134 use datatypes::vectors::{DateVector, StringVector, TimestampSecondVector};
135
136 use super::{DateFormatFunction, *};
137
138 #[test]
139 fn test_date_format_misc() {
140 let f = DateFormatFunction;
141 assert_eq!("date_format", f.name());
142 assert_eq!(
143 DataType::Utf8,
144 f.return_type(&[DataType::Timestamp(TimeUnit::Microsecond, None)])
145 .unwrap()
146 );
147 assert_eq!(
148 DataType::Utf8,
149 f.return_type(&[DataType::Timestamp(TimeUnit::Second, None)])
150 .unwrap()
151 );
152 assert_eq!(DataType::Utf8, f.return_type(&[DataType::Date32]).unwrap());
153 assert!(matches!(f.signature(),
154 Signature {
155 type_signature: TypeSignature::OneOf(sigs),
156 volatility: Volatility::Immutable
157 } if sigs.len() == 5));
158 }
159
160 #[test]
161 fn test_timestamp_date_format() {
162 let f = DateFormatFunction;
163
164 let times = vec![Some(123), None, Some(42), None];
165 let formats = vec![
166 "%Y-%m-%d %T.%3f",
167 "%Y-%m-%d %T.%3f",
168 "%Y-%m-%d %T.%3f",
169 "%Y-%m-%d %T.%3f",
170 ];
171 let results = [
172 Some("1970-01-01 00:02:03.000"),
173 None,
174 Some("1970-01-01 00:00:42.000"),
175 None,
176 ];
177
178 let time_vector = TimestampSecondVector::from(times.clone());
179 let interval_vector = StringVector::from_vec(formats);
180 let args: Vec<VectorRef> = vec![Arc::new(time_vector), Arc::new(interval_vector)];
181 let vector = f.eval(&FunctionContext::default(), &args).unwrap();
182
183 assert_eq!(4, vector.len());
184 for (i, _t) in times.iter().enumerate() {
185 let v = vector.get(i);
186 let result = results.get(i).unwrap();
187
188 if result.is_none() {
189 assert_eq!(Value::Null, v);
190 continue;
191 }
192 match v {
193 Value::String(s) => {
194 assert_eq!(s.as_utf8(), result.unwrap());
195 }
196 _ => unreachable!(),
197 }
198 }
199 }
200
201 #[test]
202 fn test_date_date_format() {
203 let f = DateFormatFunction;
204
205 let dates = vec![Some(123), None, Some(42), None];
206 let formats = vec![
207 "%Y-%m-%d %T.%3f",
208 "%Y-%m-%d %T.%3f",
209 "%Y-%m-%d %T.%3f",
210 "%Y-%m-%d %T.%3f",
211 ];
212 let results = [
213 Some("1970-05-04 00:00:00.000"),
214 None,
215 Some("1970-02-12 00:00:00.000"),
216 None,
217 ];
218
219 let date_vector = DateVector::from(dates.clone());
220 let interval_vector = StringVector::from_vec(formats);
221 let args: Vec<VectorRef> = vec![Arc::new(date_vector), Arc::new(interval_vector)];
222 let vector = f.eval(&FunctionContext::default(), &args).unwrap();
223
224 assert_eq!(4, vector.len());
225 for (i, _t) in dates.iter().enumerate() {
226 let v = vector.get(i);
227 let result = results.get(i).unwrap();
228
229 if result.is_none() {
230 assert_eq!(Value::Null, v);
231 continue;
232 }
233 match v {
234 Value::String(s) => {
235 assert_eq!(s.as_utf8(), result.unwrap());
236 }
237 _ => unreachable!(),
238 }
239 }
240 }
241}