Path: blob/main/crates/polars-expr/src/dispatch/temporal.rs
7884 views
use polars_core::error::{PolarsResult, polars_bail};1use polars_core::prelude::*;2use polars_plan::plans::IRTemporalFunction;3use polars_utils::pl_str::PlSmallStr;45use super::*;67pub fn temporal_func_to_udf(func: IRTemporalFunction) -> SpecialEq<Arc<dyn ColumnsUdf>> {8use IRTemporalFunction::*;9match func {10Millennium => map!(datetime::millennium),11Century => map!(datetime::century),12Year => map!(datetime::year),13IsLeapYear => map!(datetime::is_leap_year),14IsoYear => map!(datetime::iso_year),15Month => map!(datetime::month),16DaysInMonth => map!(datetime::days_in_month),17Quarter => map!(datetime::quarter),18Week => map!(datetime::week),19WeekDay => map!(datetime::weekday),20#[cfg(feature = "dtype-duration")]21Duration(tu) => map_as_slice!(polars_ops::series::impl_duration, tu),22Day => map!(datetime::day),23OrdinalDay => map!(datetime::ordinal_day),24Time => map!(datetime::time),25Date => map!(datetime::date),26Datetime => map!(datetime::datetime),27Hour => map!(datetime::hour),28Minute => map!(datetime::minute),29Second => map!(datetime::second),30Millisecond => map!(datetime::millisecond),31Microsecond => map!(datetime::microsecond),32Nanosecond => map!(datetime::nanosecond),33#[cfg(feature = "dtype-duration")]34TotalDays { fractional: false } => map!(datetime::total_days),35#[cfg(feature = "dtype-duration")]36TotalDays { fractional: true } => map!(datetime::total_days_fractional),37#[cfg(feature = "dtype-duration")]38TotalHours { fractional: false } => map!(datetime::total_hours),39#[cfg(feature = "dtype-duration")]40TotalHours { fractional: true } => map!(datetime::total_hours_fractional),41#[cfg(feature = "dtype-duration")]42TotalMinutes { fractional: false } => map!(datetime::total_minutes),43#[cfg(feature = "dtype-duration")]44TotalMinutes { fractional: true } => map!(datetime::total_minutes_fractional),45#[cfg(feature = "dtype-duration")]46TotalSeconds { fractional: false } => map!(datetime::total_seconds),47#[cfg(feature = "dtype-duration")]48TotalSeconds { fractional: true } => map!(datetime::total_seconds_fractional),49#[cfg(feature = "dtype-duration")]50TotalMilliseconds { fractional: false } => map!(datetime::total_milliseconds),51#[cfg(feature = "dtype-duration")]52TotalMilliseconds { fractional: true } => map!(datetime::total_milliseconds_fractional),53#[cfg(feature = "dtype-duration")]54TotalMicroseconds { fractional: false } => map!(datetime::total_microseconds),55#[cfg(feature = "dtype-duration")]56TotalMicroseconds { fractional: true } => map!(datetime::total_microseconds_fractional),57#[cfg(feature = "dtype-duration")]58TotalNanoseconds { fractional: false } => map!(datetime::total_nanoseconds),59#[cfg(feature = "dtype-duration")]60TotalNanoseconds { fractional: true } => map!(datetime::total_nanoseconds_fractional),61ToString(format) => map!(datetime::to_string, &format),62TimeStamp(tu) => map!(datetime::timestamp, tu),63#[cfg(feature = "timezones")]64ConvertTimeZone(tz) => map!(datetime::convert_time_zone, &tz),65WithTimeUnit(tu) => map!(datetime::with_time_unit, tu),66CastTimeUnit(tu) => map!(datetime::cast_time_unit, tu),67Truncate => {68map_as_slice!(datetime::truncate)69},70#[cfg(feature = "offset_by")]71OffsetBy => {72map_as_slice!(datetime::offset_by)73},74#[cfg(feature = "month_start")]75MonthStart => map!(datetime::month_start),76#[cfg(feature = "month_end")]77MonthEnd => map!(datetime::month_end),78#[cfg(feature = "timezones")]79BaseUtcOffset => map!(datetime::base_utc_offset),80#[cfg(feature = "timezones")]81DSTOffset => map!(datetime::dst_offset),82Round => map_as_slice!(datetime::round),83Replace => map_as_slice!(datetime::replace),84#[cfg(feature = "timezones")]85ReplaceTimeZone(tz, non_existent) => {86map_as_slice!(misc::replace_time_zone, tz.as_ref(), non_existent)87},88Combine(tu) => map_as_slice!(temporal::combine, tu),89DatetimeFunction {90time_unit,91time_zone,92} => {93map_as_slice!(temporal::datetime, &time_unit, time_zone.as_ref())94},95}96}9798#[cfg(feature = "dtype-datetime")]99pub(super) fn datetime(100s: &[Column],101time_unit: &TimeUnit,102time_zone: Option<&TimeZone>,103) -> PolarsResult<Column> {104use polars_core::prelude::{DataType, DatetimeChunked};105use polars_time::prelude::DatetimeMethods;106107let col_name = PlSmallStr::from_static("datetime");108109if s.iter().any(|s| s.is_empty()) {110return Ok(Column::new_empty(111col_name,112&DataType::Datetime(113time_unit.to_owned(),114match time_zone.cloned() {115#[cfg(feature = "timezones")]116Some(v) => Some(v),117_ => {118assert!(119time_zone.is_none(),120"cannot make use of the `time_zone` argument without the 'timezones' feature enabled."121);122None123},124},125),126));127}128129let year = &s[0];130let month = &s[1];131let day = &s[2];132let hour = &s[3];133let minute = &s[4];134let second = &s[5];135let microsecond = &s[6];136let ambiguous = &s[7];137138let max_len = s.iter().map(|s| s.len()).max().unwrap();139140let mut year = year.cast(&DataType::Int32)?;141if year.len() < max_len {142year = year.new_from_index(0, max_len)143}144let year = year.i32()?;145146let mut month = month.cast(&DataType::Int8)?;147if month.len() < max_len {148month = month.new_from_index(0, max_len);149}150let month = month.i8()?;151152let mut day = day.cast(&DataType::Int8)?;153if day.len() < max_len {154day = day.new_from_index(0, max_len);155}156let day = day.i8()?;157158let mut hour = hour.cast(&DataType::Int8)?;159if hour.len() < max_len {160hour = hour.new_from_index(0, max_len);161}162let hour = hour.i8()?;163164let mut minute = minute.cast(&DataType::Int8)?;165if minute.len() < max_len {166minute = minute.new_from_index(0, max_len);167}168let minute = minute.i8()?;169170let mut second = second.cast(&DataType::Int8)?;171if second.len() < max_len {172second = second.new_from_index(0, max_len);173}174let second = second.i8()?;175176let mut nanosecond = microsecond.cast(&DataType::Int32)? * 1_000;177if nanosecond.len() < max_len {178nanosecond = nanosecond.new_from_index(0, max_len);179}180let nanosecond = nanosecond.i32()?;181182let mut _ambiguous = ambiguous.cast(&DataType::String)?;183if _ambiguous.len() < max_len {184_ambiguous = _ambiguous.new_from_index(0, max_len);185}186let ambiguous = _ambiguous.str()?;187188let ca = DatetimeChunked::new_from_parts(189year,190month,191day,192hour,193minute,194second,195nanosecond,196ambiguous,197time_unit,198time_zone.cloned(),199col_name,200);201ca.map(|s| s.into_column())202}203204pub(super) fn combine(s: &[Column], tu: TimeUnit) -> PolarsResult<Column> {205let date = &s[0];206let time = &s[1];207208let tz = match date.dtype() {209DataType::Date => None,210DataType::Datetime(_, tz) => tz.as_ref(),211_dtype => {212polars_bail!(ComputeError: format!("expected Date or Datetime, got {}", _dtype))213},214};215216let date = date.cast(&DataType::Date)?;217let datetime = date.cast(&DataType::Datetime(tu, None)).unwrap();218219let duration = time.cast(&DataType::Duration(tu))?;220let result_naive = datetime + duration;221match tz {222#[cfg(feature = "timezones")]223Some(tz) => Ok(polars_ops::prelude::replace_time_zone(224result_naive?.datetime().unwrap(),225Some(tz),226&StringChunked::from_iter(std::iter::once("raise")),227NonExistent::Raise,228)?229.into_column()),230_ => result_naive,231}232}233234235