|
17 | 17 |
|
18 | 18 | //! DateTime expressions |
19 | 19 |
|
| 20 | +use arrow::compute::cast; |
20 | 21 | use arrow::{ |
21 | 22 | array::TimestampNanosecondArray, compute::kernels::temporal, datatypes::TimeUnit, |
22 | 23 | temporal_conversions::timestamp_ns_to_datetime, |
23 | 24 | }; |
24 | 25 | use arrow::{ |
25 | | - array::{Array, ArrayRef, OffsetSizeTrait, PrimitiveArray}, |
| 26 | + array::{Array, ArrayRef, Float64Array, OffsetSizeTrait, PrimitiveArray}, |
26 | 27 | compute::kernels::cast_utils::string_to_timestamp_nanos, |
27 | 28 | datatypes::{ |
28 | | - ArrowPrimitiveType, DataType, IntervalDayTimeType, TimestampMicrosecondType, |
29 | | - TimestampMillisecondType, TimestampNanosecondType, TimestampSecondType, |
| 29 | + ArrowNumericType, ArrowPrimitiveType, ArrowTemporalType, DataType, |
| 30 | + IntervalDayTimeType, TimestampMicrosecondType, TimestampMillisecondType, |
| 31 | + TimestampNanosecondType, TimestampSecondType, |
30 | 32 | }, |
31 | 33 | }; |
32 | 34 | use chrono::prelude::*; |
@@ -401,30 +403,36 @@ pub fn date_bin(args: &[ColumnarValue]) -> Result<ColumnarValue> { |
401 | 403 | macro_rules! extract_date_part { |
402 | 404 | ($ARRAY: expr, $FN:expr) => { |
403 | 405 | match $ARRAY.data_type() { |
404 | | - DataType::Date32 => match as_date32_array($ARRAY) { |
405 | | - Ok(array) => Ok($FN(array)?), |
406 | | - Err(e) => Err(e), |
407 | | - }, |
| 406 | + DataType::Date32 => { |
| 407 | + let array = as_date32_array($ARRAY)?; |
| 408 | + Ok($FN(array) |
| 409 | + .map(|v| cast(&(Arc::new(v) as ArrayRef), &DataType::Float64))?) |
| 410 | + } |
408 | 411 | DataType::Date64 => { |
409 | 412 | let array = as_date64_array($ARRAY)?; |
410 | | - Ok($FN(array)?) |
| 413 | + Ok($FN(array) |
| 414 | + .map(|v| cast(&(Arc::new(v) as ArrayRef), &DataType::Float64))?) |
411 | 415 | } |
412 | 416 | DataType::Timestamp(time_unit, None) => match time_unit { |
413 | 417 | TimeUnit::Second => { |
414 | 418 | let array = as_timestamp_second_array($ARRAY)?; |
415 | | - Ok($FN(array)?) |
| 419 | + Ok($FN(array) |
| 420 | + .map(|v| cast(&(Arc::new(v) as ArrayRef), &DataType::Float64))?) |
416 | 421 | } |
417 | 422 | TimeUnit::Millisecond => { |
418 | 423 | let array = as_timestamp_millisecond_array($ARRAY)?; |
419 | | - Ok($FN(array)?) |
| 424 | + Ok($FN(array) |
| 425 | + .map(|v| cast(&(Arc::new(v) as ArrayRef), &DataType::Float64))?) |
420 | 426 | } |
421 | 427 | TimeUnit::Microsecond => { |
422 | 428 | let array = as_timestamp_microsecond_array($ARRAY)?; |
423 | | - Ok($FN(array)?) |
| 429 | + Ok($FN(array) |
| 430 | + .map(|v| cast(&(Arc::new(v) as ArrayRef), &DataType::Float64))?) |
424 | 431 | } |
425 | 432 | TimeUnit::Nanosecond => { |
426 | 433 | let array = as_timestamp_nanosecond_array($ARRAY)?; |
427 | | - Ok($FN(array)?) |
| 434 | + Ok($FN(array) |
| 435 | + .map(|v| cast(&(Arc::new(v) as ArrayRef), &DataType::Float64))?) |
428 | 436 | } |
429 | 437 | }, |
430 | 438 | datatype => Err(DataFusionError::Internal(format!( |
@@ -469,23 +477,70 @@ pub fn date_part(args: &[ColumnarValue]) -> Result<ColumnarValue> { |
469 | 477 | "dow" => extract_date_part!(&array, temporal::num_days_from_sunday), |
470 | 478 | "hour" => extract_date_part!(&array, temporal::hour), |
471 | 479 | "minute" => extract_date_part!(&array, temporal::minute), |
472 | | - "second" => extract_date_part!(&array, temporal::second), |
| 480 | + "second" => extract_date_part!(&array, seconds), |
| 481 | + "millisecond" => extract_date_part!(&array, millis), |
| 482 | + "microsecond" => extract_date_part!(&array, micros), |
| 483 | + "nanosecond" => extract_date_part!(&array, nanos), |
473 | 484 | _ => Err(DataFusionError::Execution(format!( |
474 | 485 | "Date part '{}' not supported", |
475 | 486 | date_part |
476 | 487 | ))), |
477 | 488 | }?; |
478 | 489 |
|
479 | 490 | Ok(if is_scalar { |
480 | | - ColumnarValue::Scalar(ScalarValue::try_from_array( |
481 | | - &(Arc::new(arr) as ArrayRef), |
482 | | - 0, |
483 | | - )?) |
| 491 | + ColumnarValue::Scalar(ScalarValue::try_from_array(&arr?, 0)?) |
484 | 492 | } else { |
485 | | - ColumnarValue::Array(Arc::new(arr)) |
| 493 | + ColumnarValue::Array(arr?) |
486 | 494 | }) |
487 | 495 | } |
488 | 496 |
|
| 497 | +fn to_ticks<T>(array: &PrimitiveArray<T>, frac: i32) -> Result<Float64Array> |
| 498 | +where |
| 499 | + T: ArrowTemporalType + ArrowNumericType, |
| 500 | + i64: From<T::Native>, |
| 501 | +{ |
| 502 | + let zipped = temporal::second(array)? |
| 503 | + .values() |
| 504 | + .iter() |
| 505 | + .zip(temporal::nanosecond(array)?.values().iter()) |
| 506 | + .map(|o| ((*o.0 as f64 + (*o.1 as f64) / 1_000_000_000.0) * (frac as f64))) |
| 507 | + .collect::<Vec<f64>>(); |
| 508 | + |
| 509 | + Ok(Float64Array::from(zipped)) |
| 510 | +} |
| 511 | + |
| 512 | +fn seconds<T>(array: &PrimitiveArray<T>) -> Result<Float64Array> |
| 513 | +where |
| 514 | + T: ArrowTemporalType + ArrowNumericType, |
| 515 | + i64: From<T::Native>, |
| 516 | +{ |
| 517 | + to_ticks(array, 1) |
| 518 | +} |
| 519 | + |
| 520 | +fn millis<T>(array: &PrimitiveArray<T>) -> Result<Float64Array> |
| 521 | +where |
| 522 | + T: ArrowTemporalType + ArrowNumericType, |
| 523 | + i64: From<T::Native>, |
| 524 | +{ |
| 525 | + to_ticks(array, 1_000) |
| 526 | +} |
| 527 | + |
| 528 | +fn micros<T>(array: &PrimitiveArray<T>) -> Result<Float64Array> |
| 529 | +where |
| 530 | + T: ArrowTemporalType + ArrowNumericType, |
| 531 | + i64: From<T::Native>, |
| 532 | +{ |
| 533 | + to_ticks(array, 1_000_000) |
| 534 | +} |
| 535 | + |
| 536 | +fn nanos<T>(array: &PrimitiveArray<T>) -> Result<Float64Array> |
| 537 | +where |
| 538 | + T: ArrowTemporalType + ArrowNumericType, |
| 539 | + i64: From<T::Native>, |
| 540 | +{ |
| 541 | + to_ticks(array, 1_000_000_000) |
| 542 | +} |
| 543 | + |
489 | 544 | #[cfg(test)] |
490 | 545 | mod tests { |
491 | 546 | use std::sync::Arc; |
|
0 commit comments