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);
+ }
}