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

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


The following commit(s) were added to refs/heads/master by this push:
     new 71572bd  ARROW-11318: [Rust] Support pretty printing timestamp, date, 
and timestamp types
71572bd is described below

commit 71572bd0ff1069fc3ccec688305e4d1361cca570
Author: Andrew Lamb <[email protected]>
AuthorDate: Wed Jan 20 06:50:47 2021 -0500

    ARROW-11318: [Rust] Support pretty printing timestamp, date, and timestamp 
types
    
    I found this while removing `test::format_batches` (PR to come shortly); 
The Record batch pretty printing code was printing numbers rather than dates.
    
    Before this PR, when date/time columns were printed they were printed as 
numbers:
    
    ```
    [
        "+----------+",
        "| f        |",
        "+----------+",
        "| 11111111 |",
        "|          |",
        "+----------+",
    ]
    ```
    
    After this PR, they are printed (via chrono) as dates:
    
    ```
    [
        "+---------------------+",
        "| f                   |",
        "+---------------------+",
        "| 1970-05-09 14:25:11 |",
        "|                     |",
        "+---------------------+",
    ]
    ```
    
    Closes #9263 from alamb/alamb/pretty_print_datetimes
    
    Authored-by: Andrew Lamb <[email protected]>
    Signed-off-by: Andrew Lamb <[email protected]>
---
 rust/arrow/src/util/display.rs |  73 +++++++++++++++---
 rust/arrow/src/util/pretty.rs  | 167 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 227 insertions(+), 13 deletions(-)

diff --git a/rust/arrow/src/util/display.rs b/rust/arrow/src/util/display.rs
index 7d4b10e..c559658 100644
--- a/rust/arrow/src/util/display.rs
+++ b/rust/arrow/src/util/display.rs
@@ -44,6 +44,57 @@ macro_rules! make_string {
     }};
 }
 
+macro_rules! make_string_date {
+    ($array_type:ty, $column: ident, $row: ident) => {{
+        let array = $column.as_any().downcast_ref::<$array_type>().unwrap();
+
+        let s = if array.is_null($row) {
+            "".to_string()
+        } else {
+            array
+                .value_as_date($row)
+                .map(|d| d.to_string())
+                .unwrap_or_else(|| "ERROR CONVERTING DATE".to_string())
+        };
+
+        Ok(s)
+    }};
+}
+
+macro_rules! make_string_time {
+    ($array_type:ty, $column: ident, $row: ident) => {{
+        let array = $column.as_any().downcast_ref::<$array_type>().unwrap();
+
+        let s = if array.is_null($row) {
+            "".to_string()
+        } else {
+            array
+                .value_as_time($row)
+                .map(|d| d.to_string())
+                .unwrap_or_else(|| "ERROR CONVERTING DATE".to_string())
+        };
+
+        Ok(s)
+    }};
+}
+
+macro_rules! make_string_datetime {
+    ($array_type:ty, $column: ident, $row: ident) => {{
+        let array = $column.as_any().downcast_ref::<$array_type>().unwrap();
+
+        let s = if array.is_null($row) {
+            "".to_string()
+        } else {
+            array
+                .value_as_datetime($row)
+                .map(|d| d.to_string())
+                .unwrap_or_else(|| "ERROR CONVERTING DATE".to_string())
+        };
+
+        Ok(s)
+    }};
+}
+
 // It's not possible to do array.value($row).to_string() for &[u8], let's 
format it as hex
 macro_rules! make_string_hex {
     ($array_type:ty, $column: ident, $row: ident) => {{
@@ -104,30 +155,30 @@ pub fn array_value_to_string(column: &array::ArrayRef, 
row: usize) -> Result<Str
         DataType::Float32 => make_string!(array::Float32Array, column, row),
         DataType::Float64 => make_string!(array::Float64Array, column, row),
         DataType::Timestamp(unit, _) if *unit == TimeUnit::Second => {
-            make_string!(array::TimestampSecondArray, column, row)
+            make_string_datetime!(array::TimestampSecondArray, column, row)
         }
         DataType::Timestamp(unit, _) if *unit == TimeUnit::Millisecond => {
-            make_string!(array::TimestampMillisecondArray, column, row)
+            make_string_datetime!(array::TimestampMillisecondArray, column, 
row)
         }
         DataType::Timestamp(unit, _) if *unit == TimeUnit::Microsecond => {
-            make_string!(array::TimestampMicrosecondArray, column, row)
+            make_string_datetime!(array::TimestampMicrosecondArray, column, 
row)
         }
         DataType::Timestamp(unit, _) if *unit == TimeUnit::Nanosecond => {
-            make_string!(array::TimestampNanosecondArray, column, row)
+            make_string_datetime!(array::TimestampNanosecondArray, column, row)
         }
-        DataType::Date32(_) => make_string!(array::Date32Array, column, row),
-        DataType::Date64(_) => make_string!(array::Date64Array, column, row),
+        DataType::Date32(_) => make_string_date!(array::Date32Array, column, 
row),
+        DataType::Date64(_) => make_string_date!(array::Date64Array, column, 
row),
         DataType::Time32(unit) if *unit == TimeUnit::Second => {
-            make_string!(array::Time32SecondArray, column, row)
+            make_string_time!(array::Time32SecondArray, column, row)
         }
         DataType::Time32(unit) if *unit == TimeUnit::Millisecond => {
-            make_string!(array::Time32MillisecondArray, column, row)
+            make_string_time!(array::Time32MillisecondArray, column, row)
         }
-        DataType::Time32(unit) if *unit == TimeUnit::Microsecond => {
-            make_string!(array::Time64MicrosecondArray, column, row)
+        DataType::Time64(unit) if *unit == TimeUnit::Microsecond => {
+            make_string_time!(array::Time64MicrosecondArray, column, row)
         }
         DataType::Time64(unit) if *unit == TimeUnit::Nanosecond => {
-            make_string!(array::Time64NanosecondArray, column, row)
+            make_string_time!(array::Time64NanosecondArray, column, row)
         }
         DataType::List(_) => make_string_from_list!(column, row),
         DataType::Dictionary(index_type, _value_type) => match **index_type {
diff --git a/rust/arrow/src/util/pretty.rs b/rust/arrow/src/util/pretty.rs
index 4896d1a..9a0c95d 100644
--- a/rust/arrow/src/util/pretty.rs
+++ b/rust/arrow/src/util/pretty.rs
@@ -71,10 +71,17 @@ fn create_table(results: &[RecordBatch]) -> Result<Table> {
 
 #[cfg(test)]
 mod tests {
-    use crate::array::{self, PrimitiveBuilder, StringBuilder, 
StringDictionaryBuilder};
+    use crate::{
+        array::{
+            self, Array, Date32Array, Date64Array, PrimitiveBuilder, 
StringBuilder,
+            StringDictionaryBuilder, Time32MillisecondArray, Time32SecondArray,
+            Time64MicrosecondArray, Time64NanosecondArray, 
TimestampMicrosecondArray,
+            TimestampMillisecondArray, TimestampNanosecondArray, 
TimestampSecondArray,
+        },
+        datatypes::{DataType, Field, Int32Type, Schema},
+    };
 
     use super::*;
-    use crate::datatypes::{DataType, Field, Int32Type, Schema};
     use std::sync::Arc;
 
     #[test]
@@ -160,4 +167,160 @@ mod tests {
 
         Ok(())
     }
+
+    /// Generate an array with type $ARRAYTYPE with a numeric value of
+    /// $VALUE, and compare $EXPECTED_RESULT to the output of
+    /// formatting that array with `pretty_format_batches`
+    macro_rules! check_datetime {
+        ($ARRAYTYPE:ident, $VALUE:expr, $EXPECTED_RESULT:expr) => {
+            let mut builder = $ARRAYTYPE::builder(10);
+            builder.append_value($VALUE).unwrap();
+            builder.append_null().unwrap();
+            let array = builder.finish();
+
+            let schema = Arc::new(Schema::new(vec![Field::new(
+                "f",
+                array.data_type().clone(),
+                true,
+            )]));
+            let batch = RecordBatch::try_new(schema, 
vec![Arc::new(array)]).unwrap();
+
+            let table = pretty_format_batches(&[batch]).expect("formatting 
batches");
+
+            let expected = $EXPECTED_RESULT;
+            let actual: Vec<&str> = table.lines().collect();
+
+            assert_eq!(expected, actual, "Actual result:\n\n{:#?}\n\n", 
actual);
+        };
+    }
+
+    #[test]
+    fn test_pretty_format_timestamp_second() {
+        let expected = vec![
+            "+---------------------+",
+            "| f                   |",
+            "+---------------------+",
+            "| 1970-05-09 14:25:11 |",
+            "|                     |",
+            "+---------------------+",
+        ];
+        check_datetime!(TimestampSecondArray, 11111111, expected);
+    }
+
+    #[test]
+    fn test_pretty_format_timestamp_millisecond() {
+        let expected = vec![
+            "+-------------------------+",
+            "| f                       |",
+            "+-------------------------+",
+            "| 1970-01-01 03:05:11.111 |",
+            "|                         |",
+            "+-------------------------+",
+        ];
+        check_datetime!(TimestampMillisecondArray, 11111111, expected);
+    }
+
+    #[test]
+    fn test_pretty_format_timestamp_microsecond() {
+        let expected = vec![
+            "+----------------------------+",
+            "| f                          |",
+            "+----------------------------+",
+            "| 1970-01-01 00:00:11.111111 |",
+            "|                            |",
+            "+----------------------------+",
+        ];
+        check_datetime!(TimestampMicrosecondArray, 11111111, expected);
+    }
+
+    #[test]
+    fn test_pretty_format_timestamp_nanosecond() {
+        let expected = vec![
+            "+-------------------------------+",
+            "| f                             |",
+            "+-------------------------------+",
+            "| 1970-01-01 00:00:00.011111111 |",
+            "|                               |",
+            "+-------------------------------+",
+        ];
+        check_datetime!(TimestampNanosecondArray, 11111111, expected);
+    }
+
+    #[test]
+    fn test_pretty_format_date_32() {
+        let expected = vec![
+            "+------------+",
+            "| f          |",
+            "+------------+",
+            "| 1973-05-19 |",
+            "|            |",
+            "+------------+",
+        ];
+        check_datetime!(Date32Array, 1234, expected);
+    }
+
+    #[test]
+    fn test_pretty_format_date_64() {
+        let expected = vec![
+            "+------------+",
+            "| f          |",
+            "+------------+",
+            "| 2005-03-18 |",
+            "|            |",
+            "+------------+",
+        ];
+        check_datetime!(Date64Array, 1111111100000, expected);
+    }
+
+    #[test]
+    fn test_pretty_format_time_32_second() {
+        let expected = vec![
+            "+----------+",
+            "| f        |",
+            "+----------+",
+            "| 00:18:31 |",
+            "|          |",
+            "+----------+",
+        ];
+        check_datetime!(Time32SecondArray, 1111, expected);
+    }
+
+    #[test]
+    fn test_pretty_format_time_32_millisecond() {
+        let expected = vec![
+            "+--------------+",
+            "| f            |",
+            "+--------------+",
+            "| 03:05:11.111 |",
+            "|              |",
+            "+--------------+",
+        ];
+        check_datetime!(Time32MillisecondArray, 11111111, expected);
+    }
+
+    #[test]
+    fn test_pretty_format_time_64_microsecond() {
+        let expected = vec![
+            "+-----------------+",
+            "| f               |",
+            "+-----------------+",
+            "| 00:00:11.111111 |",
+            "|                 |",
+            "+-----------------+",
+        ];
+        check_datetime!(Time64MicrosecondArray, 11111111, expected);
+    }
+
+    #[test]
+    fn test_pretty_format_time_64_nanosecond() {
+        let expected = vec![
+            "+--------------------+",
+            "| f                  |",
+            "+--------------------+",
+            "| 00:00:00.011111111 |",
+            "|                    |",
+            "+--------------------+",
+        ];
+        check_datetime!(Time64NanosecondArray, 11111111, expected);
+    }
 }

Reply via email to