1616// under the License.
1717
1818use crate :: utils:: array_with_timezone;
19- use arrow:: array:: AsArray ;
19+ use arrow:: array:: { Array , AsArray , PrimitiveArray } ;
2020use arrow:: compute:: cast;
21- use arrow:: datatypes:: { DataType , TimeUnit :: Microsecond } ;
21+ use arrow:: datatypes:: { DataType , Int64Type , TimeUnit :: Microsecond } ;
2222use datafusion:: common:: { internal_datafusion_err, DataFusionError } ;
2323use datafusion:: logical_expr:: {
2424 ColumnarValue , ScalarFunctionArgs , ScalarUDFImpl , Signature , Volatility ,
@@ -79,35 +79,67 @@ impl ScalarUDFImpl for SparkUnixTimestamp {
7979 match args {
8080 [ ColumnarValue :: Array ( array) ] => match array. data_type ( ) {
8181 DataType :: Timestamp ( _, _) => {
82- let array = array_with_timezone (
83- array,
84- self . timezone . clone ( ) ,
85- Some ( & DataType :: Timestamp ( Microsecond , Some ( "UTC" . into ( ) ) ) ) ,
86- ) ?;
82+ let is_utc = self . timezone == "UTC" ;
83+ let array = if is_utc
84+ && matches ! ( array. data_type( ) , DataType :: Timestamp ( Microsecond , Some ( tz) ) if tz. as_ref( ) == "UTC" )
85+ {
86+ array
87+ } else {
88+ array_with_timezone (
89+ array,
90+ self . timezone . clone ( ) ,
91+ Some ( & DataType :: Timestamp ( Microsecond , Some ( "UTC" . into ( ) ) ) ) ,
92+ ) ?
93+ } ;
8794
8895 let timestamp_array =
8996 array. as_primitive :: < arrow:: datatypes:: TimestampMicrosecondType > ( ) ;
90- let result: arrow:: array:: Int64Array = timestamp_array
91- . iter ( )
92- . map ( |v| v. map ( |micros| div_floor ( micros, MICROS_PER_SECOND ) ) )
93- . collect ( ) ;
97+
98+ let result: PrimitiveArray < Int64Type > = if timestamp_array. null_count ( ) == 0 {
99+ timestamp_array
100+ . values ( )
101+ . iter ( )
102+ . map ( |& micros| micros / MICROS_PER_SECOND )
103+ . collect ( )
104+ } else {
105+ timestamp_array
106+ . iter ( )
107+ . map ( |v| v. map ( |micros| div_floor ( micros, MICROS_PER_SECOND ) ) )
108+ . collect ( )
109+ } ;
110+
94111 Ok ( ColumnarValue :: Array ( Arc :: new ( result) ) )
95112 }
96113 DataType :: Date32 => {
97114 let timestamp_array = cast ( & array, & DataType :: Timestamp ( Microsecond , None ) ) ?;
98115
99- let array = array_with_timezone (
100- timestamp_array,
101- self . timezone . clone ( ) ,
102- Some ( & DataType :: Timestamp ( Microsecond , Some ( "UTC" . into ( ) ) ) ) ,
103- ) ?;
116+ let is_utc = self . timezone == "UTC" ;
117+ let array = if is_utc {
118+ timestamp_array
119+ } else {
120+ array_with_timezone (
121+ timestamp_array,
122+ self . timezone . clone ( ) ,
123+ Some ( & DataType :: Timestamp ( Microsecond , Some ( "UTC" . into ( ) ) ) ) ,
124+ ) ?
125+ } ;
104126
105127 let timestamp_array =
106128 array. as_primitive :: < arrow:: datatypes:: TimestampMicrosecondType > ( ) ;
107- let result: arrow:: array:: Int64Array = timestamp_array
108- . iter ( )
109- . map ( |v| v. map ( |micros| div_floor ( micros, MICROS_PER_SECOND ) ) )
110- . collect ( ) ;
129+
130+ let result: PrimitiveArray < Int64Type > = if timestamp_array. null_count ( ) == 0 {
131+ timestamp_array
132+ . values ( )
133+ . iter ( )
134+ . map ( |& micros| micros / MICROS_PER_SECOND )
135+ . collect ( )
136+ } else {
137+ timestamp_array
138+ . iter ( )
139+ . map ( |v| v. map ( |micros| div_floor ( micros, MICROS_PER_SECOND ) ) )
140+ . collect ( )
141+ } ;
142+
111143 Ok ( ColumnarValue :: Array ( Arc :: new ( result) ) )
112144 }
113145 _ => Err ( DataFusionError :: Execution ( format ! (
@@ -130,6 +162,8 @@ impl ScalarUDFImpl for SparkUnixTimestamp {
130162mod tests {
131163 use super :: * ;
132164 use arrow:: array:: { Array , Date32Array , TimestampMicrosecondArray } ;
165+ use arrow:: datatypes:: Field ;
166+ use datafusion:: config:: ConfigOptions ;
133167 use std:: sync:: Arc ;
134168
135169 #[ test]
0 commit comments