polars_core/series/implementations/
duration.rs

1use polars_compute::rolling::QuantileMethod;
2
3use super::*;
4use crate::chunked_array::comparison::*;
5#[cfg(feature = "algorithm_group_by")]
6use crate::frame::group_by::*;
7use crate::prelude::*;
8
9unsafe impl IntoSeries for DurationChunked {
10    fn into_series(self) -> Series {
11        Series(Arc::new(SeriesWrap(self)))
12    }
13}
14
15impl private::PrivateSeriesNumeric for SeriesWrap<DurationChunked> {
16    fn bit_repr(&self) -> Option<BitRepr> {
17        Some(self.0.physical().to_bit_repr())
18    }
19}
20
21impl private::PrivateSeries for SeriesWrap<DurationChunked> {
22    fn compute_len(&mut self) {
23        self.0.physical_mut().compute_len()
24    }
25    fn _field(&self) -> Cow<'_, Field> {
26        Cow::Owned(self.0.field())
27    }
28    fn _dtype(&self) -> &DataType {
29        self.0.dtype()
30    }
31
32    fn _set_flags(&mut self, flags: StatisticsFlags) {
33        self.0.physical_mut().set_flags(flags)
34    }
35
36    fn _get_flags(&self) -> StatisticsFlags {
37        self.0.physical().get_flags()
38    }
39
40    unsafe fn equal_element(&self, idx_self: usize, idx_other: usize, other: &Series) -> bool {
41        self.0.physical().equal_element(idx_self, idx_other, other)
42    }
43
44    #[cfg(feature = "zip_with")]
45    fn zip_with_same_type(&self, mask: &BooleanChunked, other: &Series) -> PolarsResult<Series> {
46        let other = other.to_physical_repr().into_owned();
47        self.0
48            .physical()
49            .zip_with(mask, other.as_ref().as_ref())
50            .map(|ca| ca.into_duration(self.0.time_unit()).into_series())
51    }
52
53    fn into_total_eq_inner<'a>(&'a self) -> Box<dyn TotalEqInner + 'a> {
54        self.0.physical().into_total_eq_inner()
55    }
56    fn into_total_ord_inner<'a>(&'a self) -> Box<dyn TotalOrdInner + 'a> {
57        self.0.physical().into_total_ord_inner()
58    }
59
60    fn vec_hash(
61        &self,
62        random_state: PlSeedableRandomStateQuality,
63        buf: &mut Vec<u64>,
64    ) -> PolarsResult<()> {
65        self.0.physical().vec_hash(random_state, buf)?;
66        Ok(())
67    }
68
69    fn vec_hash_combine(
70        &self,
71        build_hasher: PlSeedableRandomStateQuality,
72        hashes: &mut [u64],
73    ) -> PolarsResult<()> {
74        self.0.physical().vec_hash_combine(build_hasher, hashes)?;
75        Ok(())
76    }
77
78    #[cfg(feature = "algorithm_group_by")]
79    unsafe fn agg_min(&self, groups: &GroupsType) -> Series {
80        self.0
81            .physical()
82            .agg_min(groups)
83            .into_duration(self.0.time_unit())
84            .into_series()
85    }
86
87    #[cfg(feature = "algorithm_group_by")]
88    unsafe fn agg_max(&self, groups: &GroupsType) -> Series {
89        self.0
90            .physical()
91            .agg_max(groups)
92            .into_duration(self.0.time_unit())
93            .into_series()
94    }
95
96    #[cfg(feature = "algorithm_group_by")]
97    unsafe fn agg_sum(&self, groups: &GroupsType) -> Series {
98        self.0
99            .physical()
100            .agg_sum(groups)
101            .into_duration(self.0.time_unit())
102            .into_series()
103    }
104
105    #[cfg(feature = "algorithm_group_by")]
106    unsafe fn agg_std(&self, groups: &GroupsType, ddof: u8) -> Series {
107        self.0
108            .physical()
109            .agg_std(groups, ddof)
110            // cast f64 back to physical type
111            .cast(&DataType::Int64)
112            .unwrap()
113            .into_duration(self.0.time_unit())
114            .into_series()
115    }
116
117    #[cfg(feature = "algorithm_group_by")]
118    unsafe fn agg_var(&self, groups: &GroupsType, ddof: u8) -> Series {
119        self.0
120            .physical()
121            .agg_var(groups, ddof)
122            // cast f64 back to physical type
123            .cast(&DataType::Int64)
124            .unwrap()
125            .into_duration(self.0.time_unit())
126            .into_series()
127    }
128
129    #[cfg(feature = "algorithm_group_by")]
130    unsafe fn agg_list(&self, groups: &GroupsType) -> Series {
131        // we cannot cast and dispatch as the inner type of the list would be incorrect
132        self.0
133            .physical()
134            .agg_list(groups)
135            .cast(&DataType::List(Box::new(self.dtype().clone())))
136            .unwrap()
137    }
138
139    fn subtract(&self, rhs: &Series) -> PolarsResult<Series> {
140        match (self.dtype(), rhs.dtype()) {
141            (DataType::Duration(tu), DataType::Duration(tur)) => {
142                polars_ensure!(tu == tur, InvalidOperation: "units are different");
143                let lhs = self.cast(&DataType::Int64, CastOptions::NonStrict).unwrap();
144                let rhs = rhs.cast(&DataType::Int64).unwrap();
145                Ok(lhs.subtract(&rhs)?.into_duration(*tu).into_series())
146            },
147            (dtl, dtr) => polars_bail!(opq = sub, dtl, dtr),
148        }
149    }
150    fn add_to(&self, rhs: &Series) -> PolarsResult<Series> {
151        match (self.dtype(), rhs.dtype()) {
152            (DataType::Duration(tu), DataType::Duration(tur)) => {
153                polars_ensure!(tu == tur, InvalidOperation: "units are different");
154                let lhs = self.cast(&DataType::Int64, CastOptions::NonStrict).unwrap();
155                let rhs = rhs.cast(&DataType::Int64).unwrap();
156                Ok(lhs.add_to(&rhs)?.into_duration(*tu).into_series())
157            },
158            (DataType::Duration(tu), DataType::Date) => {
159                let one_day_in_tu: i64 = match tu {
160                    TimeUnit::Milliseconds => 86_400_000,
161                    TimeUnit::Microseconds => 86_400_000_000,
162                    TimeUnit::Nanoseconds => 86_400_000_000_000,
163                };
164                let lhs =
165                    self.cast(&DataType::Int64, CastOptions::NonStrict).unwrap() / one_day_in_tu;
166                let rhs = rhs
167                    .cast(&DataType::Int32)
168                    .unwrap()
169                    .cast(&DataType::Int64)
170                    .unwrap();
171                Ok(lhs
172                    .add_to(&rhs)?
173                    .cast(&DataType::Int32)?
174                    .into_date()
175                    .into_series())
176            },
177            (DataType::Duration(tu), DataType::Datetime(tur, tz)) => {
178                polars_ensure!(tu == tur, InvalidOperation: "units are different");
179                let lhs = self.cast(&DataType::Int64, CastOptions::NonStrict).unwrap();
180                let rhs = rhs.cast(&DataType::Int64).unwrap();
181                Ok(lhs
182                    .add_to(&rhs)?
183                    .into_datetime(*tu, tz.clone())
184                    .into_series())
185            },
186            (dtl, dtr) => polars_bail!(opq = add, dtl, dtr),
187        }
188    }
189    fn multiply(&self, rhs: &Series) -> PolarsResult<Series> {
190        let tul = self.0.time_unit();
191        match rhs.dtype() {
192            DataType::Int64 => Ok((&self.0.phys * rhs.i64().unwrap())
193                .into_duration(tul)
194                .into_series()),
195            dt if dt.is_integer() => {
196                let rhs = rhs.cast(&DataType::Int64)?;
197                self.multiply(&rhs)
198            },
199            dt if dt.is_float() => {
200                let phys = &self.0.phys;
201                let phys_float = phys.cast(dt).unwrap();
202                let out = std::ops::Mul::mul(&phys_float, rhs)?
203                    .cast(&DataType::Int64)
204                    .unwrap();
205                let phys = out.i64().unwrap().clone();
206                Ok(phys.into_duration(tul).into_series())
207            },
208            _ => {
209                polars_bail!(opq = mul, self.dtype(), rhs.dtype());
210            },
211        }
212    }
213    fn divide(&self, rhs: &Series) -> PolarsResult<Series> {
214        let tul = self.0.time_unit();
215        match rhs.dtype() {
216            DataType::Duration(tur) => {
217                if tul == *tur {
218                    // Returns a constant as f64.
219                    Ok(std::ops::Div::div(
220                        &self.0.phys.cast(&DataType::Float64).unwrap(),
221                        &rhs.duration()
222                            .unwrap()
223                            .phys
224                            .cast(&DataType::Float64)
225                            .unwrap(),
226                    )?
227                    .into_series())
228                } else {
229                    let rhs = rhs.cast(self.dtype())?;
230                    self.divide(&rhs)
231                }
232            },
233            DataType::Int64 => Ok((&self.0.phys / rhs.i64().unwrap())
234                .into_duration(tul)
235                .into_series()),
236            dt if dt.is_integer() => {
237                let rhs = rhs.cast(&DataType::Int64)?;
238                self.divide(&rhs)
239            },
240            dt if dt.is_float() => {
241                let phys = &self.0.phys;
242                let phys_float = phys.cast(dt).unwrap();
243                let out = std::ops::Div::div(&phys_float, rhs)?
244                    .cast(&DataType::Int64)
245                    .unwrap();
246                let phys = out.i64().unwrap().clone();
247                Ok(phys.into_duration(tul).into_series())
248            },
249            _ => {
250                polars_bail!(opq = div, self.dtype(), rhs.dtype());
251            },
252        }
253    }
254    fn remainder(&self, rhs: &Series) -> PolarsResult<Series> {
255        polars_ensure!(self.dtype() == rhs.dtype(), InvalidOperation: "dtypes and units must be equal in duration arithmetic");
256        let lhs = self.cast(&DataType::Int64, CastOptions::NonStrict).unwrap();
257        let rhs = rhs.cast(&DataType::Int64).unwrap();
258        Ok(lhs
259            .remainder(&rhs)?
260            .into_duration(self.0.time_unit())
261            .into_series())
262    }
263    #[cfg(feature = "algorithm_group_by")]
264    fn group_tuples(&self, multithreaded: bool, sorted: bool) -> PolarsResult<GroupsType> {
265        self.0.physical().group_tuples(multithreaded, sorted)
266    }
267
268    fn arg_sort_multiple(
269        &self,
270        by: &[Column],
271        options: &SortMultipleOptions,
272    ) -> PolarsResult<IdxCa> {
273        self.0.physical().arg_sort_multiple(by, options)
274    }
275}
276
277impl SeriesTrait for SeriesWrap<DurationChunked> {
278    fn rename(&mut self, name: PlSmallStr) {
279        self.0.rename(name);
280    }
281
282    fn chunk_lengths(&self) -> ChunkLenIter<'_> {
283        self.0.physical().chunk_lengths()
284    }
285    fn name(&self) -> &PlSmallStr {
286        self.0.name()
287    }
288
289    fn chunks(&self) -> &Vec<ArrayRef> {
290        self.0.physical().chunks()
291    }
292    unsafe fn chunks_mut(&mut self) -> &mut Vec<ArrayRef> {
293        self.0.physical_mut().chunks_mut()
294    }
295
296    fn shrink_to_fit(&mut self) {
297        self.0.physical_mut().shrink_to_fit()
298    }
299
300    fn slice(&self, offset: i64, length: usize) -> Series {
301        self.0.slice(offset, length).into_series()
302    }
303
304    fn split_at(&self, offset: i64) -> (Series, Series) {
305        let (a, b) = self.0.split_at(offset);
306        (a.into_series(), b.into_series())
307    }
308
309    fn _sum_as_f64(&self) -> f64 {
310        self.0.physical()._sum_as_f64()
311    }
312
313    fn mean(&self) -> Option<f64> {
314        self.0.physical().mean()
315    }
316
317    fn median(&self) -> Option<f64> {
318        self.0.physical().median()
319    }
320
321    fn std(&self, ddof: u8) -> Option<f64> {
322        self.0.physical().std(ddof)
323    }
324
325    fn var(&self, ddof: u8) -> Option<f64> {
326        self.0.physical().var(ddof)
327    }
328
329    fn append(&mut self, other: &Series) -> PolarsResult<()> {
330        polars_ensure!(self.0.dtype() == other.dtype(), append);
331        let mut other = other.to_physical_repr().into_owned();
332        self.0
333            .physical_mut()
334            .append_owned(std::mem::take(other._get_inner_mut().as_mut()))
335    }
336    fn append_owned(&mut self, mut other: Series) -> PolarsResult<()> {
337        polars_ensure!(self.0.dtype() == other.dtype(), append);
338        self.0.physical_mut().append_owned(std::mem::take(
339            &mut other
340                ._get_inner_mut()
341                .as_any_mut()
342                .downcast_mut::<DurationChunked>()
343                .unwrap()
344                .phys,
345        ))
346    }
347
348    fn extend(&mut self, other: &Series) -> PolarsResult<()> {
349        polars_ensure!(self.0.dtype() == other.dtype(), extend);
350        let other = other.to_physical_repr();
351        self.0
352            .physical_mut()
353            .extend(other.as_ref().as_ref().as_ref())?;
354        Ok(())
355    }
356
357    fn filter(&self, filter: &BooleanChunked) -> PolarsResult<Series> {
358        self.0
359            .physical()
360            .filter(filter)
361            .map(|ca| ca.into_duration(self.0.time_unit()).into_series())
362    }
363
364    fn take(&self, indices: &IdxCa) -> PolarsResult<Series> {
365        Ok(self
366            .0
367            .physical()
368            .take(indices)?
369            .into_duration(self.0.time_unit())
370            .into_series())
371    }
372
373    unsafe fn take_unchecked(&self, indices: &IdxCa) -> Series {
374        self.0
375            .physical()
376            .take_unchecked(indices)
377            .into_duration(self.0.time_unit())
378            .into_series()
379    }
380
381    fn take_slice(&self, indices: &[IdxSize]) -> PolarsResult<Series> {
382        Ok(self
383            .0
384            .physical()
385            .take(indices)?
386            .into_duration(self.0.time_unit())
387            .into_series())
388    }
389
390    unsafe fn take_slice_unchecked(&self, indices: &[IdxSize]) -> Series {
391        self.0
392            .physical()
393            .take_unchecked(indices)
394            .into_duration(self.0.time_unit())
395            .into_series()
396    }
397
398    fn len(&self) -> usize {
399        self.0.len()
400    }
401
402    fn rechunk(&self) -> Series {
403        self.0
404            .physical()
405            .rechunk()
406            .into_owned()
407            .into_duration(self.0.time_unit())
408            .into_series()
409    }
410
411    fn new_from_index(&self, index: usize, length: usize) -> Series {
412        self.0
413            .physical()
414            .new_from_index(index, length)
415            .into_duration(self.0.time_unit())
416            .into_series()
417    }
418
419    fn cast(&self, dtype: &DataType, cast_options: CastOptions) -> PolarsResult<Series> {
420        self.0.cast_with_options(dtype, cast_options)
421    }
422
423    #[inline]
424    unsafe fn get_unchecked(&self, index: usize) -> AnyValue<'_> {
425        self.0.get_any_value_unchecked(index)
426    }
427
428    fn sort_with(&self, options: SortOptions) -> PolarsResult<Series> {
429        Ok(self
430            .0
431            .physical()
432            .sort_with(options)
433            .into_duration(self.0.time_unit())
434            .into_series())
435    }
436
437    fn arg_sort(&self, options: SortOptions) -> IdxCa {
438        self.0.physical().arg_sort(options)
439    }
440
441    fn null_count(&self) -> usize {
442        self.0.null_count()
443    }
444
445    fn has_nulls(&self) -> bool {
446        self.0.has_nulls()
447    }
448
449    #[cfg(feature = "algorithm_group_by")]
450    fn unique(&self) -> PolarsResult<Series> {
451        self.0
452            .physical()
453            .unique()
454            .map(|ca| ca.into_duration(self.0.time_unit()).into_series())
455    }
456
457    #[cfg(feature = "algorithm_group_by")]
458    fn n_unique(&self) -> PolarsResult<usize> {
459        self.0.physical().n_unique()
460    }
461
462    #[cfg(feature = "algorithm_group_by")]
463    fn arg_unique(&self) -> PolarsResult<IdxCa> {
464        self.0.physical().arg_unique()
465    }
466
467    fn is_null(&self) -> BooleanChunked {
468        self.0.is_null()
469    }
470
471    fn is_not_null(&self) -> BooleanChunked {
472        self.0.is_not_null()
473    }
474
475    fn reverse(&self) -> Series {
476        self.0
477            .physical()
478            .reverse()
479            .into_duration(self.0.time_unit())
480            .into_series()
481    }
482
483    fn as_single_ptr(&mut self) -> PolarsResult<usize> {
484        self.0.physical_mut().as_single_ptr()
485    }
486
487    fn shift(&self, periods: i64) -> Series {
488        self.0
489            .physical()
490            .shift(periods)
491            .into_duration(self.0.time_unit())
492            .into_series()
493    }
494
495    fn sum_reduce(&self) -> PolarsResult<Scalar> {
496        let sc = self.0.physical().sum_reduce();
497        let v = sc.value().as_duration(self.0.time_unit());
498        Ok(Scalar::new(self.dtype().clone(), v))
499    }
500
501    fn max_reduce(&self) -> PolarsResult<Scalar> {
502        let sc = self.0.physical().max_reduce();
503        let v = sc.value().as_duration(self.0.time_unit());
504        Ok(Scalar::new(self.dtype().clone(), v))
505    }
506    fn min_reduce(&self) -> PolarsResult<Scalar> {
507        let sc = self.0.physical().min_reduce();
508        let v = sc.value().as_duration(self.0.time_unit());
509        Ok(Scalar::new(self.dtype().clone(), v))
510    }
511    fn std_reduce(&self, ddof: u8) -> PolarsResult<Scalar> {
512        let sc = self.0.physical().std_reduce(ddof);
513        let to = self.dtype().to_physical();
514        let v = sc.value().cast(&to);
515        Ok(Scalar::new(
516            self.dtype().clone(),
517            v.as_duration(self.0.time_unit()),
518        ))
519    }
520
521    fn median_reduce(&self) -> PolarsResult<Scalar> {
522        let v: AnyValue = self.median().map(|v| v as i64).into();
523        let to = self.dtype().to_physical();
524        let v = v.cast(&to);
525        Ok(Scalar::new(
526            self.dtype().clone(),
527            v.as_duration(self.0.time_unit()),
528        ))
529    }
530    fn quantile_reduce(&self, quantile: f64, method: QuantileMethod) -> PolarsResult<Scalar> {
531        let v = self.0.physical().quantile_reduce(quantile, method)?;
532        let to = self.dtype().to_physical();
533        let v = v.value().cast(&to);
534        Ok(Scalar::new(
535            self.dtype().clone(),
536            v.as_duration(self.0.time_unit()),
537        ))
538    }
539
540    fn clone_inner(&self) -> Arc<dyn SeriesTrait> {
541        Arc::new(SeriesWrap(Clone::clone(&self.0)))
542    }
543
544    fn find_validity_mismatch(&self, other: &Series, idxs: &mut Vec<IdxSize>) {
545        self.0.physical().find_validity_mismatch(other, idxs)
546    }
547
548    fn as_any(&self) -> &dyn Any {
549        &self.0
550    }
551
552    fn as_any_mut(&mut self) -> &mut dyn Any {
553        &mut self.0
554    }
555
556    fn as_phys_any(&self) -> &dyn Any {
557        self.0.physical()
558    }
559
560    fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
561        self as _
562    }
563}