use arrow::temporal_conversions::{EPOCH_DAYS_FROM_CE, MILLISECONDS, SECONDS_IN_DAY};
use chrono::{Datelike, NaiveDate};
use super::*;
pub(crate) fn naive_date_to_date(nd: NaiveDate) -> i32 {
let nt = NaiveTime::from_hms_opt(0, 0, 0).unwrap();
let ndt = NaiveDateTime::new(nd, nt);
naive_datetime_to_date(ndt)
}
pub(crate) fn naive_datetime_to_date(v: NaiveDateTime) -> i32 {
(datetime_to_timestamp_ms(v) / (MILLISECONDS * SECONDS_IN_DAY)) as i32
}
pub trait DateMethods: AsDate {
fn year(&self) -> Int32Chunked {
let ca = self.as_date();
ca.physical().apply_kernel_cast::<Int32Type>(&date_to_year)
}
fn is_leap_year(&self) -> BooleanChunked {
let ca = self.as_date();
ca.physical()
.apply_kernel_cast::<BooleanType>(&date_to_is_leap_year)
}
fn iso_year(&self) -> Int32Chunked {
let ca = self.as_date();
ca.physical()
.apply_kernel_cast::<Int32Type>(&date_to_iso_year)
}
fn quarter(&self) -> Int8Chunked {
let months = self.month();
months_to_quarters(months)
}
fn month(&self) -> Int8Chunked {
let ca = self.as_date();
ca.physical().apply_kernel_cast::<Int8Type>(&date_to_month)
}
fn days_in_month(&self) -> Int8Chunked {
let ca = self.as_date();
ca.physical()
.apply_kernel_cast::<Int8Type>(&date_to_days_in_month)
}
fn week(&self) -> Int8Chunked {
let ca = self.as_date();
ca.physical()
.apply_kernel_cast::<Int8Type>(&date_to_iso_week)
}
fn day(&self) -> Int8Chunked {
let ca = self.as_date();
ca.physical().apply_kernel_cast::<Int8Type>(&date_to_day)
}
fn ordinal(&self) -> Int16Chunked {
let ca = self.as_date();
ca.physical()
.apply_kernel_cast::<Int16Type>(&date_to_ordinal)
}
fn parse_from_str_slice(name: PlSmallStr, v: &[&str], fmt: &str) -> DateChunked;
fn new_from_parts(
year: &Int32Chunked,
month: &Int8Chunked,
day: &Int8Chunked,
name: PlSmallStr,
) -> PolarsResult<DateChunked> {
let ca: Int32Chunked = year
.iter()
.zip(month.iter())
.zip(day.iter())
.map(|((y, m), d)| {
if let (Some(y), Some(m), Some(d)) = (y, m, d) {
NaiveDate::from_ymd_opt(y, m as u32, d as u32).map_or_else(
|| polars_bail!(ComputeError: "Invalid date components ({y}, {m}, {d}) supplied"),
|date| Ok(Some(date.num_days_from_ce() - EPOCH_DAYS_FROM_CE)),
)
} else {
Ok(None)
}
})
.try_collect_ca_with_dtype(name, DataType::Int32)?;
Ok(ca.into_date())
}
}
impl DateMethods for DateChunked {
fn parse_from_str_slice(name: PlSmallStr, v: &[&str], fmt: &str) -> DateChunked {
Int32Chunked::from_iter_options(
name,
v.iter().map(|s| {
NaiveDate::parse_from_str(s, fmt)
.ok()
.as_ref()
.map(|v| naive_date_to_date(*v))
}),
)
.into_date()
}
}
pub trait AsDate {
fn as_date(&self) -> &DateChunked;
}
impl AsDate for DateChunked {
fn as_date(&self) -> &DateChunked {
self
}
}