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