Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-core/src/series/implementations/date.rs
8421 views
1
//! This module exists to reduce compilation times.
2
//!
3
//! All the data types are backed by a physical type in memory e.g. Date -> i32, Datetime-> i64.
4
//!
5
//! Series lead to code implementations of all traits. Whereas there are a lot of duplicates due to
6
//! data types being backed by the same physical type. In this module we reduce compile times by
7
//! opting for a little more run time cost. We cast to the physical type -> apply the operation and
8
//! (depending on the result) cast back to the original type
9
//!
10
use super::*;
11
#[cfg(feature = "algorithm_group_by")]
12
use crate::frame::group_by::*;
13
use crate::prelude::*;
14
15
unsafe impl IntoSeries for DateChunked {
16
fn into_series(self) -> Series {
17
Series(Arc::new(SeriesWrap(self)))
18
}
19
}
20
21
impl private::PrivateSeries for SeriesWrap<DateChunked> {
22
fn compute_len(&mut self) {
23
self.0.physical_mut().compute_len()
24
}
25
26
fn _field(&self) -> Cow<'_, Field> {
27
Cow::Owned(self.0.field())
28
}
29
30
fn _dtype(&self) -> &DataType {
31
self.0.dtype()
32
}
33
34
fn _get_flags(&self) -> StatisticsFlags {
35
self.0.physical().get_flags()
36
}
37
38
fn _set_flags(&mut self, flags: StatisticsFlags) {
39
self.0.physical_mut().set_flags(flags)
40
}
41
42
#[cfg(feature = "zip_with")]
43
fn zip_with_same_type(&self, mask: &BooleanChunked, other: &Series) -> PolarsResult<Series> {
44
let other = other.to_physical_repr().into_owned();
45
self.0
46
.physical()
47
.zip_with(mask, other.as_ref().as_ref())
48
.map(|ca| ca.into_date().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
55
fn into_total_ord_inner<'a>(&'a self) -> Box<dyn TotalOrdInner + 'a> {
56
self.0.physical().into_total_ord_inner()
57
}
58
59
fn vec_hash(
60
&self,
61
random_state: PlSeedableRandomStateQuality,
62
buf: &mut Vec<u64>,
63
) -> PolarsResult<()> {
64
self.0.physical().vec_hash(random_state, buf)?;
65
Ok(())
66
}
67
68
fn vec_hash_combine(
69
&self,
70
build_hasher: PlSeedableRandomStateQuality,
71
hashes: &mut [u64],
72
) -> PolarsResult<()> {
73
self.0.physical().vec_hash_combine(build_hasher, hashes)?;
74
Ok(())
75
}
76
77
#[cfg(feature = "algorithm_group_by")]
78
unsafe fn agg_min(&self, groups: &GroupsType) -> Series {
79
self.0.physical().agg_min(groups).into_date().into_series()
80
}
81
82
#[cfg(feature = "algorithm_group_by")]
83
unsafe fn agg_max(&self, groups: &GroupsType) -> Series {
84
self.0.physical().agg_max(groups).into_date().into_series()
85
}
86
87
#[cfg(feature = "algorithm_group_by")]
88
unsafe fn agg_arg_min(&self, groups: &GroupsType) -> Series {
89
self.0.physical().agg_arg_min(groups)
90
}
91
92
#[cfg(feature = "algorithm_group_by")]
93
unsafe fn agg_arg_max(&self, groups: &GroupsType) -> Series {
94
self.0.physical().agg_arg_max(groups)
95
}
96
97
#[cfg(feature = "algorithm_group_by")]
98
unsafe fn agg_list(&self, groups: &GroupsType) -> Series {
99
// we cannot cast and dispatch as the inner type of the list would be incorrect
100
self.0
101
.physical()
102
.agg_list(groups)
103
.cast(&DataType::List(Box::new(self.dtype().clone())))
104
.unwrap()
105
}
106
107
fn subtract(&self, rhs: &Series) -> PolarsResult<Series> {
108
match rhs.dtype() {
109
DataType::Date => {
110
let dt = DataType::Datetime(TimeUnit::Microseconds, None);
111
let lhs = self.cast(&dt, CastOptions::NonStrict)?;
112
let rhs = rhs.cast(&dt)?;
113
lhs.subtract(&rhs)
114
},
115
DataType::Duration(_) => std::ops::Sub::sub(
116
&self.cast(
117
&DataType::Datetime(TimeUnit::Microseconds, None),
118
CastOptions::NonStrict,
119
)?,
120
rhs,
121
)?
122
.cast(&DataType::Date),
123
dtr => polars_bail!(opq = sub, DataType::Date, dtr),
124
}
125
}
126
127
fn add_to(&self, rhs: &Series) -> PolarsResult<Series> {
128
match rhs.dtype() {
129
DataType::Duration(_) => std::ops::Add::add(
130
&self.cast(
131
&DataType::Datetime(TimeUnit::Microseconds, None),
132
CastOptions::NonStrict,
133
)?,
134
rhs,
135
)?
136
.cast(&DataType::Date),
137
dtr => polars_bail!(opq = add, DataType::Date, dtr),
138
}
139
}
140
141
fn multiply(&self, rhs: &Series) -> PolarsResult<Series> {
142
polars_bail!(opq = mul, self.0.dtype(), rhs.dtype());
143
}
144
145
fn divide(&self, rhs: &Series) -> PolarsResult<Series> {
146
polars_bail!(opq = div, self.0.dtype(), rhs.dtype());
147
}
148
149
fn remainder(&self, rhs: &Series) -> PolarsResult<Series> {
150
polars_bail!(opq = rem, self.0.dtype(), rhs.dtype());
151
}
152
#[cfg(feature = "algorithm_group_by")]
153
fn group_tuples(&self, multithreaded: bool, sorted: bool) -> PolarsResult<GroupsType> {
154
self.0.physical().group_tuples(multithreaded, sorted)
155
}
156
157
fn arg_sort_multiple(
158
&self,
159
by: &[Column],
160
options: &SortMultipleOptions,
161
) -> PolarsResult<IdxCa> {
162
self.0.physical().arg_sort_multiple(by, options)
163
}
164
}
165
166
impl SeriesTrait for SeriesWrap<DateChunked> {
167
fn rename(&mut self, name: PlSmallStr) {
168
self.0.rename(name);
169
}
170
171
fn chunk_lengths(&self) -> ChunkLenIter<'_> {
172
self.0.physical().chunk_lengths()
173
}
174
175
fn name(&self) -> &PlSmallStr {
176
self.0.name()
177
}
178
179
fn chunks(&self) -> &Vec<ArrayRef> {
180
self.0.physical().chunks()
181
}
182
183
unsafe fn chunks_mut(&mut self) -> &mut Vec<ArrayRef> {
184
self.0.physical_mut().chunks_mut()
185
}
186
187
fn shrink_to_fit(&mut self) {
188
self.0.physical_mut().shrink_to_fit()
189
}
190
191
fn slice(&self, offset: i64, length: usize) -> Series {
192
self.0.slice(offset, length).into_series()
193
}
194
195
fn split_at(&self, offset: i64) -> (Series, Series) {
196
let (a, b) = self.0.split_at(offset);
197
(a.into_series(), b.into_series())
198
}
199
200
fn _sum_as_f64(&self) -> f64 {
201
self.0.physical()._sum_as_f64()
202
}
203
204
fn mean(&self) -> Option<f64> {
205
self.0.physical().mean()
206
}
207
208
fn median(&self) -> Option<f64> {
209
self.0.physical().median()
210
}
211
212
fn append(&mut self, other: &Series) -> PolarsResult<()> {
213
polars_ensure!(self.0.dtype() == other.dtype(), append);
214
let mut other = other.to_physical_repr().into_owned();
215
self.0
216
.physical_mut()
217
.append_owned(std::mem::take(other._get_inner_mut().as_mut()))
218
}
219
220
fn append_owned(&mut self, mut other: Series) -> PolarsResult<()> {
221
polars_ensure!(self.0.dtype() == other.dtype(), append);
222
self.0.physical_mut().append_owned(std::mem::take(
223
&mut other
224
._get_inner_mut()
225
.as_any_mut()
226
.downcast_mut::<DateChunked>()
227
.unwrap()
228
.phys,
229
))
230
}
231
232
fn extend(&mut self, other: &Series) -> PolarsResult<()> {
233
polars_ensure!(self.0.dtype() == other.dtype(), extend);
234
// 3 refs
235
// ref Cow
236
// ref SeriesTrait
237
// ref ChunkedArray
238
let other = other.to_physical_repr();
239
self.0
240
.physical_mut()
241
.extend(other.as_ref().as_ref().as_ref())?;
242
Ok(())
243
}
244
245
fn filter(&self, filter: &BooleanChunked) -> PolarsResult<Series> {
246
self.0
247
.physical()
248
.filter(filter)
249
.map(|ca| ca.into_date().into_series())
250
}
251
252
fn take(&self, indices: &IdxCa) -> PolarsResult<Series> {
253
Ok(self.0.physical().take(indices)?.into_date().into_series())
254
}
255
256
unsafe fn take_unchecked(&self, indices: &IdxCa) -> Series {
257
self.0
258
.physical()
259
.take_unchecked(indices)
260
.into_date()
261
.into_series()
262
}
263
264
fn take_slice(&self, indices: &[IdxSize]) -> PolarsResult<Series> {
265
Ok(self.0.physical().take(indices)?.into_date().into_series())
266
}
267
268
unsafe fn take_slice_unchecked(&self, indices: &[IdxSize]) -> Series {
269
self.0
270
.physical()
271
.take_unchecked(indices)
272
.into_date()
273
.into_series()
274
}
275
276
fn deposit(&self, validity: &Bitmap) -> Series {
277
self.0
278
.physical()
279
.deposit(validity)
280
.into_date()
281
.into_series()
282
}
283
284
fn len(&self) -> usize {
285
self.0.len()
286
}
287
288
fn rechunk(&self) -> Series {
289
self.0
290
.physical()
291
.rechunk()
292
.into_owned()
293
.into_date()
294
.into_series()
295
}
296
297
fn new_from_index(&self, index: usize, length: usize) -> Series {
298
self.0
299
.physical()
300
.new_from_index(index, length)
301
.into_date()
302
.into_series()
303
}
304
305
fn cast(&self, dtype: &DataType, cast_options: CastOptions) -> PolarsResult<Series> {
306
match dtype {
307
DataType::String => Ok(self
308
.0
309
.clone()
310
.into_series()
311
.date()
312
.unwrap()
313
.to_string("%Y-%m-%d")?
314
.into_series()),
315
#[cfg(feature = "dtype-datetime")]
316
DataType::Datetime(_, _) => {
317
let mut out = self.0.cast_with_options(dtype, CastOptions::NonStrict)?;
318
out.set_sorted_flag(self.0.physical().is_sorted_flag());
319
Ok(out)
320
},
321
_ => self.0.cast_with_options(dtype, cast_options),
322
}
323
}
324
325
#[inline]
326
unsafe fn get_unchecked(&self, index: usize) -> AnyValue<'_> {
327
self.0.get_any_value_unchecked(index)
328
}
329
330
fn sort_with(&self, options: SortOptions) -> PolarsResult<Series> {
331
Ok(self
332
.0
333
.physical()
334
.sort_with(options)
335
.into_date()
336
.into_series())
337
}
338
339
fn arg_sort(&self, options: SortOptions) -> IdxCa {
340
self.0.physical().arg_sort(options)
341
}
342
343
fn null_count(&self) -> usize {
344
self.0.null_count()
345
}
346
347
fn has_nulls(&self) -> bool {
348
self.0.has_nulls()
349
}
350
351
#[cfg(feature = "algorithm_group_by")]
352
fn unique(&self) -> PolarsResult<Series> {
353
self.0
354
.physical()
355
.unique()
356
.map(|ca| ca.into_date().into_series())
357
}
358
359
#[cfg(feature = "algorithm_group_by")]
360
fn n_unique(&self) -> PolarsResult<usize> {
361
self.0.physical().n_unique()
362
}
363
364
#[cfg(feature = "algorithm_group_by")]
365
fn arg_unique(&self) -> PolarsResult<IdxCa> {
366
self.0.physical().arg_unique()
367
}
368
369
fn unique_id(&self) -> PolarsResult<(IdxSize, Vec<IdxSize>)> {
370
ChunkUnique::unique_id(self.0.physical())
371
}
372
373
fn is_null(&self) -> BooleanChunked {
374
self.0.is_null()
375
}
376
377
fn is_not_null(&self) -> BooleanChunked {
378
self.0.is_not_null()
379
}
380
381
fn reverse(&self) -> Series {
382
self.0.physical().reverse().into_date().into_series()
383
}
384
385
fn as_single_ptr(&mut self) -> PolarsResult<usize> {
386
self.0.physical_mut().as_single_ptr()
387
}
388
389
fn shift(&self, periods: i64) -> Series {
390
self.0.physical().shift(periods).into_date().into_series()
391
}
392
393
fn max_reduce(&self) -> PolarsResult<Scalar> {
394
let sc = self.0.physical().max_reduce();
395
let av = sc.value().as_date();
396
Ok(Scalar::new(self.dtype().clone(), av))
397
}
398
399
fn min_reduce(&self) -> PolarsResult<Scalar> {
400
let sc = self.0.physical().min_reduce();
401
let av = sc.value().as_date();
402
Ok(Scalar::new(self.dtype().clone(), av))
403
}
404
405
#[cfg(feature = "dtype-datetime")]
406
fn mean_reduce(&self) -> PolarsResult<Scalar> {
407
let mean = self.mean().map(|v| (v * US_IN_DAY as f64) as i64);
408
let dtype = DataType::Datetime(TimeUnit::Microseconds, None);
409
let av = AnyValue::from(mean).as_datetime(TimeUnit::Microseconds, None);
410
Ok(Scalar::new(dtype, av))
411
}
412
413
#[cfg(feature = "dtype-datetime")]
414
fn median_reduce(&self) -> PolarsResult<Scalar> {
415
let median = self.median().map(|v| (v * (US_IN_DAY as f64)) as i64);
416
let dtype = DataType::Datetime(TimeUnit::Microseconds, None);
417
let av = AnyValue::from(median).as_datetime(TimeUnit::Microseconds, None);
418
Ok(Scalar::new(dtype, av))
419
}
420
421
#[cfg(feature = "dtype-datetime")]
422
fn quantile_reduce(&self, quantile: f64, method: QuantileMethod) -> PolarsResult<Scalar> {
423
let quantile = self.0.physical().quantile_reduce(quantile, method)?;
424
let v = quantile.value().extract::<f64>().unwrap();
425
let datetime_us_value = (v * (US_IN_DAY as f64)) as i64;
426
let av = AnyValue::Datetime(datetime_us_value, TimeUnit::Microseconds, None);
427
Ok(Scalar::new(
428
DataType::Datetime(TimeUnit::Microseconds, None),
429
av,
430
))
431
}
432
433
#[cfg(feature = "dtype-datetime")]
434
fn quantiles_reduce(&self, quantiles: &[f64], method: QuantileMethod) -> PolarsResult<Scalar> {
435
let result = self.0.physical().quantiles_reduce(quantiles, method)?;
436
if let AnyValue::List(float_s) = result.value() {
437
let float_ca = float_s.f64().unwrap();
438
let int_s = float_ca
439
.iter()
440
.map(|v: Option<f64>| v.map(|f| (f * (US_IN_DAY as f64)) as i64))
441
.collect::<Int64Chunked>()
442
.into_datetime(TimeUnit::Microseconds, None)
443
.into_series();
444
Ok(Scalar::new(
445
DataType::List(Box::new(DataType::Datetime(TimeUnit::Microseconds, None))),
446
AnyValue::List(int_s),
447
))
448
} else {
449
polars_bail!(ComputeError: "expected list scalar from quantiles_reduce")
450
}
451
}
452
453
#[cfg(feature = "approx_unique")]
454
fn approx_n_unique(&self) -> PolarsResult<IdxSize> {
455
Ok(ChunkApproxNUnique::approx_n_unique(self.0.physical()))
456
}
457
458
fn clone_inner(&self) -> Arc<dyn SeriesTrait> {
459
Arc::new(SeriesWrap(Clone::clone(&self.0)))
460
}
461
462
fn find_validity_mismatch(&self, other: &Series, idxs: &mut Vec<IdxSize>) {
463
self.0.physical().find_validity_mismatch(other, idxs)
464
}
465
466
fn as_any(&self) -> &dyn Any {
467
&self.0
468
}
469
470
fn as_any_mut(&mut self) -> &mut dyn Any {
471
&mut self.0
472
}
473
474
fn as_phys_any(&self) -> &dyn Any {
475
self.0.physical()
476
}
477
478
fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
479
self as _
480
}
481
}
482
483
impl private::PrivateSeriesNumeric for SeriesWrap<DateChunked> {
484
fn bit_repr(&self) -> Option<BitRepr> {
485
Some(self.0.physical().to_bit_repr())
486
}
487
}
488
489