Skip to main content

A lightweight, flexible business duration calculator.

Project description

bizdurr

Tests PyPI version PyPI - Downloads Python versions License: MIT

A lightweight, flexible business duration calculator

Calculate the amount of time that falls within your defined business hours — accounting for weekly schedules, holidays, and per-date overrides.


Installation

uv add bizdurr

Or with pip:

pip install bizdurr

Or install from source:

git clone https://github.com/patclrk/bizdurr.git
cd bizdurr
uv pip install .

Quick Start

from datetime import datetime
from bizdurr import BusinessDuration

# Define your weekly business hours
schedule = {
    "monday":    {"start": "09:00", "end": "17:00"},
    "tuesday":   {"start": "09:00", "end": "17:00"},
    "wednesday": {"start": "09:00", "end": "17:00"},
    "thursday":  {"start": "09:00", "end": "17:00"},
    "friday":    {"start": "09:00", "end": "17:00"},
}

# Create a BusinessDuration instance
bd = BusinessDuration(
    business_hours=schedule,
    business_timezone="America/New_York",
)

# Calculate the business duration between two datetimes
start = datetime(2025, 12, 8, 8, 0)   # Monday 8:00 AM
end   = datetime(2025, 12, 8, 18, 0)  # Monday 6:00 PM

duration = bd.calculate(start, end)
print(duration)  # 8:00:00 (8 hours of business time)
type(duration)  # <class 'datetime.timedelta'>

In a DataFrame

from datetime import datetime
import polars as pl
from bizdurr import BusinessDuration

# Set up business hours
bd = BusinessDuration(
    business_hours={"start": "09:00", "end": "17:00"},
    business_timezone="America/New_York",
)

# Create a dataframe with start and end timestamps
df = pl.DataFrame({
    "ticket_id": [1, 2, 3, 4],
    "start_time": [
        datetime(2025, 12, 8, 9, 0),   # Monday 9:00 AM
        datetime(2025, 12, 8, 16, 0),  # Monday 4:00 PM
        datetime(2025, 12, 9, 10, 0),  # Tuesday 10:00 AM
        datetime(2025, 12, 12, 11, 0), # Friday 11:00 AM
    ],
    "end_time": [
        datetime(2025, 12, 8, 12, 0),  # Monday 12:00 PM
        datetime(2025, 12, 9, 10, 0),  # Tuesday 10:00 AM
        datetime(2025, 12, 9, 15, 0),  # Tuesday 3:00 PM
        datetime(2025, 12, 12, 17, 0), # Friday 5:00 PM
    ],
})

# Calculate business duration for each row
df_with_duration = df.with_columns(
    business_duration=pl.struct("start_time", "end_time").map_elements(
        lambda row: bd.calculate(row["start_time"], row["end_time"])
    )
)

print(df_with_duration)
# Output:
# ┌───────────┬─────────────────────┬─────────────────────┬──────────────────┐
# │ ticket_id ┆ start_time          ┆ end_time            ┆ business_duration│
# │ ---       ┆ ---                 ┆ ---                 ┆ ---              │
# │ i64       ┆ datetime[μs]        ┆ datetime[μs]        ┆ duration[μs]     │
# ╞═══════════╪═════════════════════╪═════════════════════╪══════════════════╡
# │ 1         ┆ 2025-12-08 09:00:00 ┆ 2025-12-08 12:00:00 ┆ 3h               │
# │ 2         ┆ 2025-12-08 16:00:00 ┆ 2025-12-09 10:00:00 ┆ 2h               │
# │ 3         ┆ 2025-12-09 10:00:00 ┆ 2025-12-09 15:00:00 ┆ 5h               │
# │ 4         ┆ 2025-12-12 11:00:00 ┆ 2025-12-12 17:00:00 ┆ 6h               │
# └───────────┴─────────────────────┴─────────────────────┴──────────────────┘

Features

Weekly Schedule

Pass a dict mapping weekday names (case-insensitive) to start/end times in HH:MM 24-hour format:

schedule = {
    "monday": {"start": "09:00", "end": "17:00"},
    "tuesday": {"start": "10:00", "end": "16:00"},
    # ...
}

Shorthand Schedule (Monday–Friday)

For a fixed Monday through Friday schedule, use the shorthand format:

bd = BusinessDuration(
    business_hours={"start": "09:00", "end": "17:00"},  # Expands to Mon-Fri
    business_timezone="America/New_York",
)

This automatically expands to Monday through Friday with the same hours. Weekend days (Saturday and Sunday) are excluded.

Holidays

Exclude specific dates from business hours:

bd = BusinessDuration(
    business_hours=schedule,
    business_timezone="America/New_York",
    holidays=["2025-12-25", "2026-01-01"],  # ISO date strings or date objects
)

Per-Date Overrides

Override business hours for specific dates (e.g., early close):

bd = BusinessDuration(
    business_hours=schedule,
    business_timezone="America/New_York",
    overrides={
        # Christmas Eve: half day
        "2025-12-24": {"start": "09:00", "end": "12:00"},
    },
)

Timezone Handling

The business_timezone parameter specifies where the business is located. All business hours are interpreted in this timezone, and all calculations are performed relative to it.

from datetime import datetime
from zoneinfo import ZoneInfo
from bizdurr import BusinessDuration

# Business is located in New York
bd = BusinessDuration(
    business_hours={"start": "09:00", "end": "17:00"},
    business_timezone="America/New_York",
)

# 1. Naive datetimes are assumed to be in the business timezone
bd.calculate(
    datetime(2025, 12, 8, 10, 0),
    datetime(2025, 12, 8, 15, 0)
)  # 5 hours

# 2. Aware datetimes in the same timezone work as expected
eastern = ZoneInfo("America/New_York")
bd.calculate(
    datetime(2025, 12, 8, 10, 0, tzinfo=eastern),
    datetime(2025, 12, 8, 15, 0, tzinfo=eastern)
)  # 5 hours

# 3. Aware datetimes in different timezones are converted automatically
pacific = ZoneInfo("America/Los_Angeles")
bd.calculate(
    datetime(2025, 12, 8, 7, 0, tzinfo=pacific),   # 7 AM Pacific = 10 AM Eastern
    datetime(2025, 12, 8, 12, 0, tzinfo=pacific)   # 12 PM Pacific = 3 PM Eastern
)  # 5 hours

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bizdurr-2.0.1.tar.gz (10.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bizdurr-2.0.1-py3-none-any.whl (14.5 kB view details)

Uploaded Python 3

File details

Details for the file bizdurr-2.0.1.tar.gz.

File metadata

  • Download URL: bizdurr-2.0.1.tar.gz
  • Upload date:
  • Size: 10.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for bizdurr-2.0.1.tar.gz
Algorithm Hash digest
SHA256 1b764cf5dc080aac4526d4ccf795a275df846ffc2e423bee8e5b8d69d84e61eb
MD5 470776a91c52b511a6818862d47ed132
BLAKE2b-256 6d24803dea66de11f05c1634ab9b79162181242f9bfa2c994435368f765f2bc6

See more details on using hashes here.

File details

Details for the file bizdurr-2.0.1-py3-none-any.whl.

File metadata

  • Download URL: bizdurr-2.0.1-py3-none-any.whl
  • Upload date:
  • Size: 14.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for bizdurr-2.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a3a4867f8d7eb6ff55c93ca81f02fdd19eda37712701fbf2da6d4dee3165a780
MD5 b4c60cf77c3905e9a716c0bd26fa72e2
BLAKE2b-256 320fbbe7a36c70e350194653cbd0d420afdde5e8a328d0447688b73369fe474a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page