polars_core/series/implementations/
date.rs

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//!
10use super::*;
11#[cfg(feature = "algorithm_group_by")]
12use crate::frame::group_by::*;
13use crate::prelude::*;
14
15unsafe impl IntoSeries for DateChunked {
16    fn into_series(self) -> Series {
17        Series(Arc::new(SeriesWrap(self)))
18    }
19}
20
21impl 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_list(&self, groups: &GroupsType) -> Series {
89        // we cannot cast and dispatch as the inner type of the list would be incorrect
90        self.0
91            .physical()
92            .agg_list(groups)
93            .cast(&DataType::List(Box::new(self.dtype().clone())))
94            .unwrap()
95    }
96
97    fn subtract(&self, rhs: &Series) -> PolarsResult<Series> {
98        match rhs.dtype() {
99            DataType::Date => {
100                let dt = DataType::Datetime(TimeUnit::Milliseconds, None);
101                let lhs = self.cast(&dt, CastOptions::NonStrict)?;
102                let rhs = rhs.cast(&dt)?;
103                lhs.subtract(&rhs)
104            },
105            DataType::Duration(_) => std::ops::Sub::sub(
106                &self.cast(
107                    &DataType::Datetime(TimeUnit::Milliseconds, None),
108                    CastOptions::NonStrict,
109                )?,
110                rhs,
111            )?
112            .cast(&DataType::Date),
113            dtr => polars_bail!(opq = sub, DataType::Date, dtr),
114        }
115    }
116
117    fn add_to(&self, rhs: &Series) -> PolarsResult<Series> {
118        match rhs.dtype() {
119            DataType::Duration(_) => std::ops::Add::add(
120                &self.cast(
121                    &DataType::Datetime(TimeUnit::Milliseconds, None),
122                    CastOptions::NonStrict,
123                )?,
124                rhs,
125            )?
126            .cast(&DataType::Date),
127            dtr => polars_bail!(opq = add, DataType::Date, dtr),
128        }
129    }
130
131    fn multiply(&self, rhs: &Series) -> PolarsResult<Series> {
132        polars_bail!(opq = mul, self.0.dtype(), rhs.dtype());
133    }
134
135    fn divide(&self, rhs: &Series) -> PolarsResult<Series> {
136        polars_bail!(opq = div, self.0.dtype(), rhs.dtype());
137    }
138
139    fn remainder(&self, rhs: &Series) -> PolarsResult<Series> {
140        polars_bail!(opq = rem, self.0.dtype(), rhs.dtype());
141    }
142    #[cfg(feature = "algorithm_group_by")]
143    fn group_tuples(&self, multithreaded: bool, sorted: bool) -> PolarsResult<GroupsType> {
144        self.0.physical().group_tuples(multithreaded, sorted)
145    }
146
147    fn arg_sort_multiple(
148        &self,
149        by: &[Column],
150        options: &SortMultipleOptions,
151    ) -> PolarsResult<IdxCa> {
152        self.0.physical().arg_sort_multiple(by, options)
153    }
154}
155
156impl SeriesTrait for SeriesWrap<DateChunked> {
157    fn rename(&mut self, name: PlSmallStr) {
158        self.0.rename(name);
159    }
160
161    fn chunk_lengths(&self) -> ChunkLenIter<'_> {
162        self.0.physical().chunk_lengths()
163    }
164
165    fn name(&self) -> &PlSmallStr {
166        self.0.name()
167    }
168
169    fn chunks(&self) -> &Vec<ArrayRef> {
170        self.0.physical().chunks()
171    }
172
173    unsafe fn chunks_mut(&mut self) -> &mut Vec<ArrayRef> {
174        self.0.physical_mut().chunks_mut()
175    }
176
177    fn shrink_to_fit(&mut self) {
178        self.0.physical_mut().shrink_to_fit()
179    }
180
181    fn slice(&self, offset: i64, length: usize) -> Series {
182        self.0.slice(offset, length).into_series()
183    }
184
185    fn split_at(&self, offset: i64) -> (Series, Series) {
186        let (a, b) = self.0.split_at(offset);
187        (a.into_series(), b.into_series())
188    }
189
190    fn _sum_as_f64(&self) -> f64 {
191        self.0.physical()._sum_as_f64()
192    }
193
194    fn mean(&self) -> Option<f64> {
195        self.0.physical().mean()
196    }
197
198    fn median(&self) -> Option<f64> {
199        self.0.physical().median()
200    }
201
202    fn append(&mut self, other: &Series) -> PolarsResult<()> {
203        polars_ensure!(self.0.dtype() == other.dtype(), append);
204        let mut other = other.to_physical_repr().into_owned();
205        self.0
206            .physical_mut()
207            .append_owned(std::mem::take(other._get_inner_mut().as_mut()))
208    }
209
210    fn append_owned(&mut self, mut other: Series) -> PolarsResult<()> {
211        polars_ensure!(self.0.dtype() == other.dtype(), append);
212        self.0.physical_mut().append_owned(std::mem::take(
213            &mut other
214                ._get_inner_mut()
215                .as_any_mut()
216                .downcast_mut::<DateChunked>()
217                .unwrap()
218                .phys,
219        ))
220    }
221
222    fn extend(&mut self, other: &Series) -> PolarsResult<()> {
223        polars_ensure!(self.0.dtype() == other.dtype(), extend);
224        // 3 refs
225        // ref Cow
226        // ref SeriesTrait
227        // ref ChunkedArray
228        let other = other.to_physical_repr();
229        self.0
230            .physical_mut()
231            .extend(other.as_ref().as_ref().as_ref())?;
232        Ok(())
233    }
234
235    fn filter(&self, filter: &BooleanChunked) -> PolarsResult<Series> {
236        self.0
237            .physical()
238            .filter(filter)
239            .map(|ca| ca.into_date().into_series())
240    }
241
242    fn take(&self, indices: &IdxCa) -> PolarsResult<Series> {
243        Ok(self.0.physical().take(indices)?.into_date().into_series())
244    }
245
246    unsafe fn take_unchecked(&self, indices: &IdxCa) -> Series {
247        self.0
248            .physical()
249            .take_unchecked(indices)
250            .into_date()
251            .into_series()
252    }
253
254    fn take_slice(&self, indices: &[IdxSize]) -> PolarsResult<Series> {
255        Ok(self.0.physical().take(indices)?.into_date().into_series())
256    }
257
258    unsafe fn take_slice_unchecked(&self, indices: &[IdxSize]) -> Series {
259        self.0
260            .physical()
261            .take_unchecked(indices)
262            .into_date()
263            .into_series()
264    }
265
266    fn len(&self) -> usize {
267        self.0.len()
268    }
269
270    fn rechunk(&self) -> Series {
271        self.0
272            .physical()
273            .rechunk()
274            .into_owned()
275            .into_date()
276            .into_series()
277    }
278
279    fn new_from_index(&self, index: usize, length: usize) -> Series {
280        self.0
281            .physical()
282            .new_from_index(index, length)
283            .into_date()
284            .into_series()
285    }
286
287    fn cast(&self, dtype: &DataType, cast_options: CastOptions) -> PolarsResult<Series> {
288        match dtype {
289            DataType::String => Ok(self
290                .0
291                .clone()
292                .into_series()
293                .date()
294                .unwrap()
295                .to_string("%Y-%m-%d")?
296                .into_series()),
297            #[cfg(feature = "dtype-datetime")]
298            DataType::Datetime(_, _) => {
299                let mut out = self.0.cast_with_options(dtype, CastOptions::NonStrict)?;
300                out.set_sorted_flag(self.0.physical().is_sorted_flag());
301                Ok(out)
302            },
303            _ => self.0.cast_with_options(dtype, cast_options),
304        }
305    }
306
307    #[inline]
308    unsafe fn get_unchecked(&self, index: usize) -> AnyValue<'_> {
309        self.0.get_any_value_unchecked(index)
310    }
311
312    fn sort_with(&self, options: SortOptions) -> PolarsResult<Series> {
313        Ok(self
314            .0
315            .physical()
316            .sort_with(options)
317            .into_date()
318            .into_series())
319    }
320
321    fn arg_sort(&self, options: SortOptions) -> IdxCa {
322        self.0.physical().arg_sort(options)
323    }
324
325    fn null_count(&self) -> usize {
326        self.0.null_count()
327    }
328
329    fn has_nulls(&self) -> bool {
330        self.0.has_nulls()
331    }
332
333    #[cfg(feature = "algorithm_group_by")]
334    fn unique(&self) -> PolarsResult<Series> {
335        self.0
336            .physical()
337            .unique()
338            .map(|ca| ca.into_date().into_series())
339    }
340
341    #[cfg(feature = "algorithm_group_by")]
342    fn n_unique(&self) -> PolarsResult<usize> {
343        self.0.physical().n_unique()
344    }
345
346    #[cfg(feature = "algorithm_group_by")]
347    fn arg_unique(&self) -> PolarsResult<IdxCa> {
348        self.0.physical().arg_unique()
349    }
350
351    fn is_null(&self) -> BooleanChunked {
352        self.0.is_null()
353    }
354
355    fn is_not_null(&self) -> BooleanChunked {
356        self.0.is_not_null()
357    }
358
359    fn reverse(&self) -> Series {
360        self.0.physical().reverse().into_date().into_series()
361    }
362
363    fn as_single_ptr(&mut self) -> PolarsResult<usize> {
364        self.0.physical_mut().as_single_ptr()
365    }
366
367    fn shift(&self, periods: i64) -> Series {
368        self.0.physical().shift(periods).into_date().into_series()
369    }
370
371    fn max_reduce(&self) -> PolarsResult<Scalar> {
372        let sc = self.0.physical().max_reduce();
373        let av = sc.value().cast(self.dtype()).into_static();
374        Ok(Scalar::new(self.dtype().clone(), av))
375    }
376
377    fn min_reduce(&self) -> PolarsResult<Scalar> {
378        let sc = self.0.physical().min_reduce();
379        let av = sc.value().cast(self.dtype()).into_static();
380        Ok(Scalar::new(self.dtype().clone(), av))
381    }
382
383    fn median_reduce(&self) -> PolarsResult<Scalar> {
384        let av: AnyValue = self
385            .median()
386            .map(|v| (v * (MS_IN_DAY as f64)) as i64)
387            .into();
388        Ok(Scalar::new(
389            DataType::Datetime(TimeUnit::Milliseconds, None),
390            av,
391        ))
392    }
393
394    fn clone_inner(&self) -> Arc<dyn SeriesTrait> {
395        Arc::new(SeriesWrap(Clone::clone(&self.0)))
396    }
397
398    fn find_validity_mismatch(&self, other: &Series, idxs: &mut Vec<IdxSize>) {
399        self.0.physical().find_validity_mismatch(other, idxs)
400    }
401
402    fn as_any(&self) -> &dyn Any {
403        &self.0
404    }
405
406    fn as_any_mut(&mut self) -> &mut dyn Any {
407        &mut self.0
408    }
409
410    fn as_phys_any(&self) -> &dyn Any {
411        self.0.physical()
412    }
413
414    fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
415        self as _
416    }
417}
418
419impl private::PrivateSeriesNumeric for SeriesWrap<DateChunked> {
420    fn bit_repr(&self) -> Option<BitRepr> {
421        Some(self.0.physical().to_bit_repr())
422    }
423}