From 421ee98f27245476d9fe2c00bde1084c2d45b314 Mon Sep 17 00:00:00 2001 From: "Jorge C. Leitao" Date: Sun, 31 Jan 2021 06:29:12 +0100 Subject: [PATCH] Split datetime conversion logic to a separate module. --- rust/arrow/src/array/array_primitive.rs | 79 ++++----------- rust/arrow/src/lib.rs | 1 + rust/arrow/src/temporal_conversions.rs | 127 ++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 59 deletions(-) create mode 100644 rust/arrow/src/temporal_conversions.rs diff --git a/rust/arrow/src/array/array_primitive.rs b/rust/arrow/src/array/array_primitive.rs index fb5006e3d40..2056b886620 100644 --- a/rust/arrow/src/array/array_primitive.rs +++ b/rust/arrow/src/array/array_primitive.rs @@ -29,6 +29,7 @@ use super::array::print_long_array; use super::raw_pointer::RawPtrBox; use super::*; use crate::buffer::{Buffer, MutableBuffer}; +use crate::temporal_conversions; use crate::util::bit_util; /// Number of seconds in a day @@ -137,37 +138,20 @@ impl Array for PrimitiveArray { fn as_datetime(v: i64) -> Option { match T::DATA_TYPE { - DataType::Date32 => { - // convert days into seconds - Some(NaiveDateTime::from_timestamp(v as i64 * SECONDS_IN_DAY, 0)) - } - DataType::Date64 => Some(NaiveDateTime::from_timestamp( - // extract seconds from milliseconds - v / MILLISECONDS, - // discard extracted seconds and convert milliseconds to nanoseconds - (v % MILLISECONDS * MICROSECONDS) as u32, - )), + DataType::Date32 => Some(temporal_conversions::date32_to_datetime(v as i32)), + DataType::Date64 => Some(temporal_conversions::date64_to_datetime(v)), DataType::Time32(_) | DataType::Time64(_) => None, DataType::Timestamp(unit, _) => match unit { - TimeUnit::Second => Some(NaiveDateTime::from_timestamp(v, 0)), - TimeUnit::Millisecond => Some(NaiveDateTime::from_timestamp( - // extract seconds from milliseconds - v / MILLISECONDS, - // discard extracted seconds and convert milliseconds to nanoseconds - (v % MILLISECONDS * MICROSECONDS) as u32, - )), - TimeUnit::Microsecond => Some(NaiveDateTime::from_timestamp( - // extract seconds from microseconds - v / MICROSECONDS, - // discard extracted seconds and convert microseconds to nanoseconds - (v % MICROSECONDS * MILLISECONDS) as u32, - )), - TimeUnit::Nanosecond => Some(NaiveDateTime::from_timestamp( - // extract seconds from nanoseconds - v / NANOSECONDS, - // discard extracted seconds - (v % NANOSECONDS) as u32, - )), + TimeUnit::Second => Some(temporal_conversions::timestamp_s_to_datetime(v)), + TimeUnit::Millisecond => { + Some(temporal_conversions::timestamp_ms_to_datetime(v)) + } + TimeUnit::Microsecond => { + Some(temporal_conversions::timestamp_us_to_datetime(v)) + } + TimeUnit::Nanosecond => { + Some(temporal_conversions::timestamp_ns_to_datetime(v)) + } }, // interval is not yet fully documented [ARROW-3097] DataType::Interval(_) => None, @@ -185,41 +169,18 @@ fn as_time(v: i64) -> Option { // safe to immediately cast to u32 as `self.value(i)` is positive i32 let v = v as u32; match unit { - TimeUnit::Second => Some(NaiveTime::from_num_seconds_from_midnight(v, 0)), + TimeUnit::Second => Some(temporal_conversions::time32s_to_time(v as i32)), TimeUnit::Millisecond => { - Some(NaiveTime::from_num_seconds_from_midnight( - // extract seconds from milliseconds - v / MILLISECONDS as u32, - // discard extracted seconds and convert milliseconds to - // nanoseconds - v % MILLISECONDS as u32 * MICROSECONDS as u32, - )) - } - _ => None, - } - } - DataType::Time64(unit) => { - match unit { - TimeUnit::Microsecond => { - Some(NaiveTime::from_num_seconds_from_midnight( - // extract seconds from microseconds - (v / MICROSECONDS) as u32, - // discard extracted seconds and convert microseconds to - // nanoseconds - (v % MICROSECONDS * MILLISECONDS) as u32, - )) - } - TimeUnit::Nanosecond => { - Some(NaiveTime::from_num_seconds_from_midnight( - // extract seconds from nanoseconds - (v / NANOSECONDS) as u32, - // discard extracted seconds - (v % NANOSECONDS) as u32, - )) + Some(temporal_conversions::time32ms_to_time(v as i32)) } _ => None, } } + DataType::Time64(unit) => match unit { + TimeUnit::Microsecond => Some(temporal_conversions::time64us_to_time(v)), + TimeUnit::Nanosecond => Some(temporal_conversions::time64ns_to_time(v)), + _ => None, + }, DataType::Timestamp(_, _) => as_datetime::(v).map(|datetime| datetime.time()), DataType::Date32 | DataType::Date64 => Some(NaiveTime::from_hms(0, 0, 0)), DataType::Interval(_) => None, diff --git a/rust/arrow/src/lib.rs b/rust/arrow/src/lib.rs index 170997dc5f6..c082d6136e2 100644 --- a/rust/arrow/src/lib.rs +++ b/rust/arrow/src/lib.rs @@ -149,6 +149,7 @@ pub mod ipc; pub mod json; pub mod memory; pub mod record_batch; +pub mod temporal_conversions; pub mod tensor; pub mod util; mod zz_memory_check; diff --git a/rust/arrow/src/temporal_conversions.rs b/rust/arrow/src/temporal_conversions.rs new file mode 100644 index 00000000000..4033839e7d9 --- /dev/null +++ b/rust/arrow/src/temporal_conversions.rs @@ -0,0 +1,127 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +//! Conversion methods for dates and times. + +use chrono::{NaiveDateTime, NaiveTime}; + +/// Number of seconds in a day +const SECONDS_IN_DAY: i64 = 86_400; +/// Number of milliseconds in a second +const MILLISECONDS: i64 = 1_000; +/// Number of microseconds in a second +const MICROSECONDS: i64 = 1_000_000; +/// Number of nanoseconds in a second +const NANOSECONDS: i64 = 1_000_000_000; + +/// converts a `i32` representing a `date32` to [`NaiveDateTime`] +#[inline] +pub fn date32_to_datetime(v: i32) -> NaiveDateTime { + NaiveDateTime::from_timestamp(v as i64 * SECONDS_IN_DAY, 0) +} + +/// converts a `i64` representing a `date64` to [`NaiveDateTime`] +#[inline] +pub fn date64_to_datetime(v: i64) -> NaiveDateTime { + NaiveDateTime::from_timestamp( + // extract seconds from milliseconds + v / MILLISECONDS, + // discard extracted seconds and convert milliseconds to nanoseconds + (v % MILLISECONDS * MICROSECONDS) as u32, + ) +} + +/// converts a `i32` representing a `time32(s)` to [`NaiveDateTime`] +#[inline] +pub fn time32s_to_time(v: i32) -> NaiveTime { + NaiveTime::from_num_seconds_from_midnight(v as u32, 0) +} + +/// converts a `i32` representing a `time32(ms)` to [`NaiveDateTime`] +#[inline] +pub fn time32ms_to_time(v: i32) -> NaiveTime { + let v = v as i64; + NaiveTime::from_num_seconds_from_midnight( + // extract seconds from milliseconds + (v / MILLISECONDS) as u32, + // discard extracted seconds and convert milliseconds to + // nanoseconds + (v % MILLISECONDS * MICROSECONDS) as u32, + ) +} + +/// converts a `i64` representing a `time64(us)` to [`NaiveDateTime`] +#[inline] +pub fn time64us_to_time(v: i64) -> NaiveTime { + NaiveTime::from_num_seconds_from_midnight( + // extract seconds from microseconds + (v / MICROSECONDS) as u32, + // discard extracted seconds and convert microseconds to + // nanoseconds + (v % MICROSECONDS * MILLISECONDS) as u32, + ) +} + +/// converts a `i64` representing a `time64(ns)` to [`NaiveDateTime`] +#[inline] +pub fn time64ns_to_time(v: i64) -> NaiveTime { + NaiveTime::from_num_seconds_from_midnight( + // extract seconds from nanoseconds + (v / NANOSECONDS) as u32, + // discard extracted seconds + (v % NANOSECONDS) as u32, + ) +} + +/// converts a `i64` representing a `timestamp(s)` to [`NaiveDateTime`] +#[inline] +pub fn timestamp_s_to_datetime(v: i64) -> NaiveDateTime { + NaiveDateTime::from_timestamp(v, 0) +} + +/// converts a `i64` representing a `timestamp(ms)` to [`NaiveDateTime`] +#[inline] +pub fn timestamp_ms_to_datetime(v: i64) -> NaiveDateTime { + NaiveDateTime::from_timestamp( + // extract seconds from milliseconds + v / MILLISECONDS, + // discard extracted seconds and convert milliseconds to nanoseconds + (v % MILLISECONDS * MICROSECONDS) as u32, + ) +} + +/// converts a `i64` representing a `timestamp(us)` to [`NaiveDateTime`] +#[inline] +pub fn timestamp_us_to_datetime(v: i64) -> NaiveDateTime { + NaiveDateTime::from_timestamp( + // extract seconds from microseconds + v / MICROSECONDS, + // discard extracted seconds and convert microseconds to nanoseconds + (v % MICROSECONDS * MILLISECONDS) as u32, + ) +} + +/// converts a `i64` representing a `timestamp(ns)` to [`NaiveDateTime`] +#[inline] +pub fn timestamp_ns_to_datetime(v: i64) -> NaiveDateTime { + NaiveDateTime::from_timestamp( + // extract seconds from nanoseconds + v / NANOSECONDS, + // discard extracted seconds + (v % NANOSECONDS) as u32, + ) +}