diff --git a/arrow-cast/src/cast/mod.rs b/arrow-cast/src/cast/mod.rs index c9de714e7d55..3f9c9c8a3356 100644 --- a/arrow-cast/src/cast/mod.rs +++ b/arrow-cast/src/cast/mod.rs @@ -4314,8 +4314,8 @@ mod tests { IntervalUnit::YearMonth, IntervalYearMonthArray, vec![ - Some("1 years 1 mons 0 days 0 hours 0 mins 0.00 secs"), - Some("2 years 7 mons 0 days 0 hours 0 mins 0.00 secs"), + Some("1 years 1 mons"), + Some("2 years 7 mons"), None, None, None, @@ -4338,9 +4338,9 @@ mod tests { IntervalUnit::DayTime, IntervalDayTimeArray, vec![ - Some("0 years 0 mons 390 days 0 hours 0 mins 0.000 secs"), - Some("0 years 0 mons 930 days 0 hours 0 mins 0.000 secs"), - Some("0 years 0 mons 30 days 0 hours 0 mins 0.000 secs"), + Some("390 days"), + Some("930 days"), + Some("30 days"), None, None, ] @@ -4366,16 +4366,16 @@ mod tests { IntervalUnit::MonthDayNano, IntervalMonthDayNanoArray, vec![ - Some("0 years 13 mons 1 days 0 hours 0 mins 0.000000000 secs"), + Some("13 mons 1 days"), None, - Some("0 years 31 mons 35 days 0 hours 0 mins 0.001400000 secs"), - Some("0 years 0 mons 3 days 0 hours 0 mins 0.000000000 secs"), - Some("0 years 0 mons 0 days 0 hours 0 mins 8.000000000 secs"), + Some("31 mons 35 days 0.001400000 secs"), + Some("3 days"), + Some("8.000000000 secs"), None, - Some("0 years 0 mons 1 days 0 hours 0 mins 29.800000000 secs"), - Some("0 years 3 mons 0 days 0 hours 0 mins 1.000000000 secs"), - Some("0 years 0 mons 0 days 0 hours 8 mins 0.000000000 secs"), - Some("0 years 63 mons 9 days 19 hours 9 mins 2.222000000 secs"), + Some("1 days 29.800000000 secs"), + Some("3 mons 1.000000000 secs"), + Some("8 mins"), + Some("63 mons 9 days 19 hours 9 mins 2.222000000 secs"), None, ] ); diff --git a/arrow-cast/src/display.rs b/arrow-cast/src/display.rs index 6a40d036350a..ab172cb240cf 100644 --- a/arrow-cast/src/display.rs +++ b/arrow-cast/src/display.rs @@ -654,10 +654,7 @@ impl<'a> DisplayIndex for &'a PrimitiveArray { let years = (interval / 12_f64).floor(); let month = interval - (years * 12_f64); - write!( - f, - "{years} years {month} mons 0 days 0 hours 0 mins 0.00 secs", - )?; + write!(f, "{years} years {month} mons",)?; Ok(()) } } @@ -665,62 +662,181 @@ impl<'a> DisplayIndex for &'a PrimitiveArray { impl<'a> DisplayIndex for &'a PrimitiveArray { fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult { let value = self.value(idx); + let mut first_part = true; - let secs = value.milliseconds / 1_000; + if value.days != 0 { + write!(f, "{} days", value.days)?; + first_part = false; + } + + if value.milliseconds != 0 { + let millis_fmt = MillisecondsFormatter { + milliseconds: value.milliseconds, + first_part, + }; + + f.write_fmt(format_args!("{millis_fmt}"))?; + } + + Ok(()) + } +} + +impl<'a> DisplayIndex for &'a PrimitiveArray { + fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult { + let value = self.value(idx); + let mut first_part = true; + + if value.months != 0 { + write!(f, "{} mons", value.months)?; + first_part = false; + } + + if value.days != 0 { + if first_part { + write!(f, "{} days", value.days)?; + first_part = false; + } else { + write!(f, " {} days", value.days)?; + } + } + + if value.nanoseconds != 0 { + let nano_fmt = NanosecondsFormatter { + nanoseconds: value.nanoseconds, + first_part, + }; + f.write_fmt(format_args!("{nano_fmt}"))?; + } + + Ok(()) + } +} + +struct NanosecondsFormatter { + nanoseconds: i64, + first_part: bool, +} + +impl Display for NanosecondsFormatter { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let mut first_part = self.first_part; + + let secs = self.nanoseconds / 1_000_000_000; let mins = secs / 60; let hours = mins / 60; let secs = secs - (mins * 60); let mins = mins - (hours * 60); - let milliseconds = value.milliseconds % 1_000; + let nanoseconds = self.nanoseconds % 1_000_000_000; - let secs_sign = if secs < 0 || milliseconds < 0 { - "-" - } else { - "" - }; + if hours != 0 { + if first_part { + write!(f, "{} hours", hours)?; + first_part = false; + } else { + write!(f, " {} hours", hours)?; + } + } + + if mins != 0 { + if first_part { + write!(f, "{} mins", mins)?; + first_part = false; + } else { + write!(f, " {} mins", mins)?; + } + } + + if secs != 0 || nanoseconds != 0 { + let secs_sign = if secs < 0 || nanoseconds < 0 { "-" } else { "" }; + + if first_part { + write!( + f, + "{}{}.{:09} secs", + secs_sign, + secs.abs(), + nanoseconds.abs() + )?; + } else { + write!( + f, + " {}{}.{:09} secs", + secs_sign, + secs.abs(), + nanoseconds.abs() + )?; + } + } - write!( - f, - "0 years 0 mons {} days {} hours {} mins {}{}.{:03} secs", - value.days, - hours, - mins, - secs_sign, - secs.abs(), - milliseconds.abs(), - )?; Ok(()) } } -impl<'a> DisplayIndex for &'a PrimitiveArray { - fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult { - let value = self.value(idx); +struct MillisecondsFormatter { + milliseconds: i32, + first_part: bool, +} + +impl Display for MillisecondsFormatter { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let mut first_part = self.first_part; - let secs = value.nanoseconds / 1_000_000_000; + let secs = self.milliseconds / 1_000; let mins = secs / 60; let hours = mins / 60; let secs = secs - (mins * 60); let mins = mins - (hours * 60); - let nanoseconds = value.nanoseconds % 1_000_000_000; - - let secs_sign = if secs < 0 || nanoseconds < 0 { "-" } else { "" }; - - write!( - f, - "0 years {} mons {} days {} hours {} mins {}{}.{:09} secs", - value.months, - value.days, - hours, - mins, - secs_sign, - secs.abs(), - nanoseconds.abs(), - )?; + let milliseconds = self.milliseconds % 1_000; + + if hours != 0 { + if first_part { + write!(f, "{} hours", hours,)?; + first_part = false; + } else { + write!(f, " {} hours", hours,)?; + } + } + + if mins != 0 { + if first_part { + write!(f, "{} mins", mins,)?; + first_part = false; + } else { + write!(f, " {} mins", mins,)?; + } + } + + if secs != 0 || milliseconds != 0 { + let secs_sign = if secs < 0 || milliseconds < 0 { + "-" + } else { + "" + }; + + if first_part { + write!( + f, + "{}{}.{:03} secs", + secs_sign, + secs.abs(), + milliseconds.abs() + )?; + } else { + write!( + f, + " {}{}.{:03} secs", + secs_sign, + secs.abs(), + milliseconds.abs() + )?; + } + } + Ok(()) } } diff --git a/arrow-cast/src/pretty.rs b/arrow-cast/src/pretty.rs index 9383b9f73f61..f41471e38d5e 100644 --- a/arrow-cast/src/pretty.rs +++ b/arrow-cast/src/pretty.rs @@ -986,16 +986,16 @@ mod tests { let table = pretty_format_batches(&[batch]).unwrap().to_string(); let expected = vec![ - "+----------------------------------------------------+", - "| IntervalDayTime |", - "+----------------------------------------------------+", - "| 0 years 0 mons -1 days 0 hours -10 mins 0.000 secs |", - "| 0 years 0 mons 0 days 0 hours 0 mins -1.001 secs |", - "| 0 years 0 mons 0 days 0 hours 0 mins -0.001 secs |", - "| 0 years 0 mons 0 days 0 hours 0 mins 0.001 secs |", - "| 0 years 0 mons 0 days 0 hours 0 mins 0.010 secs |", - "| 0 years 0 mons 0 days 0 hours 0 mins 0.100 secs |", - "+----------------------------------------------------+", + "+------------------+", + "| IntervalDayTime |", + "+------------------+", + "| -1 days -10 mins |", + "| -1.001 secs |", + "| -0.001 secs |", + "| 0.001 secs |", + "| 0.010 secs |", + "| 0.100 secs |", + "+------------------+", ]; let actual: Vec<&str> = table.lines().collect(); @@ -1032,23 +1032,23 @@ mod tests { let table = pretty_format_batches(&[batch]).unwrap().to_string(); let expected = vec![ - "+-----------------------------------------------------------+", - "| IntervalMonthDayNano |", - "+-----------------------------------------------------------+", - "| 0 years -1 mons -1 days 0 hours -10 mins 0.000000000 secs |", - "| 0 years 0 mons 0 days 0 hours 0 mins -1.000000001 secs |", - "| 0 years 0 mons 0 days 0 hours 0 mins -0.000000001 secs |", - "| 0 years 0 mons 0 days 0 hours 0 mins 0.000000001 secs |", - "| 0 years 0 mons 0 days 0 hours 0 mins 0.000000010 secs |", - "| 0 years 0 mons 0 days 0 hours 0 mins 0.000000100 secs |", - "| 0 years 0 mons 0 days 0 hours 0 mins 0.000001000 secs |", - "| 0 years 0 mons 0 days 0 hours 0 mins 0.000010000 secs |", - "| 0 years 0 mons 0 days 0 hours 0 mins 0.000100000 secs |", - "| 0 years 0 mons 0 days 0 hours 0 mins 0.001000000 secs |", - "| 0 years 0 mons 0 days 0 hours 0 mins 0.010000000 secs |", - "| 0 years 0 mons 0 days 0 hours 0 mins 0.100000000 secs |", - "| 0 years 0 mons 0 days 0 hours 0 mins 1.000000000 secs |", - "+-----------------------------------------------------------+", + "+--------------------------+", + "| IntervalMonthDayNano |", + "+--------------------------+", + "| -1 mons -1 days -10 mins |", + "| -1.000000001 secs |", + "| -0.000000001 secs |", + "| 0.000000001 secs |", + "| 0.000000010 secs |", + "| 0.000000100 secs |", + "| 0.000001000 secs |", + "| 0.000010000 secs |", + "| 0.000100000 secs |", + "| 0.001000000 secs |", + "| 0.010000000 secs |", + "| 0.100000000 secs |", + "| 1.000000000 secs |", + "+--------------------------+", ]; let actual: Vec<&str> = table.lines().collect();