1use std::ops::{Deref, Div};
2
3use arrow::temporal_conversions::{MICROSECONDS_IN_DAY, MILLISECONDS_IN_DAY, NANOSECONDS_IN_DAY};
4use polars_core::prelude::arity::unary_elementwise_values;
5use polars_core::prelude::*;
6
7use crate::chunkedarray::*;
8
9pub trait AsSeries {
10 fn as_series(&self) -> &Series;
11}
12
13impl AsSeries for Series {
14 fn as_series(&self) -> &Series {
15 self
16 }
17}
18
19pub trait TemporalMethods: AsSeries {
20 fn hour(&self) -> PolarsResult<Int8Chunked> {
23 let s = self.as_series();
24 match s.dtype() {
25 #[cfg(feature = "dtype-datetime")]
26 DataType::Datetime(_, _) => s.datetime().map(|ca| ca.hour()),
27 #[cfg(feature = "dtype-time")]
28 DataType::Time => s.time().map(|ca| ca.hour()),
29 dt => polars_bail!(opq = hour, dt),
30 }
31 }
32
33 fn minute(&self) -> PolarsResult<Int8Chunked> {
36 let s = self.as_series();
37 match s.dtype() {
38 #[cfg(feature = "dtype-datetime")]
39 DataType::Datetime(_, _) => s.datetime().map(|ca| ca.minute()),
40 #[cfg(feature = "dtype-time")]
41 DataType::Time => s.time().map(|ca| ca.minute()),
42 dt => polars_bail!(opq = minute, dt),
43 }
44 }
45
46 fn second(&self) -> PolarsResult<Int8Chunked> {
49 let s = self.as_series();
50 match s.dtype() {
51 #[cfg(feature = "dtype-datetime")]
52 DataType::Datetime(_, _) => s.datetime().map(|ca| ca.second()),
53 #[cfg(feature = "dtype-time")]
54 DataType::Time => s.time().map(|ca| ca.second()),
55 dt => polars_bail!(opq = second, dt),
56 }
57 }
58
59 fn nanosecond(&self) -> PolarsResult<Int32Chunked> {
62 let s = self.as_series();
63 match s.dtype() {
64 #[cfg(feature = "dtype-datetime")]
65 DataType::Datetime(_, _) => s.datetime().map(|ca| ca.nanosecond()),
66 #[cfg(feature = "dtype-time")]
67 DataType::Time => s.time().map(|ca| ca.nanosecond()),
68 dt => polars_bail!(opq = nanosecond, dt),
69 }
70 }
71
72 fn day(&self) -> PolarsResult<Int8Chunked> {
77 let s = self.as_series();
78 match s.dtype() {
79 #[cfg(feature = "dtype-date")]
80 DataType::Date => s.date().map(|ca| ca.day()),
81 #[cfg(feature = "dtype-datetime")]
82 DataType::Datetime(_, _) => s.datetime().map(|ca| ca.day()),
83 dt => polars_bail!(opq = day, dt),
84 }
85 }
86 fn weekday(&self) -> PolarsResult<Int8Chunked> {
88 let s = self.as_series();
89 match s.dtype() {
90 #[cfg(feature = "dtype-date")]
91 DataType::Date => s.date().map(|ca| {
92 unary_elementwise_values(ca, |t| (((t - 4) % 7 + 7) % 7 + 1) as i8)
96 }),
97 #[cfg(feature = "dtype-datetime")]
98 DataType::Datetime(time_unit, time_zone) => s.datetime().map(|ca| {
99 match time_zone.as_deref() {
100 Some("UTC") | None => {
101 let divisor = match time_unit {
105 TimeUnit::Milliseconds => MILLISECONDS_IN_DAY,
106 TimeUnit::Microseconds => MICROSECONDS_IN_DAY,
107 TimeUnit::Nanoseconds => NANOSECONDS_IN_DAY,
108 };
109 unary_elementwise_values(ca, |t| {
110 let t = t / divisor - ((t < 0 && t % divisor != 0) as i64);
111 (((t - 4) % 7 + 7) % 7 + 1) as i8
112 })
113 },
114 _ => ca.weekday(),
115 }
116 }),
117 dt => polars_bail!(opq = weekday, dt),
118 }
119 }
120
121 fn week(&self) -> PolarsResult<Int8Chunked> {
124 let s = self.as_series();
125 match s.dtype() {
126 #[cfg(feature = "dtype-date")]
127 DataType::Date => s.date().map(|ca| ca.week()),
128 #[cfg(feature = "dtype-datetime")]
129 DataType::Datetime(_, _) => s.datetime().map(|ca| ca.week()),
130 dt => polars_bail!(opq = week, dt),
131 }
132 }
133
134 fn ordinal_day(&self) -> PolarsResult<Int16Chunked> {
138 let s = self.as_series();
139 match s.dtype() {
140 #[cfg(feature = "dtype-date")]
141 DataType::Date => s.date().map(|ca| ca.ordinal()),
142 #[cfg(feature = "dtype-datetime")]
143 DataType::Datetime(_, _) => s.datetime().map(|ca| ca.ordinal()),
144 dt => polars_bail!(opq = ordinal_day, dt),
145 }
146 }
147
148 fn millennium(&self) -> PolarsResult<Int32Chunked> {
150 let s = self.as_series();
151 match s.dtype() {
152 #[cfg(feature = "dtype-date")]
155 DataType::Date => s.date().map(|ca| (ca.year() - 1i32).div(1000f64) + 1),
156 #[cfg(feature = "dtype-datetime")]
157 DataType::Datetime(_, _) => s.datetime().map(|ca| (ca.year() - 1i32).div(1000f64) + 1),
158 dt => polars_bail!(opq = century, dt),
159 }
160 }
161
162 fn century(&self) -> PolarsResult<Int32Chunked> {
164 let s = self.as_series();
165 match s.dtype() {
166 #[cfg(feature = "dtype-date")]
169 DataType::Date => s.date().map(|ca| (ca.year() - 1i32).div(100f64) + 1),
170 #[cfg(feature = "dtype-datetime")]
171 DataType::Datetime(_, _) => s.datetime().map(|ca| (ca.year() - 1i32).div(100f64) + 1),
172 dt => polars_bail!(opq = century, dt),
173 }
174 }
175
176 fn year(&self) -> PolarsResult<Int32Chunked> {
179 let s = self.as_series();
180 match s.dtype() {
181 #[cfg(feature = "dtype-date")]
182 DataType::Date => s.date().map(|ca| ca.year()),
183 #[cfg(feature = "dtype-datetime")]
184 DataType::Datetime(_, _) => s.datetime().map(|ca| ca.year()),
185 dt => polars_bail!(opq = year, dt),
186 }
187 }
188
189 fn iso_year(&self) -> PolarsResult<Int32Chunked> {
190 let s = self.as_series();
191 match s.dtype() {
192 #[cfg(feature = "dtype-date")]
193 DataType::Date => s.date().map(|ca| ca.iso_year()),
194 #[cfg(feature = "dtype-datetime")]
195 DataType::Datetime(_, _) => s.datetime().map(|ca| ca.iso_year()),
196 dt => polars_bail!(opq = iso_year, dt),
197 }
198 }
199
200 fn ordinal_year(&self) -> PolarsResult<Int32Chunked> {
203 let s = self.as_series();
204 match s.dtype() {
205 #[cfg(feature = "dtype-date")]
206 DataType::Date => s.date().map(|ca| ca.year()),
207 #[cfg(feature = "dtype-datetime")]
208 DataType::Datetime(_, _) => s.datetime().map(|ca| ca.year()),
209 dt => polars_bail!(opq = ordinal_year, dt),
210 }
211 }
212
213 fn is_leap_year(&self) -> PolarsResult<BooleanChunked> {
216 let s = self.as_series();
217 match s.dtype() {
218 #[cfg(feature = "dtype-date")]
219 DataType::Date => s.date().map(|ca| ca.is_leap_year()),
220 #[cfg(feature = "dtype-datetime")]
221 DataType::Datetime(_, _) => s.datetime().map(|ca| ca.is_leap_year()),
222 dt => polars_bail!(opq = is_leap_year, dt),
223 }
224 }
225
226 fn quarter(&self) -> PolarsResult<Int8Chunked> {
229 let s = self.as_series();
230 match s.dtype() {
231 #[cfg(feature = "dtype-date")]
232 DataType::Date => s.date().map(|ca| ca.quarter()),
233 #[cfg(feature = "dtype-datetime")]
234 DataType::Datetime(_, _) => s.datetime().map(|ca| ca.quarter()),
235 dt => polars_bail!(opq = quarter, dt),
236 }
237 }
238
239 fn month(&self) -> PolarsResult<Int8Chunked> {
244 let s = self.as_series();
245 match s.dtype() {
246 #[cfg(feature = "dtype-date")]
247 DataType::Date => s.date().map(|ca| ca.month()),
248 #[cfg(feature = "dtype-datetime")]
249 DataType::Datetime(_, _) => s.datetime().map(|ca| ca.month()),
250 dt => polars_bail!(opq = month, dt),
251 }
252 }
253
254 fn to_string(&self, format: &str) -> PolarsResult<Series> {
257 let s = self.as_series();
258 match s.dtype() {
259 #[cfg(feature = "dtype-datetime")]
260 DataType::Datetime(_, _) => {
261 let format = get_strftime_format(format, s.dtype())?;
262 s.datetime()
263 .map(|ca| Ok(ca.to_string(format.as_str())?.into_series()))?
264 },
265 #[cfg(feature = "dtype-date")]
266 DataType::Date => {
267 let format = get_strftime_format(format, s.dtype())?;
268 s.date()
269 .map(|ca| Ok(ca.to_string(format.as_str())?.into_series()))?
270 },
271 #[cfg(feature = "dtype-time")]
272 DataType::Time => {
273 let format = get_strftime_format(format, s.dtype())?;
274 s.time()
275 .map(|ca| ca.to_string(format.as_str()).into_series())
276 },
277 #[cfg(feature = "dtype-duration")]
278 DataType::Duration(_) => s
279 .duration()
280 .map(|ca| Ok(ca.to_string(format)?.into_series()))?,
281 dt => polars_bail!(opq = to_string, dt),
282 }
283 }
284
285 fn strftime(&self, format: &str) -> PolarsResult<Series> {
290 self.to_string(format)
291 }
292
293 #[cfg(feature = "temporal")]
294 fn timestamp(&self, tu: TimeUnit) -> PolarsResult<Int64Chunked> {
296 let s = self.as_series();
297 if matches!(s.dtype(), DataType::Time | DataType::Duration(_)) {
298 polars_bail!(opq = timestamp, s.dtype());
299 } else {
300 s.cast(&DataType::Datetime(tu, None))
301 .map(|s| s.datetime().unwrap().deref().clone())
302 }
303 }
304}
305
306impl<T: ?Sized + AsSeries> TemporalMethods for T {}