Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-ops/src/series/ops/duration.rs
8449 views
1
use arrow::temporal_conversions::{MICROSECONDS, MILLISECONDS, NANOSECONDS, SECONDS_IN_DAY};
2
use polars_core::datatypes::{AnyValue, DataType, TimeUnit};
3
use polars_core::prelude::Column;
4
use polars_error::PolarsResult;
5
6
pub fn impl_duration(s: &[Column], time_unit: TimeUnit) -> PolarsResult<Column> {
7
if s.iter().any(|s| s.is_empty()) {
8
return Ok(Column::new_empty(
9
s[0].name().clone(),
10
&DataType::Duration(time_unit),
11
));
12
}
13
14
// TODO: Handle overflow for UInt64
15
let weeks = &s[0];
16
let days = &s[1];
17
let hours = &s[2];
18
let minutes = &s[3];
19
let seconds = &s[4];
20
let mut milliseconds = s[5].clone();
21
let mut microseconds = s[6].clone();
22
let mut nanoseconds = s[7].clone();
23
24
let is_scalar = |s: &Column| s.len() == 1;
25
let is_zero = |av: AnyValue<'_>| match av {
26
v if v.is_integer() => v == AnyValue::Int64(0),
27
v if v.is_float() => v == AnyValue::Float64(0.0),
28
_ => false,
29
};
30
let is_zero_scalar = |s: &Column| is_scalar(s) && is_zero(s.get(0).unwrap());
31
32
// Process subseconds
33
let max_len = s.iter().map(|s| s.len()).max().unwrap();
34
let mut duration = match time_unit {
35
TimeUnit::Microseconds => {
36
if is_scalar(&microseconds) {
37
microseconds = microseconds.new_from_index(0, max_len);
38
}
39
if !is_zero_scalar(&nanoseconds) {
40
microseconds = (microseconds + (nanoseconds.wrapping_trunc_div_scalar(1_000)))?;
41
}
42
if !is_zero_scalar(&milliseconds) {
43
microseconds = (microseconds + milliseconds * 1_000)?;
44
}
45
microseconds
46
},
47
TimeUnit::Nanoseconds => {
48
if is_scalar(&nanoseconds) {
49
nanoseconds = nanoseconds.new_from_index(0, max_len);
50
}
51
if !is_zero_scalar(&microseconds) {
52
nanoseconds = (nanoseconds + microseconds * 1_000)?;
53
}
54
if !is_zero_scalar(&milliseconds) {
55
nanoseconds = (nanoseconds + milliseconds * 1_000_000)?;
56
}
57
nanoseconds
58
},
59
TimeUnit::Milliseconds => {
60
if is_scalar(&milliseconds) {
61
milliseconds = milliseconds.new_from_index(0, max_len);
62
}
63
if !is_zero_scalar(&nanoseconds) {
64
milliseconds = (milliseconds + (nanoseconds.wrapping_trunc_div_scalar(1_000_000)))?;
65
}
66
if !is_zero_scalar(&microseconds) {
67
milliseconds = (milliseconds + (microseconds.wrapping_trunc_div_scalar(1_000)))?;
68
}
69
milliseconds
70
},
71
};
72
73
// Process other duration specifiers
74
let multiplier = match time_unit {
75
TimeUnit::Nanoseconds => NANOSECONDS,
76
TimeUnit::Microseconds => MICROSECONDS,
77
TimeUnit::Milliseconds => MILLISECONDS,
78
};
79
if !is_zero_scalar(seconds) {
80
duration = (duration + seconds * multiplier)?;
81
}
82
if !is_zero_scalar(minutes) {
83
duration = (duration + minutes * (multiplier * 60))?;
84
}
85
if !is_zero_scalar(hours) {
86
duration = (duration + hours * (multiplier * 60 * 60))?;
87
}
88
if !is_zero_scalar(days) {
89
duration = (duration + days * (multiplier * SECONDS_IN_DAY))?;
90
}
91
if !is_zero_scalar(weeks) {
92
duration = (duration + weeks * (multiplier * SECONDS_IN_DAY * 7))?;
93
}
94
95
duration.cast(&DataType::Duration(time_unit))
96
}
97
98