Skip to content

Commit

Permalink
impl namedfrom for temporal types (#2575)
Browse files Browse the repository at this point in the history
  • Loading branch information
ritchie46 committed Feb 8, 2022
1 parent 41d64aa commit ea92306
Show file tree
Hide file tree
Showing 11 changed files with 222 additions and 15 deletions.
4 changes: 2 additions & 2 deletions polars/polars-core/src/chunked_array/logical/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ pub type DateChunked = Logical<DateType, Int32Type>;

impl From<Int32Chunked> for DateChunked {
fn from(ca: Int32Chunked) -> Self {
DateChunked::new(ca)
DateChunked::new_logical(ca)
}
}

impl Int32Chunked {
pub fn into_date(self) -> DateChunked {
DateChunked::new(self)
DateChunked::new_logical(self)
}
}

Expand Down
2 changes: 1 addition & 1 deletion polars/polars-core/src/chunked_array/logical/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub type DatetimeChunked = Logical<DatetimeType, Int64Type>;

impl Int64Chunked {
pub fn into_datetime(self, timeunit: TimeUnit, tz: Option<TimeZone>) -> DatetimeChunked {
let mut dt = DatetimeChunked::new(self);
let mut dt = DatetimeChunked::new_logical(self);
dt.2 = Some(DataType::Datetime(timeunit, tz));
dt
}
Expand Down
2 changes: 1 addition & 1 deletion polars/polars-core/src/chunked_array/logical/duration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub type DurationChunked = Logical<DurationType, Int64Type>;

impl Int64Chunked {
pub fn into_duration(self, timeunit: TimeUnit) -> DurationChunked {
let mut dt = DurationChunked::new(self);
let mut dt = DurationChunked::new_logical(self);
dt.2 = Some(DataType::Duration(timeunit));
dt
}
Expand Down
4 changes: 2 additions & 2 deletions polars/polars-core/src/chunked_array/logical/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub struct Logical<K: PolarsDataType, T: PolarsDataType>(

impl<K: PolarsDataType, T: PolarsDataType> Clone for Logical<K, T> {
fn clone(&self) -> Self {
let mut new = Logical::<K, _>::new(self.0.clone());
let mut new = Logical::<K, _>::new_logical(self.0.clone());
new.2 = self.2.clone();
new
}
Expand All @@ -40,7 +40,7 @@ impl<K: PolarsDataType, T: PolarsDataType> DerefMut for Logical<K, T> {
}

impl<K: PolarsDataType, T: PolarsDataType> Logical<K, T> {
pub fn new<J: PolarsDataType>(ca: ChunkedArray<T>) -> Logical<J, T> {
pub fn new_logical<J: PolarsDataType>(ca: ChunkedArray<T>) -> Logical<J, T> {
Logical(ca, PhantomData, None)
}
}
Expand Down
4 changes: 2 additions & 2 deletions polars/polars-core/src/chunked_array/logical/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ pub type TimeChunked = Logical<TimeType, Int64Type>;

impl From<Int64Chunked> for TimeChunked {
fn from(ca: Int64Chunked) -> Self {
TimeChunked::new(ca)
TimeChunked::new_logical(ca)
}
}

impl Int64Chunked {
pub fn into_time(self) -> TimeChunked {
TimeChunked::new(self)
TimeChunked::new_logical(self)
}
}

Expand Down
4 changes: 3 additions & 1 deletion polars/polars-core/src/chunked_array/ops/sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,9 @@ pub(crate) fn prepare_argsort(
.map(|s| {
use DataType::*;
match s.dtype() {
Float32 | Float64 | Int32 | Int64 | Utf8 | UInt32 | UInt64 => s.clone(),
Categorical | Float32 | Float64 | Int32 | Int64 | Utf8 | UInt32 | UInt64 => {
s.clone()
}
_ => {
// small integers i8, u8 etc are casted to reduce compiler bloat
// not that we don't expect any logical types at this point
Expand Down
9 changes: 9 additions & 0 deletions polars/polars-core/src/chunked_array/temporal/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ impl DateChunked {
Int32Chunked::from_vec(name, unit).into()
}

/// Construct a new [`DateChunked`] from an iterator over optional [`NaiveDate`].
pub fn from_naive_date_options<I: IntoIterator<Item = Option<NaiveDate>>>(
name: &str,
v: I,
) -> Self {
let unit = v.into_iter().map(|opt| opt.map(naive_date_to_date));
Int32Chunked::from_iter_options(name, unit).into()
}

pub fn parse_from_str_slice(name: &str, v: &[&str], fmt: &str) -> Self {
Int32Chunked::from_iter_options(
name,
Expand Down
13 changes: 13 additions & 0 deletions polars/polars-core/src/chunked_array/temporal/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,19 @@ impl DatetimeChunked {
Int64Chunked::from_vec(name, vals).into_datetime(tu, None)
}

pub fn from_naive_datetime_options<I: IntoIterator<Item = Option<NaiveDateTime>>>(
name: &str,
v: I,
tu: TimeUnit,
) -> Self {
let func = match tu {
TimeUnit::Nanoseconds => naive_datetime_to_datetime_ns,
TimeUnit::Milliseconds => naive_datetime_to_datetime_ms,
};
let vals = v.into_iter().map(|opt_nd| opt_nd.map(|nd| (func(&nd))));
Int64Chunked::from_iter_options(name, vals).into_datetime(tu, None)
}

pub fn parse_from_str_slice(name: &str, v: &[&str], fmt: &str, tu: TimeUnit) -> Self {
let func = match tu {
TimeUnit::Nanoseconds => naive_datetime_to_datetime_ns,
Expand Down
14 changes: 14 additions & 0 deletions polars/polars-core/src/chunked_array/temporal/duration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ impl DurationChunked {
Int64Chunked::from_vec(name, vals).into_duration(tu)
}

/// Construct a new [`DurationChunked`] from an iterator over optional [`ChronoDuration`].
pub fn from_duration_options<I: IntoIterator<Item = Option<ChronoDuration>>>(
name: &str,
v: I,
tu: TimeUnit,
) -> Self {
let func = match tu {
TimeUnit::Nanoseconds => |v: ChronoDuration| v.num_nanoseconds().unwrap(),
TimeUnit::Milliseconds => |v: ChronoDuration| v.num_milliseconds(),
};
let vals = v.into_iter().map(|opt| opt.map(func));
Int64Chunked::from_iter_options(name, vals).into_duration(tu)
}

/// Extract the hours from a `Duration`
pub fn hours(&self) -> Int64Chunked {
match self.time_unit() {
Expand Down
21 changes: 15 additions & 6 deletions polars/polars-core/src/chunked_array/temporal/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use crate::chunked_array::kernels::temporal::{
time_to_hour, time_to_minute, time_to_nanosecond, time_to_second,
};
use crate::prelude::*;
use crate::utils::NoNull;
use arrow::temporal_conversions::{time64ns_to_time, NANOSECONDS};
use chrono::Timelike;

Expand Down Expand Up @@ -63,11 +62,21 @@ impl TimeChunked {
}

/// Construct a new [`TimeChunked`] from an iterator over [`NaiveTime`].
pub fn from_naive_time(name: &str, v: &[NaiveTime]) -> Self {
let ca: NoNull<Int64Chunked> = v.iter().map(time_to_time64ns).collect_trusted();
let mut ca = ca.into_inner();
ca.rename(name);
ca.into()
pub fn from_naive_time<I: IntoIterator<Item = NaiveTime>>(name: &str, v: I) -> Self {
let vals = v
.into_iter()
.map(|nt| time_to_time64ns(&nt))
.collect::<Vec<_>>();
Int64Chunked::from_vec(name, vals).into_time()
}

/// Construct a new [`TimeChunked`] from an iterator over optional [`NaiveTime`].
pub fn from_naive_time_options<I: IntoIterator<Item = Option<NaiveTime>>>(
name: &str,
v: I,
) -> Self {
let vals = v.into_iter().map(|opt| opt.map(|nt| time_to_time64ns(&nt)));
Int64Chunked::from_iter_options(name, vals).into_time()
}

pub fn parse_from_str_slice(name: &str, v: &[&str], fmt: &str) -> Self {
Expand Down
160 changes: 160 additions & 0 deletions polars/polars-core/src/named_from.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
use crate::chunked_array::builder::{get_list_builder, AnonymousListBuilder};
use crate::prelude::*;
#[cfg(feature = "dtype-duration")]
use chrono::Duration as ChronoDuration;
#[cfg(feature = "dtype-date")]
use chrono::NaiveDate;
#[cfg(feature = "dtype-datetime")]
use chrono::NaiveDateTime;
#[cfg(feature = "dtype-time")]
use chrono::NaiveTime;
use std::borrow::Cow;

pub trait NamedFrom<T, Phantom: ?Sized> {
Expand Down Expand Up @@ -194,6 +202,132 @@ impl<'a, T: AsRef<[Option<Cow<'a, str>>]>> NamedFrom<T, [Option<Cow<'a, str>>]>
}
}

#[cfg(feature = "dtype-date")]
impl<T: AsRef<[NaiveDate]>> NamedFrom<T, [NaiveDate]> for DateChunked {
fn new(name: &str, v: T) -> Self {
DateChunked::from_naive_date(name, v.as_ref().iter().copied())
}
}

#[cfg(feature = "dtype-date")]
impl<T: AsRef<[NaiveDate]>> NamedFrom<T, [NaiveDate]> for Series {
fn new(name: &str, v: T) -> Self {
DateChunked::new(name, v).into_series()
}
}

#[cfg(feature = "dtype-date")]
impl<T: AsRef<[Option<NaiveDate>]>> NamedFrom<T, [Option<NaiveDate>]> for DateChunked {
fn new(name: &str, v: T) -> Self {
DateChunked::from_naive_date_options(name, v.as_ref().iter().copied())
}
}

#[cfg(feature = "dtype-date")]
impl<T: AsRef<[Option<NaiveDate>]>> NamedFrom<T, [Option<NaiveDate>]> for Series {
fn new(name: &str, v: T) -> Self {
DateChunked::new(name, v).into_series()
}
}

#[cfg(feature = "dtype-datetime")]
impl<T: AsRef<[NaiveDateTime]>> NamedFrom<T, [NaiveDateTime]> for DatetimeChunked {
fn new(name: &str, v: T) -> Self {
DatetimeChunked::from_naive_datetime(
name,
v.as_ref().iter().copied(),
TimeUnit::Milliseconds,
)
}
}

#[cfg(feature = "dtype-datetime")]
impl<T: AsRef<[NaiveDateTime]>> NamedFrom<T, [NaiveDateTime]> for Series {
fn new(name: &str, v: T) -> Self {
DatetimeChunked::new(name, v).into_series()
}
}

#[cfg(feature = "dtype-datetime")]
impl<T: AsRef<[Option<NaiveDateTime>]>> NamedFrom<T, [Option<NaiveDateTime>]> for DatetimeChunked {
fn new(name: &str, v: T) -> Self {
DatetimeChunked::from_naive_datetime_options(
name,
v.as_ref().iter().copied(),
TimeUnit::Milliseconds,
)
}
}

#[cfg(feature = "dtype-datetime")]
impl<T: AsRef<[Option<NaiveDateTime>]>> NamedFrom<T, [Option<NaiveDateTime>]> for Series {
fn new(name: &str, v: T) -> Self {
DatetimeChunked::new(name, v).into_series()
}
}

#[cfg(feature = "dtype-duration")]
impl<T: AsRef<[ChronoDuration]>> NamedFrom<T, [ChronoDuration]> for DurationChunked {
fn new(name: &str, v: T) -> Self {
DurationChunked::from_duration(name, v.as_ref().iter().copied(), TimeUnit::Nanoseconds)
}
}

#[cfg(feature = "dtype-duration")]
impl<T: AsRef<[ChronoDuration]>> NamedFrom<T, [ChronoDuration]> for Series {
fn new(name: &str, v: T) -> Self {
DurationChunked::new(name, v).into_series()
}
}

#[cfg(feature = "dtype-duration")]
impl<T: AsRef<[Option<ChronoDuration>]>> NamedFrom<T, [Option<ChronoDuration>]>
for DurationChunked
{
fn new(name: &str, v: T) -> Self {
DurationChunked::from_duration_options(
name,
v.as_ref().iter().copied(),
TimeUnit::Nanoseconds,
)
}
}

#[cfg(feature = "dtype-duration")]
impl<T: AsRef<[Option<ChronoDuration>]>> NamedFrom<T, [Option<ChronoDuration>]> for Series {
fn new(name: &str, v: T) -> Self {
DurationChunked::new(name, v).into_series()
}
}

#[cfg(feature = "dtype-time")]
impl<T: AsRef<[NaiveTime]>> NamedFrom<T, [NaiveTime]> for TimeChunked {
fn new(name: &str, v: T) -> Self {
TimeChunked::from_naive_time(name, v.as_ref().iter().copied())
}
}

#[cfg(feature = "dtype-time")]
impl<T: AsRef<[NaiveTime]>> NamedFrom<T, [NaiveTime]> for Series {
fn new(name: &str, v: T) -> Self {
TimeChunked::new(name, v).into_series()
}
}

#[cfg(feature = "dtype-time")]
impl<T: AsRef<[Option<NaiveTime>]>> NamedFrom<T, [Option<NaiveTime>]> for TimeChunked {
fn new(name: &str, v: T) -> Self {
TimeChunked::from_naive_time_options(name, v.as_ref().iter().copied())
}
}

#[cfg(feature = "dtype-time")]
impl<T: AsRef<[Option<NaiveTime>]>> NamedFrom<T, [Option<NaiveTime>]> for Series {
fn new(name: &str, v: T) -> Self {
TimeChunked::new(name, v).into_series()
}
}

#[cfg(feature = "object")]
impl<T: PolarsObject> NamedFrom<&[T], &[T]> for ObjectChunked<T> {
fn new(name: &str, v: &[T]) -> Self {
Expand All @@ -215,3 +349,29 @@ impl<T: PolarsNumericType> ChunkedArray<T> {
ChunkedArray::from_vec(name, v)
}
}

#[cfg(test)]
mod test {
use super::*;

#[cfg(all(
feature = "dtype-datetime",
feature = "dtype-duration",
feature = "dtype-date",
feature = "dtype-time"
))]
#[test]
fn test_temporal_df_construction() {
// check if we can construct.
let _df = df![
"date" => [NaiveDate::from_ymd(2021, 1, 1)],
"datetime" => [NaiveDate::from_ymd(2021, 1, 1).and_hms(0, 0, 0)],
"optional_date" => [Some(NaiveDate::from_ymd(2021, 1, 1))],
"optional_datetime" => [Some(NaiveDate::from_ymd(2021, 1, 1).and_hms(0, 0, 0))],
"time" => [NaiveTime::from_hms(23, 23, 23)],
"optional_time" => [Some(NaiveTime::from_hms(23, 23, 23))],
"duration" => [ChronoDuration::from_std(std::time::Duration::from_secs(10)).unwrap()],
"optional_duration" => [Some(ChronoDuration::from_std(std::time::Duration::from_secs(10)).unwrap())],
].unwrap();
}
}

0 comments on commit ea92306

Please sign in to comment.