Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-expr/src/dispatch/temporal.rs
7884 views
1
use polars_core::error::{PolarsResult, polars_bail};
2
use polars_core::prelude::*;
3
use polars_plan::plans::IRTemporalFunction;
4
use polars_utils::pl_str::PlSmallStr;
5
6
use super::*;
7
8
pub fn temporal_func_to_udf(func: IRTemporalFunction) -> SpecialEq<Arc<dyn ColumnsUdf>> {
9
use IRTemporalFunction::*;
10
match func {
11
Millennium => map!(datetime::millennium),
12
Century => map!(datetime::century),
13
Year => map!(datetime::year),
14
IsLeapYear => map!(datetime::is_leap_year),
15
IsoYear => map!(datetime::iso_year),
16
Month => map!(datetime::month),
17
DaysInMonth => map!(datetime::days_in_month),
18
Quarter => map!(datetime::quarter),
19
Week => map!(datetime::week),
20
WeekDay => map!(datetime::weekday),
21
#[cfg(feature = "dtype-duration")]
22
Duration(tu) => map_as_slice!(polars_ops::series::impl_duration, tu),
23
Day => map!(datetime::day),
24
OrdinalDay => map!(datetime::ordinal_day),
25
Time => map!(datetime::time),
26
Date => map!(datetime::date),
27
Datetime => map!(datetime::datetime),
28
Hour => map!(datetime::hour),
29
Minute => map!(datetime::minute),
30
Second => map!(datetime::second),
31
Millisecond => map!(datetime::millisecond),
32
Microsecond => map!(datetime::microsecond),
33
Nanosecond => map!(datetime::nanosecond),
34
#[cfg(feature = "dtype-duration")]
35
TotalDays { fractional: false } => map!(datetime::total_days),
36
#[cfg(feature = "dtype-duration")]
37
TotalDays { fractional: true } => map!(datetime::total_days_fractional),
38
#[cfg(feature = "dtype-duration")]
39
TotalHours { fractional: false } => map!(datetime::total_hours),
40
#[cfg(feature = "dtype-duration")]
41
TotalHours { fractional: true } => map!(datetime::total_hours_fractional),
42
#[cfg(feature = "dtype-duration")]
43
TotalMinutes { fractional: false } => map!(datetime::total_minutes),
44
#[cfg(feature = "dtype-duration")]
45
TotalMinutes { fractional: true } => map!(datetime::total_minutes_fractional),
46
#[cfg(feature = "dtype-duration")]
47
TotalSeconds { fractional: false } => map!(datetime::total_seconds),
48
#[cfg(feature = "dtype-duration")]
49
TotalSeconds { fractional: true } => map!(datetime::total_seconds_fractional),
50
#[cfg(feature = "dtype-duration")]
51
TotalMilliseconds { fractional: false } => map!(datetime::total_milliseconds),
52
#[cfg(feature = "dtype-duration")]
53
TotalMilliseconds { fractional: true } => map!(datetime::total_milliseconds_fractional),
54
#[cfg(feature = "dtype-duration")]
55
TotalMicroseconds { fractional: false } => map!(datetime::total_microseconds),
56
#[cfg(feature = "dtype-duration")]
57
TotalMicroseconds { fractional: true } => map!(datetime::total_microseconds_fractional),
58
#[cfg(feature = "dtype-duration")]
59
TotalNanoseconds { fractional: false } => map!(datetime::total_nanoseconds),
60
#[cfg(feature = "dtype-duration")]
61
TotalNanoseconds { fractional: true } => map!(datetime::total_nanoseconds_fractional),
62
ToString(format) => map!(datetime::to_string, &format),
63
TimeStamp(tu) => map!(datetime::timestamp, tu),
64
#[cfg(feature = "timezones")]
65
ConvertTimeZone(tz) => map!(datetime::convert_time_zone, &tz),
66
WithTimeUnit(tu) => map!(datetime::with_time_unit, tu),
67
CastTimeUnit(tu) => map!(datetime::cast_time_unit, tu),
68
Truncate => {
69
map_as_slice!(datetime::truncate)
70
},
71
#[cfg(feature = "offset_by")]
72
OffsetBy => {
73
map_as_slice!(datetime::offset_by)
74
},
75
#[cfg(feature = "month_start")]
76
MonthStart => map!(datetime::month_start),
77
#[cfg(feature = "month_end")]
78
MonthEnd => map!(datetime::month_end),
79
#[cfg(feature = "timezones")]
80
BaseUtcOffset => map!(datetime::base_utc_offset),
81
#[cfg(feature = "timezones")]
82
DSTOffset => map!(datetime::dst_offset),
83
Round => map_as_slice!(datetime::round),
84
Replace => map_as_slice!(datetime::replace),
85
#[cfg(feature = "timezones")]
86
ReplaceTimeZone(tz, non_existent) => {
87
map_as_slice!(misc::replace_time_zone, tz.as_ref(), non_existent)
88
},
89
Combine(tu) => map_as_slice!(temporal::combine, tu),
90
DatetimeFunction {
91
time_unit,
92
time_zone,
93
} => {
94
map_as_slice!(temporal::datetime, &time_unit, time_zone.as_ref())
95
},
96
}
97
}
98
99
#[cfg(feature = "dtype-datetime")]
100
pub(super) fn datetime(
101
s: &[Column],
102
time_unit: &TimeUnit,
103
time_zone: Option<&TimeZone>,
104
) -> PolarsResult<Column> {
105
use polars_core::prelude::{DataType, DatetimeChunked};
106
use polars_time::prelude::DatetimeMethods;
107
108
let col_name = PlSmallStr::from_static("datetime");
109
110
if s.iter().any(|s| s.is_empty()) {
111
return Ok(Column::new_empty(
112
col_name,
113
&DataType::Datetime(
114
time_unit.to_owned(),
115
match time_zone.cloned() {
116
#[cfg(feature = "timezones")]
117
Some(v) => Some(v),
118
_ => {
119
assert!(
120
time_zone.is_none(),
121
"cannot make use of the `time_zone` argument without the 'timezones' feature enabled."
122
);
123
None
124
},
125
},
126
),
127
));
128
}
129
130
let year = &s[0];
131
let month = &s[1];
132
let day = &s[2];
133
let hour = &s[3];
134
let minute = &s[4];
135
let second = &s[5];
136
let microsecond = &s[6];
137
let ambiguous = &s[7];
138
139
let max_len = s.iter().map(|s| s.len()).max().unwrap();
140
141
let mut year = year.cast(&DataType::Int32)?;
142
if year.len() < max_len {
143
year = year.new_from_index(0, max_len)
144
}
145
let year = year.i32()?;
146
147
let mut month = month.cast(&DataType::Int8)?;
148
if month.len() < max_len {
149
month = month.new_from_index(0, max_len);
150
}
151
let month = month.i8()?;
152
153
let mut day = day.cast(&DataType::Int8)?;
154
if day.len() < max_len {
155
day = day.new_from_index(0, max_len);
156
}
157
let day = day.i8()?;
158
159
let mut hour = hour.cast(&DataType::Int8)?;
160
if hour.len() < max_len {
161
hour = hour.new_from_index(0, max_len);
162
}
163
let hour = hour.i8()?;
164
165
let mut minute = minute.cast(&DataType::Int8)?;
166
if minute.len() < max_len {
167
minute = minute.new_from_index(0, max_len);
168
}
169
let minute = minute.i8()?;
170
171
let mut second = second.cast(&DataType::Int8)?;
172
if second.len() < max_len {
173
second = second.new_from_index(0, max_len);
174
}
175
let second = second.i8()?;
176
177
let mut nanosecond = microsecond.cast(&DataType::Int32)? * 1_000;
178
if nanosecond.len() < max_len {
179
nanosecond = nanosecond.new_from_index(0, max_len);
180
}
181
let nanosecond = nanosecond.i32()?;
182
183
let mut _ambiguous = ambiguous.cast(&DataType::String)?;
184
if _ambiguous.len() < max_len {
185
_ambiguous = _ambiguous.new_from_index(0, max_len);
186
}
187
let ambiguous = _ambiguous.str()?;
188
189
let ca = DatetimeChunked::new_from_parts(
190
year,
191
month,
192
day,
193
hour,
194
minute,
195
second,
196
nanosecond,
197
ambiguous,
198
time_unit,
199
time_zone.cloned(),
200
col_name,
201
);
202
ca.map(|s| s.into_column())
203
}
204
205
pub(super) fn combine(s: &[Column], tu: TimeUnit) -> PolarsResult<Column> {
206
let date = &s[0];
207
let time = &s[1];
208
209
let tz = match date.dtype() {
210
DataType::Date => None,
211
DataType::Datetime(_, tz) => tz.as_ref(),
212
_dtype => {
213
polars_bail!(ComputeError: format!("expected Date or Datetime, got {}", _dtype))
214
},
215
};
216
217
let date = date.cast(&DataType::Date)?;
218
let datetime = date.cast(&DataType::Datetime(tu, None)).unwrap();
219
220
let duration = time.cast(&DataType::Duration(tu))?;
221
let result_naive = datetime + duration;
222
match tz {
223
#[cfg(feature = "timezones")]
224
Some(tz) => Ok(polars_ops::prelude::replace_time_zone(
225
result_naive?.datetime().unwrap(),
226
Some(tz),
227
&StringChunked::from_iter(std::iter::once("raise")),
228
NonExistent::Raise,
229
)?
230
.into_column()),
231
_ => result_naive,
232
}
233
}
234
235