Metadata-Version: 2.1
Name: polars-business
Version: 0.2.0
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
License-File: LICENSE
Summary: Business day utilities for Polars
Author-email: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com>
Requires-Python: >=3.8
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM

# Polars-business

	polars-business

[![PyPI version](https://badge.fury.io/py/polars-business.svg)](https://badge.fury.io/py/polars-business)

Business day utilities for [Polars](https://www.pola.rs/).

- ✅ blazingly fast, written in Rust!
- ✅ seamless Polars integration!
- ✅ define your own custom holidays and weekends!

Installation
------------

First, you need to [install Polars](https://pola-rs.github.io/polars/user-guide/installation/).

Then, you'll need to install `polars-business`:
```console
pip install polars-business
```

Then, if you can run
```python
from datetime import date
import polars_business as plb

print(plb.date_range(date(2023, 1, 1), date(2023, 1, 10), eager=True))
```
it means installation all worked correctly!

Usage
-----

1. `import polars_business as plb`
2. use `.bdt` accessor on expressions created via `plb.col`

Supported functions are:
- `Expr.bdt.offset_by`: just like [polars.Expr.dt.offset_by](https://pola-rs.github.io/polars/py-polars/html/reference/expressions/api/polars.Expr.dt.offset_by.html),
  but also accepts:
  - `'1bd'` in the string language (i.e. "1 business day")
  - `holidays` argument, for passing custom holidays
  - `weekend` argument, for passing custom a weekend (default is ('Sat', 'Sun'))
- `plb.date_range`: just like [polars.date_range](https://pola-rs.github.io/polars/py-polars/html/reference/expressions/api/polars.date_range.html#polars-date-range),
  but also accepts:
  - `'1bd'` in the string language (i.e. "1 business day")
  - `holidays` argument, for passing custom holidays
  - `weekend` argument, for passing custom a weekend (default is ('Sat', 'Sun'))
- `plb.datetime_range`: same as above, but the output will be `Datetime` dtype.
- `Expr.bdt.sub`: subtract two `Date`s and count the  number of business dates between them!

See `Examples` below!

Examples
--------
Say we start with
```python
from datetime import date

import polars as pl
import polars_business as plb


df = pl.DataFrame(
    {"date": [date(2023, 4, 3), date(2023, 9, 1), date(2024, 1, 4)]}
)
```

Let's shift `Date` forwards by 5 days, excluding Saturday and Sunday:

```python
result = df.with_columns(
    date_shifted=plb.col("date").bdt.offset_by(
      '5bd',
      weekend=('Sat', 'Sun'),
    )
)
print(result)
```
```
shape: (3, 2)
┌────────────┬──────────────┐
│ date       ┆ date_shifted │
│ ---        ┆ ---          │
│ date       ┆ date         │
╞════════════╪══════════════╡
│ 2023-04-03 ┆ 2023-04-10   │
│ 2023-09-01 ┆ 2023-09-08   │
│ 2024-01-04 ┆ 2024-01-11   │
└────────────┴──────────────┘
```

Let's shift `Date` forwards by 5 days, excluding Friday, Saturday, and England holidays
for 2023 and 2024:

```python
import holidays

uk_holidays = holidays.country_holidays("UK", subdiv='England', years=[2023, 2024])

result = df.with_columns(
    date_shifted=plb.col("date").bdt.offset_by(
      by='5bd',
      weekend=('Sat', 'Sun'),
      holidays=uk_holidays,
    )
)
print(result)
```
```
shape: (3, 2)
┌────────────┬──────────────┐
│ date       ┆ date_shifted │
│ ---        ┆ ---          │
│ date       ┆ date         │
╞════════════╪══════════════╡
│ 2023-04-03 ┆ 2023-04-12   │
│ 2023-09-01 ┆ 2023-09-08   │
│ 2024-01-04 ┆ 2024-01-11   │
└────────────┴──────────────┘
```

Count the number of business dates between two columns:
```python
df = pl.DataFrame(
    {
        "start": [date(2023, 1, 4), date(2023, 5, 1), date(2023, 9, 9)],
        "end": [date(2023, 2, 8), date(2023, 5, 2), date(2023, 12, 30)],
    }
)
result = df.with_columns(n_business_days=plb.col("end").bdt.sub("start"))
print(result)
```
```
shape: (3, 3)
┌────────────┬────────────┬─────────────────┐
│ start      ┆ end        ┆ n_business_days │
│ ---        ┆ ---        ┆ ---             │
│ date       ┆ date       ┆ i32             │
╞════════════╪════════════╪═════════════════╡
│ 2023-01-04 ┆ 2023-02-08 ┆ 25              │
│ 2023-05-01 ┆ 2023-05-02 ┆ 1               │
│ 2023-09-09 ┆ 2023-12-30 ┆ 80              │
└────────────┴────────────┴─────────────────┘
```

Benchmarks
----------

Single-threaded performance is:
- about on par with NumPy
- at least an order of magnitude faster than pandas.

but note that Polars will take care of parallelisation for you, and that this plugin
will fit in with Polars lazy execution.

Check out https://www.kaggle.com/code/marcogorelli/polars-business for some comparisons.

