polars_plan/dsl/function_expr/
business.rs1use std::fmt::{Display, Formatter};
2
3use polars_core::prelude::*;
4use polars_ops::prelude::Roll;
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8use super::FunctionOptions;
9use crate::dsl::{FieldsMapper, SpecialEq};
10use crate::map_as_slice;
11use crate::prelude::{ColumnsUdf, FunctionFlags};
12
13#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
14#[derive(Clone, PartialEq, Debug, Eq, Hash)]
15pub enum BusinessFunction {
16 BusinessDayCount {
17 week_mask: [bool; 7],
18 holidays: Vec<i32>,
19 },
20 AddBusinessDay {
21 week_mask: [bool; 7],
22 holidays: Vec<i32>,
23 roll: Roll,
24 },
25 IsBusinessDay {
26 week_mask: [bool; 7],
27 holidays: Vec<i32>,
28 },
29}
30
31impl BusinessFunction {
32 pub fn get_field(&self, mapper: FieldsMapper) -> PolarsResult<Field> {
33 match self {
34 Self::BusinessDayCount { .. } => mapper.with_dtype(DataType::Int32),
35 Self::AddBusinessDay { .. } => mapper.with_same_dtype(),
36 Self::IsBusinessDay { .. } => mapper.with_dtype(DataType::Boolean),
37 }
38 }
39 pub fn function_options(&self) -> FunctionOptions {
40 use BusinessFunction as B;
41 match self {
42 B::BusinessDayCount { .. } => {
43 FunctionOptions::elementwise().with_flags(|f| f | FunctionFlags::ALLOW_RENAME)
44 },
45 B::AddBusinessDay { .. } | B::IsBusinessDay { .. } => FunctionOptions::elementwise(),
46 }
47 }
48}
49
50impl Display for BusinessFunction {
51 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
52 use BusinessFunction::*;
53 let s = match self {
54 BusinessDayCount { .. } => "business_day_count",
55 AddBusinessDay { .. } => "add_business_days",
56 IsBusinessDay { .. } => "is_business_day",
57 };
58 write!(f, "{s}")
59 }
60}
61impl From<BusinessFunction> for SpecialEq<Arc<dyn ColumnsUdf>> {
62 fn from(func: BusinessFunction) -> Self {
63 use BusinessFunction::*;
64 match func {
65 BusinessDayCount {
66 week_mask,
67 holidays,
68 } => {
69 map_as_slice!(business_day_count, week_mask, &holidays)
70 },
71 AddBusinessDay {
72 week_mask,
73 holidays,
74 roll,
75 } => {
76 map_as_slice!(add_business_days, week_mask, &holidays, roll)
77 },
78 IsBusinessDay {
79 week_mask,
80 holidays,
81 } => {
82 map_as_slice!(is_business_day, week_mask, &holidays)
83 },
84 }
85 }
86}
87
88pub(super) fn business_day_count(
89 s: &[Column],
90 week_mask: [bool; 7],
91 holidays: &[i32],
92) -> PolarsResult<Column> {
93 let start = &s[0];
94 let end = &s[1];
95 polars_ops::prelude::business_day_count(
96 start.as_materialized_series(),
97 end.as_materialized_series(),
98 week_mask,
99 holidays,
100 )
101 .map(Column::from)
102}
103pub(super) fn add_business_days(
104 s: &[Column],
105 week_mask: [bool; 7],
106 holidays: &[i32],
107 roll: Roll,
108) -> PolarsResult<Column> {
109 let start = &s[0];
110 let n = &s[1];
111 polars_ops::prelude::add_business_days(
112 start.as_materialized_series(),
113 n.as_materialized_series(),
114 week_mask,
115 holidays,
116 roll,
117 )
118 .map(Column::from)
119}
120
121pub(super) fn is_business_day(
122 s: &[Column],
123 week_mask: [bool; 7],
124 holidays: &[i32],
125) -> PolarsResult<Column> {
126 let dates = &s[0];
127 polars_ops::prelude::is_business_day(dates.as_materialized_series(), week_mask, holidays)
128 .map(Column::from)
129}