This is an automated email from the ASF dual-hosted git repository.

alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-datafusion.git


The following commit(s) were added to refs/heads/main by this push:
     new 146a94921 feat: extract (epoch from col) (#5555)
146a94921 is described below

commit 146a949218ec970784974137277cde3b4e547d0a
Author: Alex Huang <[email protected]>
AuthorDate: Mon Mar 13 18:00:39 2023 +0100

    feat: extract (epoch from col) (#5555)
    
    * feat: extract (epoch from col)
    
    * add more tests and refine error info
---
 datafusion/core/tests/sql/expr.rs                  | 18 +++++++++++
 .../physical-expr/src/datetime_expressions.rs      | 36 ++++++++++++++++++++++
 2 files changed, 54 insertions(+)

diff --git a/datafusion/core/tests/sql/expr.rs 
b/datafusion/core/tests/sql/expr.rs
index 24017f9cd..3d5f134a8 100644
--- a/datafusion/core/tests/sql/expr.rs
+++ b/datafusion/core/tests/sql/expr.rs
@@ -1313,6 +1313,24 @@ async fn test_extract_date_part() -> Result<()> {
     Ok(())
 }
 
+#[tokio::test]
+async fn test_extract_epoch() -> Result<()> {
+    test_expression!(
+        "extract(epoch from '1870-01-01T07:29:10.256'::timestamp)",
+        "-3155646649.744"
+    );
+    test_expression!(
+        "extract(epoch from '2000-01-01T00:00:00.000'::timestamp)",
+        "946684800.0"
+    );
+    test_expression!(
+        "extract(epoch from to_timestamp('2000-01-01T00:00:00+00:00'))",
+        "946684800.0"
+    );
+    test_expression!("extract(epoch from NULL::timestamp)", "NULL");
+    Ok(())
+}
+
 #[tokio::test]
 async fn test_extract_date_part_func() -> Result<()> {
     test_expression!(
diff --git a/datafusion/physical-expr/src/datetime_expressions.rs 
b/datafusion/physical-expr/src/datetime_expressions.rs
index 4b3eeb442..4ce1f18e8 100644
--- a/datafusion/physical-expr/src/datetime_expressions.rs
+++ b/datafusion/physical-expr/src/datetime_expressions.rs
@@ -17,6 +17,7 @@
 
 //! DateTime expressions
 
+use arrow::array::Float64Builder;
 use arrow::compute::cast;
 use arrow::{
     array::TimestampNanosecondArray, compute::kernels::temporal, 
datatypes::TimeUnit,
@@ -478,6 +479,7 @@ pub fn date_part(args: &[ColumnarValue]) -> 
Result<ColumnarValue> {
         "millisecond" => extract_date_part!(&array, millis),
         "microsecond" => extract_date_part!(&array, micros),
         "nanosecond" => extract_date_part!(&array, nanos),
+        "epoch" => extract_date_part!(&array, epoch),
         _ => Err(DataFusionError::Execution(format!(
             "Date part '{date_part}' not supported"
         ))),
@@ -537,6 +539,40 @@ where
     to_ticks(array, 1_000_000_000)
 }
 
+fn epoch<T>(array: &PrimitiveArray<T>) -> Result<Float64Array>
+where
+    T: ArrowTemporalType + ArrowNumericType,
+    i64: From<T::Native>,
+{
+    let mut b = Float64Builder::with_capacity(array.len());
+    match array.data_type() {
+        DataType::Timestamp(tu, _) => {
+            for i in 0..array.len() {
+                if array.is_null(i) {
+                    b.append_null();
+                } else {
+                    let scale = match tu {
+                        TimeUnit::Second => 1,
+                        TimeUnit::Millisecond => 1_000,
+                        TimeUnit::Microsecond => 1_000_000,
+                        TimeUnit::Nanosecond => 1_000_000_000,
+                    };
+
+                    let n: i64 = array.value(i).into();
+                    b.append_value(n as f64 / scale as f64);
+                }
+            }
+        }
+        _ => {
+            return Err(DataFusionError::Internal(format!(
+                "Can not convert {:?} to epoch",
+                array.data_type()
+            )))
+        }
+    }
+    Ok(b.finish())
+}
+
 #[cfg(test)]
 mod tests {
     use std::sync::Arc;

Reply via email to