polars_core/series/implementations/
duration.rs

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