@@ -52,13 +52,14 @@ use arrow::compute::kernels::{
52
52
} ;
53
53
use arrow:: datatypes:: {
54
54
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 ,
58
58
TimestampNanosecondType , TimestampSecondType , UInt16Type , UInt32Type , UInt64Type ,
59
59
UInt8Type , UnionFields , UnionMode , DECIMAL128_MAX_PRECISION ,
60
60
} ;
61
61
use arrow:: util:: display:: { array_value_to_string, ArrayFormatter , FormatOptions } ;
62
+ use chrono:: { Duration , NaiveDate } ;
62
63
use half:: f16;
63
64
pub use struct_builder:: ScalarStructBuilder ;
64
65
@@ -3816,12 +3817,28 @@ impl fmt::Display for ScalarValue {
3816
3817
ScalarValue :: List ( arr) => fmt_list ( arr. to_owned ( ) as ArrayRef , f) ?,
3817
3818
ScalarValue :: LargeList ( arr) => fmt_list ( arr. to_owned ( ) as ArrayRef , f) ?,
3818
3819
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
+ ) ?,
3825
3842
ScalarValue :: Time32Second ( e) => format_option ! ( f, e) ?,
3826
3843
ScalarValue :: Time32Millisecond ( e) => format_option ! ( f, e) ?,
3827
3844
ScalarValue :: Time64Microsecond ( e) => format_option ! ( f, e) ?,
@@ -7229,6 +7246,19 @@ mod tests {
7229
7246
" ) ;
7230
7247
}
7231
7248
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
+
7232
7262
#[ test]
7233
7263
fn test_struct_display_null ( ) {
7234
7264
let fields = vec ! [ Field :: new( "a" , DataType :: Int32 , false ) ] ;
0 commit comments