polars_core/series/implementations/
duration.rs1use 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(&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(&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 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 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}