@@ -20,7 +20,9 @@ use common_query::error;
2020use common_time:: { Date , Timestamp } ;
2121use datafusion_common:: DataFusionError ;
2222use datafusion_common:: arrow:: array:: { Array , AsArray , StringViewBuilder } ;
23- use datafusion_common:: arrow:: datatypes:: { ArrowTimestampType , DataType , Date32Type , TimeUnit } ;
23+ use datafusion_common:: arrow:: datatypes:: {
24+ ArrowTimestampType , DataType , Date32Type , Date64Type , TimeUnit ,
25+ } ;
2426use datafusion_expr:: { ColumnarValue , ScalarFunctionArgs , Signature } ;
2527use snafu:: ResultExt ;
2628
@@ -40,6 +42,7 @@ impl Default for DateFormatFunction {
4042 signature : helper:: one_of_sigs2 (
4143 vec ! [
4244 DataType :: Date32 ,
45+ DataType :: Date64 ,
4346 DataType :: Timestamp ( TimeUnit :: Second , None ) ,
4447 DataType :: Timestamp ( TimeUnit :: Millisecond , None ) ,
4548 DataType :: Timestamp ( TimeUnit :: Microsecond , None ) ,
@@ -115,6 +118,29 @@ impl Function for DateFormatFunction {
115118 builder. append_option ( result. as_deref ( ) ) ;
116119 }
117120 }
121+ DataType :: Date64 => {
122+ let left = left. as_primitive :: < Date64Type > ( ) ;
123+ for i in 0 ..size {
124+ let date = left. is_valid ( i) . then ( || {
125+ let ms = left. value ( i) ;
126+ Timestamp :: new_millisecond ( ms)
127+ } ) ;
128+ let format = formats. is_valid ( i) . then ( || formats. value ( i) ) ;
129+
130+ let result = match ( date, format) {
131+ ( Some ( ts) , Some ( fmt) ) => {
132+ Some ( ts. as_formatted_string ( fmt, Some ( timezone) ) . map_err ( |e| {
133+ DataFusionError :: Execution ( format ! (
134+ "cannot format {ts:?} as '{fmt}': {e}"
135+ ) )
136+ } ) ?)
137+ }
138+ _ => None ,
139+ } ;
140+
141+ builder. append_option ( result. as_deref ( ) ) ;
142+ }
143+ }
118144 x => {
119145 return Err ( DataFusionError :: Execution ( format ! (
120146 "unsupported input data type {x}"
@@ -137,7 +163,9 @@ mod tests {
137163 use std:: sync:: Arc ;
138164
139165 use arrow_schema:: Field ;
140- use datafusion_common:: arrow:: array:: { Date32Array , StringArray , TimestampSecondArray } ;
166+ use datafusion_common:: arrow:: array:: {
167+ Date32Array , Date64Array , StringArray , TimestampSecondArray ,
168+ } ;
141169 use datafusion_common:: config:: ConfigOptions ;
142170 use datafusion_expr:: { TypeSignature , Volatility } ;
143171
@@ -166,7 +194,7 @@ mod tests {
166194 Signature {
167195 type_signature: TypeSignature :: OneOf ( sigs) ,
168196 volatility: Volatility :: Immutable
169- } if sigs. len( ) == 5 ) ) ;
197+ } if sigs. len( ) == 6 ) ) ;
170198 }
171199
172200 #[ test]
@@ -213,6 +241,50 @@ mod tests {
213241 }
214242 }
215243
244+ #[ test]
245+ fn test_date64_date_format ( ) {
246+ let f = DateFormatFunction :: default ( ) ;
247+
248+ let dates = vec ! [ Some ( 123000 ) , None , Some ( 42000 ) , None ] ;
249+ let formats = vec ! [
250+ "%Y-%m-%d %T.%3f" ,
251+ "%Y-%m-%d %T.%3f" ,
252+ "%Y-%m-%d %T.%3f" ,
253+ "%Y-%m-%d %T.%3f" ,
254+ ] ;
255+ let results = [
256+ Some ( "1970-01-01 00:02:03.000" ) ,
257+ None ,
258+ Some ( "1970-01-01 00:00:42.000" ) ,
259+ None ,
260+ ] ;
261+
262+ let mut config_options = ConfigOptions :: default ( ) ;
263+ config_options. extensions . insert ( FunctionContext :: default ( ) ) ;
264+ let config_options = Arc :: new ( config_options) ;
265+
266+ let args = ScalarFunctionArgs {
267+ args : vec ! [
268+ ColumnarValue :: Array ( Arc :: new( Date64Array :: from( dates) ) ) ,
269+ ColumnarValue :: Array ( Arc :: new( StringArray :: from_iter_values( formats) ) ) ,
270+ ] ,
271+ arg_fields : vec ! [ ] ,
272+ number_rows : 4 ,
273+ return_field : Arc :: new ( Field :: new ( "x" , DataType :: Utf8View , false ) ) ,
274+ config_options,
275+ } ;
276+ let result = f
277+ . invoke_with_args ( args)
278+ . and_then ( |x| x. to_array ( 4 ) )
279+ . unwrap ( ) ;
280+ let vector = result. as_string_view ( ) ;
281+
282+ assert_eq ! ( 4 , vector. len( ) ) ;
283+ for ( actual, expect) in vector. iter ( ) . zip ( results) {
284+ assert_eq ! ( actual, expect) ;
285+ }
286+ }
287+
216288 #[ test]
217289 fn test_date_date_format ( ) {
218290 let f = DateFormatFunction :: default ( ) ;
0 commit comments