polars_time/windows/
index_space.rs1use polars_arrow::legacy::time_zone::Tz;
9use polars_core::prelude::*;
10
11#[derive(Clone)]
14pub struct IndexSpace {
15 pub time_unit: TimeUnit,
16 time_zone: Option<TimeZone>,
17 tz: Option<Tz>,
18 index_dtype: DataType,
19}
20
21impl std::fmt::Debug for IndexSpace {
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 f.debug_struct("IndexSpace")
24 .field("time_unit", &self.time_unit)
25 .field("time_zone", &self.time_zone)
26 .field("index_dtype", &self.index_dtype)
27 .finish()
28 }
29}
30
31impl IndexSpace {
32 pub fn dynamic(index_dtype: &DataType) -> PolarsResult<Self> {
40 Self::new(index_dtype, false)
41 }
42
43 pub fn rolling(index_dtype: &DataType) -> PolarsResult<Self> {
46 Self::new(index_dtype, true)
47 }
48
49 fn new(index_dtype: &DataType, allow_unsigned: bool) -> PolarsResult<Self> {
50 let DataType::Datetime(time_unit, time_zone) =
51 window_datetime_dtype(index_dtype, allow_unsigned)?
52 else {
53 unreachable!()
54 };
55 #[cfg(feature = "timezones")]
56 let tz = time_zone.as_ref().and_then(|tz| tz.parse::<Tz>().ok());
57 #[cfg(not(feature = "timezones"))]
58 let tz = None;
59 Ok(Self {
60 time_unit,
61 time_zone,
62 tz,
63 index_dtype: index_dtype.clone(),
64 })
65 }
66
67 pub fn tz(&self) -> Option<&Tz> {
70 self.tz.as_ref()
71 }
72
73 pub fn time_zone(&self) -> Option<&TimeZone> {
75 self.time_zone.as_ref()
76 }
77
78 pub fn window_dtype(&self) -> DataType {
80 DataType::Datetime(self.time_unit, self.time_zone.clone())
81 }
82
83 pub fn cast_to_space(&self, index: &Column) -> PolarsResult<Column> {
85 debug_assert_eq!(index.dtype(), &self.index_dtype);
86 match &self.index_dtype {
87 DataType::Datetime(_, _) => Ok(index.clone()),
88 DataType::Int32 | DataType::UInt32 | DataType::UInt64 => {
89 index.cast(&DataType::Int64)?.cast(&self.window_dtype())
90 },
91 _ => index.cast(&self.window_dtype()),
92 }
93 }
94
95 pub fn cast_from_space(&self, column: &Column) -> PolarsResult<Column> {
97 debug_assert_eq!(column.dtype(), &self.window_dtype());
98 match &self.index_dtype {
99 DataType::Datetime(_, _) => Ok(column.clone()),
100 dt if dt.is_integer() => column.cast(&DataType::Int64)?.cast(dt),
101 dt => column.cast(dt),
102 }
103 }
104
105 pub fn cast_to_boundary(&self, column: &Column) -> PolarsResult<Column> {
109 match &self.index_dtype {
110 DataType::Date => Ok(column.clone()),
111 _ => self.cast_from_space(column),
112 }
113 }
114}
115
116fn window_datetime_dtype(index_dtype: &DataType, allow_unsigned: bool) -> PolarsResult<DataType> {
119 use DataType::*;
120 Ok(match index_dtype {
121 Datetime(_, _) => index_dtype.clone(),
122 Date => Datetime(TimeUnit::Microseconds, None),
123 Int32 | Int64 => Datetime(TimeUnit::Nanoseconds, None),
124 UInt32 | UInt64 if allow_unsigned => Datetime(TimeUnit::Nanoseconds, None),
125 dt if allow_unsigned => polars_bail!(
126 ComputeError:
127 "expected any of the following dtypes: {{ Date, Datetime, Int32, Int64, UInt32, UInt64 }}, got {}",
128 dt
129 ),
130 dt => polars_bail!(
131 ComputeError:
132 "expected any of the following dtypes: {{ Date, Datetime, Int32, Int64 }}, got {}",
133 dt
134 ),
135 })
136}