Path: blob/main/crates/polars-ops/src/series/ops/duration.rs
6939 views
use arrow::temporal_conversions::{MICROSECONDS, MILLISECONDS, NANOSECONDS, SECONDS_IN_DAY};1use polars_core::datatypes::{AnyValue, DataType, TimeUnit};2use polars_core::prelude::Column;3use polars_error::PolarsResult;45pub fn impl_duration(s: &[Column], time_unit: TimeUnit) -> PolarsResult<Column> {6if s.iter().any(|s| s.is_empty()) {7return Ok(Column::new_empty(8s[0].name().clone(),9&DataType::Duration(time_unit),10));11}1213// TODO: Handle overflow for UInt6414let weeks = &s[0];15let days = &s[1];16let hours = &s[2];17let minutes = &s[3];18let seconds = &s[4];19let mut milliseconds = s[5].clone();20let mut microseconds = s[6].clone();21let mut nanoseconds = s[7].clone();2223let is_scalar = |s: &Column| s.len() == 1;24let is_zero_scalar = |s: &Column| is_scalar(s) && s.get(0).unwrap() == AnyValue::Int64(0);2526// Process subseconds27let max_len = s.iter().map(|s| s.len()).max().unwrap();28let mut duration = match time_unit {29TimeUnit::Microseconds => {30if is_scalar(µseconds) {31microseconds = microseconds.new_from_index(0, max_len);32}33if !is_zero_scalar(&nanoseconds) {34microseconds = (microseconds + (nanoseconds.wrapping_trunc_div_scalar(1_000)))?;35}36if !is_zero_scalar(&milliseconds) {37microseconds = (microseconds + milliseconds * 1_000)?;38}39microseconds40},41TimeUnit::Nanoseconds => {42if is_scalar(&nanoseconds) {43nanoseconds = nanoseconds.new_from_index(0, max_len);44}45if !is_zero_scalar(µseconds) {46nanoseconds = (nanoseconds + microseconds * 1_000)?;47}48if !is_zero_scalar(&milliseconds) {49nanoseconds = (nanoseconds + milliseconds * 1_000_000)?;50}51nanoseconds52},53TimeUnit::Milliseconds => {54if is_scalar(&milliseconds) {55milliseconds = milliseconds.new_from_index(0, max_len);56}57if !is_zero_scalar(&nanoseconds) {58milliseconds = (milliseconds + (nanoseconds.wrapping_trunc_div_scalar(1_000_000)))?;59}60if !is_zero_scalar(µseconds) {61milliseconds = (milliseconds + (microseconds.wrapping_trunc_div_scalar(1_000)))?;62}63milliseconds64},65};6667// Process other duration specifiers68let multiplier = match time_unit {69TimeUnit::Nanoseconds => NANOSECONDS,70TimeUnit::Microseconds => MICROSECONDS,71TimeUnit::Milliseconds => MILLISECONDS,72};73if !is_zero_scalar(seconds) {74duration = (duration + seconds * multiplier)?;75}76if !is_zero_scalar(minutes) {77duration = (duration + minutes * multiplier * 60)?;78}79if !is_zero_scalar(hours) {80duration = (duration + hours * multiplier * 60 * 60)?;81}82if !is_zero_scalar(days) {83duration = (duration + days * multiplier * SECONDS_IN_DAY)?;84}85if !is_zero_scalar(weeks) {86duration = (duration + weeks * multiplier * SECONDS_IN_DAY * 7)?;87}8889duration.cast(&DataType::Duration(time_unit))90}919293