Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

100 changes: 79 additions & 21 deletions arrow-cast/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,29 +36,42 @@ use arrow_buffer::ArrowNativeType;
use arrow_data::decimal::write_decimal;
use arrow_schema::*;
use chrono::format::{Item, StrftimeItems};
use chrono::{NaiveDate, NaiveDateTime, SecondsFormat, TimeZone, Utc};
use chrono::{NaiveDate, NaiveDateTime, NaiveTime, SecondsFormat, TimeZone, Utc};
use lexical_core::FormattedSize;

type TimeFormat<'a> = Option<&'a str>;

struct CompiledItems<'a>(Vec<Item<'a>>);

enum CompiledTimeFormat<'a> {
enum CompiledTimeFormatInner<'a> {
Default,
Custom(Box<CompiledItems<'a>>),
}

/// A compiled time format that can be used to format temporal values.
///
/// Use [`CompiledTimeFormat::new` to compile a custom strftime format,
/// or [`Default::default`] to use the default temporal representation.
pub struct CompiledTimeFormat<'a>(CompiledTimeFormatInner<'a>);

impl<'a> CompiledTimeFormat<'a> {
fn new(format: TimeFormat<'a>) -> Self {
/// Construct a CompiledTimeFormat from the given time format
pub fn new(format: TimeFormat<'a>) -> Self {
match format {
Some(format) => Self::Custom(Box::new(CompiledItems(
Some(format) => Self(CompiledTimeFormatInner::Custom(Box::new(CompiledItems(
StrftimeItems::new(format).collect(),
))),
None => Self::Default,
)))),
None => Self(CompiledTimeFormatInner::Default),
}
}
}

impl Default for CompiledTimeFormat<'_> {
fn default() -> Self {
Self(CompiledTimeFormatInner::Default)
}
}

/// Format for displaying durations
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[non_exhaustive]
Expand Down Expand Up @@ -753,7 +766,8 @@ macro_rules! decimal_display {

decimal_display!(Decimal32Type, Decimal64Type, Decimal128Type, Decimal256Type);

fn write_timestamp(
/// Writing a given data time instance to the writer using specified time format.
pub fn write_timestamp(
f: &mut dyn Write,
naive: NaiveDateTime,
timezone: Option<Tz>,
Expand All @@ -762,20 +776,20 @@ fn write_timestamp(
match timezone {
Some(tz) => {
let date = Utc.from_utc_datetime(&naive).with_timezone(&tz);
match format {
CompiledTimeFormat::Custom(items) => {
write!(f, "{}", date.format_with_items(items.0.iter()))?
match &format.0 {
CompiledTimeFormatInner::Custom(items) => {
date.format_with_items(items.0.iter()).write_to(f)?
}
CompiledTimeFormat::Default => {
CompiledTimeFormatInner::Default => {
write!(f, "{}", date.to_rfc3339_opts(SecondsFormat::AutoSi, true))?
}
}
}
None => match format {
CompiledTimeFormat::Custom(items) => {
write!(f, "{}", naive.format_with_items(items.0.iter()))?
None => match &format.0 {
CompiledTimeFormatInner::Custom(items) => {
naive.format_with_items(items.0.iter()).write_to(f)?
}
CompiledTimeFormat::Default => write!(f, "{naive:?}")?,
CompiledTimeFormatInner::Default => write!(f, "{naive:?}")?,
},
}
Ok(())
Expand Down Expand Up @@ -817,6 +831,54 @@ timestamp_display!(
TimestampNanosecondType
);

/// A temporal value that can be formatted with a [`CompiledTimeFormat`].
///
/// This trait is implemented for [`NaiveDate`], [`NaiveTime`], and [`NaiveDateTime`].
/// It enables [`write_temporal_display`] to format these types according to a specified time format.
pub trait TemporalFormat: Debug {
/// Writes this value using the given compiled time format.
fn write_with_time_format(
&self,
f: &mut dyn Write,
format: &CompiledTimeFormat<'_>,
) -> FormatResult;
}

macro_rules! impl_temporal_format {
($($t:ty),+ $(,)?) => {
$(
impl TemporalFormat for $t {
#[inline]
fn write_with_time_format(
&self,
f: &mut dyn Write,
format: &CompiledTimeFormat<'_>,
) -> FormatResult {
match &format.0 {
CompiledTimeFormatInner::Custom(items) => {
self.format_with_items(items.0.iter()).write_to(f)?
}
CompiledTimeFormatInner::Default => write!(f, "{self:?}")?,
}
Ok(())
}
}
)+
};
}

impl_temporal_format!(NaiveDate, NaiveTime, NaiveDateTime);

/// Writing a given value to the writer using the specified format.
#[inline]
pub fn write_temporal_display(
f: &mut dyn Write,
value: &impl TemporalFormat,
format: &CompiledTimeFormat<'_>,
) -> FormatResult {
value.write_with_time_format(f, format)
}

macro_rules! temporal_display {
($convert:ident, $format:ident, $t:ty) => {
impl<'a> DisplayIndexState<'a> for &'a PrimitiveArray<$t> {
Expand All @@ -836,12 +898,8 @@ macro_rules! temporal_display {
))
})?;

match fmt {
CompiledTimeFormat::Custom(items) => {
write!(f, "{}", naive.format_with_items(items.0.iter()))?
}
CompiledTimeFormat::Default => write!(f, "{naive:?}")?,
}
write_temporal_display(f, &naive, fmt)?;

Ok(())
}
}
Expand Down
2 changes: 2 additions & 0 deletions parquet-variant-compute/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ parquet-variant-json = { workspace = true }
chrono = { workspace = true }
uuid = { version = "1.18.0", features = ["v4"] }
num-traits = { version = "0.2.19", default-features = false }
ryu = "1.0.16"
lexical-core = { version = "1.0.6", default-features = false, features = ["write-integers"]}

# uuid requires the `js` feature to run on wasm
[target.'cfg(target_arch = "wasm32")'.dependencies]
Expand Down
2 changes: 1 addition & 1 deletion parquet-variant-compute/src/shred_variant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1178,7 +1178,7 @@ mod tests {

#[test]
fn test_already_shredded_input_error() {
// Create a VariantArray that already has typed_value_field
// Create a VariantArray that already has typed_value_column
// First create a valid VariantArray, then extract its parts to construct a shredded one
let temp_array = VariantArray::from_iter([Some("test")]);
let metadata = temp_array.metadata_column().clone();
Expand Down
Loading
Loading