@@ -52,13 +52,14 @@ use arrow::compute::kernels::{
5252} ;
5353use arrow:: datatypes:: {
5454 i256, ArrowDictionaryKeyType , ArrowNativeType , ArrowTimestampType , DataType ,
55- Date32Type , Date64Type , Field , Float32Type , Int16Type , Int32Type , Int64Type ,
56- Int8Type , IntervalDayTimeType , IntervalMonthDayNanoType , IntervalUnit ,
57- IntervalYearMonthType , TimeUnit , TimestampMicrosecondType , TimestampMillisecondType ,
55+ Date32Type , Field , Float32Type , Int16Type , Int32Type , Int64Type , Int8Type ,
56+ IntervalDayTimeType , IntervalMonthDayNanoType , IntervalUnit , IntervalYearMonthType ,
57+ TimeUnit , TimestampMicrosecondType , TimestampMillisecondType ,
5858 TimestampNanosecondType , TimestampSecondType , UInt16Type , UInt32Type , UInt64Type ,
5959 UInt8Type , UnionFields , UnionMode , DECIMAL128_MAX_PRECISION ,
6060} ;
6161use arrow:: util:: display:: { array_value_to_string, ArrayFormatter , FormatOptions } ;
62+ use chrono:: { Duration , NaiveDate } ;
6263use half:: f16;
6364pub use struct_builder:: ScalarStructBuilder ;
6465
@@ -3816,12 +3817,28 @@ impl fmt::Display for ScalarValue {
38163817 ScalarValue :: List ( arr) => fmt_list ( arr. to_owned ( ) as ArrayRef , f) ?,
38173818 ScalarValue :: LargeList ( arr) => fmt_list ( arr. to_owned ( ) as ArrayRef , f) ?,
38183819 ScalarValue :: FixedSizeList ( arr) => fmt_list ( arr. to_owned ( ) as ArrayRef , f) ?,
3819- ScalarValue :: Date32 ( e) => {
3820- format_option ! ( f, e. map( |v| Date32Type :: to_naive_date( v) . to_string( ) ) ) ?
3821- }
3822- ScalarValue :: Date64 ( e) => {
3823- format_option ! ( f, e. map( |v| Date64Type :: to_naive_date( v) . to_string( ) ) ) ?
3824- }
3820+ ScalarValue :: Date32 ( e) => format_option ! (
3821+ f,
3822+ e. map( |v| {
3823+ let epoch = NaiveDate :: from_ymd_opt( 1970 , 1 , 1 ) . unwrap( ) ;
3824+ match epoch. checked_add_signed( Duration :: try_days( v as i64 ) . unwrap( ) )
3825+ {
3826+ Some ( date) => date. to_string( ) ,
3827+ None => "" . to_string( ) ,
3828+ }
3829+ } )
3830+ ) ?,
3831+ ScalarValue :: Date64 ( e) => format_option ! (
3832+ f,
3833+ e. map( |v| {
3834+ let epoch = NaiveDate :: from_ymd_opt( 1970 , 1 , 1 ) . unwrap( ) ;
3835+ match epoch. checked_add_signed( Duration :: try_milliseconds( v) . unwrap( ) )
3836+ {
3837+ Some ( date) => date. to_string( ) ,
3838+ None => "" . to_string( ) ,
3839+ }
3840+ } )
3841+ ) ?,
38253842 ScalarValue :: Time32Second ( e) => format_option ! ( f, e) ?,
38263843 ScalarValue :: Time32Millisecond ( e) => format_option ! ( f, e) ?,
38273844 ScalarValue :: Time64Microsecond ( e) => format_option ! ( f, e) ?,
@@ -7229,6 +7246,19 @@ mod tests {
72297246 " ) ;
72307247 }
72317248
7249+ #[ test]
7250+ fn test_display_date64_large_values ( ) {
7251+ assert_eq ! (
7252+ format!( "{}" , ScalarValue :: Date64 ( Some ( 790179464505 ) ) ) ,
7253+ "1995-01-15"
7254+ ) ;
7255+ // This used to panic, see https://github.com/apache/arrow-rs/issues/7728
7256+ assert_eq ! (
7257+ format!( "{}" , ScalarValue :: Date64 ( Some ( -790179464505600000 ) ) ) ,
7258+ ""
7259+ ) ;
7260+ }
7261+
72327262 #[ test]
72337263 fn test_struct_display_null ( ) {
72347264 let fields = vec ! [ Field :: new( "a" , DataType :: Int32 , false ) ] ;
0 commit comments