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.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.get_flags()
36    }
37
38    fn _set_flags(&mut self, flags: StatisticsFlags) {
39        self.0.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            .zip_with(mask, other.as_ref().as_ref())
47            .map(|ca| ca.into_date().into_series())
48    }
49
50    fn into_total_eq_inner<'a>(&'a self) -> Box<dyn TotalEqInner + 'a> {
51        self.0.physical().into_total_eq_inner()
52    }
53    fn into_total_ord_inner<'a>(&'a self) -> Box<dyn TotalOrdInner + 'a> {
54        self.0.physical().into_total_ord_inner()
55    }
56
57    fn vec_hash(&self, random_state: PlRandomState, buf: &mut Vec<u64>) -> PolarsResult<()> {
58        self.0.vec_hash(random_state, buf)?;
59        Ok(())
60    }
61
62    fn vec_hash_combine(
63        &self,
64        build_hasher: PlRandomState,
65        hashes: &mut [u64],
66    ) -> PolarsResult<()> {
67        self.0.vec_hash_combine(build_hasher, hashes)?;
68        Ok(())
69    }
70
71    #[cfg(feature = "algorithm_group_by")]
72    unsafe fn agg_min(&self, groups: &GroupsType) -> Series {
73        self.0.agg_min(groups).into_date().into_series()
74    }
75
76    #[cfg(feature = "algorithm_group_by")]
77    unsafe fn agg_max(&self, groups: &GroupsType) -> Series {
78        self.0.agg_max(groups).into_date().into_series()
79    }
80
81    #[cfg(feature = "algorithm_group_by")]
82    unsafe fn agg_list(&self, groups: &GroupsType) -> Series {
83        // we cannot cast and dispatch as the inner type of the list would be incorrect
84        self.0
85            .agg_list(groups)
86            .cast(&DataType::List(Box::new(self.dtype().clone())))
87            .unwrap()
88    }
89
90    fn subtract(&self, rhs: &Series) -> PolarsResult<Series> {
91        match rhs.dtype() {
92            DataType::Date => {
93                let dt = DataType::Datetime(TimeUnit::Milliseconds, None);
94                let lhs = self.cast(&dt, CastOptions::NonStrict)?;
95                let rhs = rhs.cast(&dt)?;
96                lhs.subtract(&rhs)
97            },
98            DataType::Duration(_) => std::ops::Sub::sub(
99                &self.cast(
100                    &DataType::Datetime(TimeUnit::Milliseconds, None),
101                    CastOptions::NonStrict,
102                )?,
103                rhs,
104            )?
105            .cast(&DataType::Date),
106            dtr => polars_bail!(opq = sub, DataType::Date, dtr),
107        }
108    }
109
110    fn add_to(&self, rhs: &Series) -> PolarsResult<Series> {
111        match rhs.dtype() {
112            DataType::Duration(_) => std::ops::Add::add(
113                &self.cast(
114                    &DataType::Datetime(TimeUnit::Milliseconds, None),
115                    CastOptions::NonStrict,
116                )?,
117                rhs,
118            )?
119            .cast(&DataType::Date),
120            dtr => polars_bail!(opq = add, DataType::Date, dtr),
121        }
122    }
123
124    fn multiply(&self, rhs: &Series) -> PolarsResult<Series> {
125        polars_bail!(opq = mul, self.0.dtype(), rhs.dtype());
126    }
127
128    fn divide(&self, rhs: &Series) -> PolarsResult<Series> {
129        polars_bail!(opq = div, self.0.dtype(), rhs.dtype());
130    }
131
132    fn remainder(&self, rhs: &Series) -> PolarsResult<Series> {
133        polars_bail!(opq = rem, self.0.dtype(), rhs.dtype());
134    }
135    #[cfg(feature = "algorithm_group_by")]
136    fn group_tuples(&self, multithreaded: bool, sorted: bool) -> PolarsResult<GroupsType> {
137        self.0.group_tuples(multithreaded, sorted)
138    }
139
140    fn arg_sort_multiple(
141        &self,
142        by: &[Column],
143        options: &SortMultipleOptions,
144    ) -> PolarsResult<IdxCa> {
145        self.0.deref().arg_sort_multiple(by, options)
146    }
147}
148
149impl SeriesTrait for SeriesWrap<DateChunked> {
150    fn rename(&mut self, name: PlSmallStr) {
151        self.0.rename(name);
152    }
153
154    fn chunk_lengths(&self) -> ChunkLenIter {
155        self.0.chunk_lengths()
156    }
157    fn name(&self) -> &PlSmallStr {
158        self.0.name()
159    }
160
161    fn chunks(&self) -> &Vec<ArrayRef> {
162        self.0.chunks()
163    }
164    unsafe fn chunks_mut(&mut self) -> &mut Vec<ArrayRef> {
165        self.0.chunks_mut()
166    }
167
168    fn shrink_to_fit(&mut self) {
169        self.0.shrink_to_fit()
170    }
171
172    fn slice(&self, offset: i64, length: usize) -> Series {
173        self.0.slice(offset, length).into_date().into_series()
174    }
175    fn split_at(&self, offset: i64) -> (Series, Series) {
176        let (a, b) = self.0.split_at(offset);
177        (a.into_date().into_series(), b.into_date().into_series())
178    }
179
180    fn _sum_as_f64(&self) -> f64 {
181        self.0._sum_as_f64()
182    }
183
184    fn mean(&self) -> Option<f64> {
185        self.0.mean()
186    }
187
188    fn median(&self) -> Option<f64> {
189        self.0.median()
190    }
191
192    fn append(&mut self, other: &Series) -> PolarsResult<()> {
193        polars_ensure!(self.0.dtype() == other.dtype(), append);
194        let mut other = other.to_physical_repr().into_owned();
195        self.0
196            .append_owned(std::mem::take(other._get_inner_mut().as_mut()))
197    }
198    fn append_owned(&mut self, mut other: Series) -> PolarsResult<()> {
199        polars_ensure!(self.0.dtype() == other.dtype(), append);
200        self.0.append_owned(std::mem::take(
201            &mut other
202                ._get_inner_mut()
203                .as_any_mut()
204                .downcast_mut::<DateChunked>()
205                .unwrap()
206                .0,
207        ))
208    }
209    fn extend(&mut self, other: &Series) -> PolarsResult<()> {
210        polars_ensure!(self.0.dtype() == other.dtype(), extend);
211        // 3 refs
212        // ref Cow
213        // ref SeriesTrait
214        // ref ChunkedArray
215        let other = other.to_physical_repr();
216        self.0.extend(other.as_ref().as_ref().as_ref())?;
217        Ok(())
218    }
219
220    fn filter(&self, filter: &BooleanChunked) -> PolarsResult<Series> {
221        self.0.filter(filter).map(|ca| ca.into_date().into_series())
222    }
223
224    fn take(&self, indices: &IdxCa) -> PolarsResult<Series> {
225        Ok(self.0.take(indices)?.into_date().into_series())
226    }
227
228    unsafe fn take_unchecked(&self, indices: &IdxCa) -> Series {
229        self.0.take_unchecked(indices).into_date().into_series()
230    }
231
232    fn take_slice(&self, indices: &[IdxSize]) -> PolarsResult<Series> {
233        Ok(self.0.take(indices)?.into_date().into_series())
234    }
235
236    unsafe fn take_slice_unchecked(&self, indices: &[IdxSize]) -> Series {
237        self.0.take_unchecked(indices).into_date().into_series()
238    }
239
240    fn len(&self) -> usize {
241        self.0.len()
242    }
243
244    fn rechunk(&self) -> Series {
245        self.0.rechunk().into_date().into_series()
246    }
247
248    fn new_from_index(&self, index: usize, length: usize) -> Series {
249        self.0
250            .new_from_index(index, length)
251            .into_date()
252            .into_series()
253    }
254
255    fn cast(&self, dtype: &DataType, cast_options: CastOptions) -> PolarsResult<Series> {
256        match dtype {
257            DataType::String => Ok(self
258                .0
259                .clone()
260                .into_series()
261                .date()
262                .unwrap()
263                .to_string("%Y-%m-%d")?
264                .into_series()),
265            #[cfg(feature = "dtype-datetime")]
266            DataType::Datetime(_, _) => {
267                let mut out = self.0.cast_with_options(dtype, CastOptions::NonStrict)?;
268                out.set_sorted_flag(self.0.is_sorted_flag());
269                Ok(out)
270            },
271            _ => self.0.cast_with_options(dtype, cast_options),
272        }
273    }
274
275    #[inline]
276    unsafe fn get_unchecked(&self, index: usize) -> AnyValue {
277        self.0.get_any_value_unchecked(index)
278    }
279
280    fn sort_with(&self, options: SortOptions) -> PolarsResult<Series> {
281        Ok(self.0.sort_with(options).into_date().into_series())
282    }
283
284    fn arg_sort(&self, options: SortOptions) -> IdxCa {
285        self.0.arg_sort(options)
286    }
287
288    fn null_count(&self) -> usize {
289        self.0.null_count()
290    }
291
292    fn has_nulls(&self) -> bool {
293        self.0.has_nulls()
294    }
295
296    #[cfg(feature = "algorithm_group_by")]
297    fn unique(&self) -> PolarsResult<Series> {
298        self.0.unique().map(|ca| ca.into_date().into_series())
299    }
300
301    #[cfg(feature = "algorithm_group_by")]
302    fn n_unique(&self) -> PolarsResult<usize> {
303        self.0.n_unique()
304    }
305
306    #[cfg(feature = "algorithm_group_by")]
307    fn arg_unique(&self) -> PolarsResult<IdxCa> {
308        self.0.arg_unique()
309    }
310
311    fn is_null(&self) -> BooleanChunked {
312        self.0.is_null()
313    }
314
315    fn is_not_null(&self) -> BooleanChunked {
316        self.0.is_not_null()
317    }
318
319    fn reverse(&self) -> Series {
320        self.0.reverse().into_date().into_series()
321    }
322
323    fn as_single_ptr(&mut self) -> PolarsResult<usize> {
324        self.0.as_single_ptr()
325    }
326
327    fn shift(&self, periods: i64) -> Series {
328        self.0.shift(periods).into_date().into_series()
329    }
330
331    fn max_reduce(&self) -> PolarsResult<Scalar> {
332        let sc = self.0.max_reduce();
333        let av = sc.value().cast(self.dtype()).into_static();
334        Ok(Scalar::new(self.dtype().clone(), av))
335    }
336
337    fn min_reduce(&self) -> PolarsResult<Scalar> {
338        let sc = self.0.min_reduce();
339        let av = sc.value().cast(self.dtype()).into_static();
340        Ok(Scalar::new(self.dtype().clone(), av))
341    }
342
343    fn median_reduce(&self) -> PolarsResult<Scalar> {
344        let av: AnyValue = self
345            .median()
346            .map(|v| (v * (MS_IN_DAY as f64)) as i64)
347            .into();
348        Ok(Scalar::new(
349            DataType::Datetime(TimeUnit::Milliseconds, None),
350            av,
351        ))
352    }
353
354    fn clone_inner(&self) -> Arc<dyn SeriesTrait> {
355        Arc::new(SeriesWrap(Clone::clone(&self.0)))
356    }
357
358    fn as_any(&self) -> &dyn Any {
359        &self.0
360    }
361
362    fn as_any_mut(&mut self) -> &mut dyn Any {
363        &mut self.0
364    }
365
366    fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
367        self as _
368    }
369}
370
371impl private::PrivateSeriesNumeric for SeriesWrap<DateChunked> {
372    fn bit_repr(&self) -> Option<BitRepr> {
373        Some(self.0.to_bit_repr())
374    }
375}