Skip to main content

Business-hours, availability, downtime, capacity, and SLA working-time calculations for Python, powered by Rust.

Project description

TimeGrid for Python

PyPI Version License Runtime

Business-hours, availability, downtime, capacity, and SLA working-time calculations for Python, powered by Rust.

TimeGrid turns schedule rules into a queryable operational timeline. Define working hours, lunch breaks, holidays, maintenance windows, capacity overrides, and named schedule entries; serialize the source definition as JSON; compile it once; then answer timestamp and range queries quickly.

Use it for factory calendars, machine availability, SLA clocks, business-hour math, capacity-aware slot search, and systems that need a dependable time layer before they schedule, simulate, dispatch, or report.

Not a scheduler. Not a simulator. Not a timezone database. TimeGrid is the availability and working-time engine those systems can depend on.

Install

pip install timegrid

30-Second Example

Calculate an SLA due date while skipping lunch, nights, weekends, and one-off closures:

from datetime import date, datetime, time
from timegrid import TimeGridCalendar, hours

calendar = (
    TimeGridCalendar.weekdays(time(9), time(17))
    .break_weekdays(time(12), time(13))
    .close(date(2026, 1, 1))
    .set_closed_window("company-offsite", datetime(2026, 1, 7, 13), datetime(2026, 1, 7, 17))
)

opened_at = datetime(2026, 1, 5, 11)
trace = calendar.at(opened_at).trace_work_duration(hours(10))

print(trace.result)
for step in trace.steps:
    print(step.window, step.duration)

Practical Examples

Runnable examples live in examples/:

python examples/sla_due_date.py
python examples/manufacturing_capacity_slot.py
python examples/fleet_batch_snapshot.py
python examples/json_schedule_template.py
python examples/overnight_shift.py

From a local checkout:

.\.venv\Scripts\python.exe examples\run_all.py
Example What it shows
sla_due_date.py Business-hour due dates and consumed working windows.
manufacturing_capacity_slot.py Downtime, capacity boosts, and first slot with enough capacity.
fleet_batch_snapshot.py Batch capacity and analysis queries across many compiled machine timelines.
json_schedule_template.py JSON schedule templates plus per-machine exceptions.
overnight_shift.py Open rules that cross midnight and breaks inside overnight shifts.

What It Answers

Question API
Can this machine, team, or queue work now? timeline.analyze(now).can_work
What is the effective capacity at this timestamp? analysis.capacity
Which state window contains this timestamp? analysis.current_window
When does the state change next? analysis.next_transition
Why is this timestamp blocked or boosted? calendar.at(now).analyze().matches
How much usable business time exists in a range? timeline.get_working_duration(start, end)
Where is the first continuous slot with enough capacity? timeline.find_first_slot(start, hours(2), 3)
What are many capacities at once? timeline.get_capacities_at(instants)
What is the state of many machine timelines now? TimeGridTimelineBatch(timelines).get_capacities_at(now)

Schedule Definitions

TimeGrid stores source rules, not compiled runtime state. That makes definitions easy to save, review, ship, and apply to many operational entities:

from datetime import datetime, time
from timegrid import TimeGridCalendar

template_json = (
    TimeGridCalendar.create()
    .open_weekdays(time(7), time(19))
    .break_weekdays(time(12), time(12, 45))
    .capacity(3)
    .to_json(indented=True)
)

template = TimeGridCalendar.from_json(template_json).to_definition()

machine = (
    template.to_calendar()
    .set_closed_window("machine-42-maintenance", datetime(2026, 1, 5, 15), datetime(2026, 1, 5, 17))
    .set_capacity_window("machine-42-overtime-crew", datetime(2026, 1, 5, 17), datetime(2026, 1, 5, 19), 5)
    .compile(datetime(2026, 1, 5), datetime(2026, 1, 6))
)

Compile For Repeated Reads

Use compile(start, end) when the same calendar will be queried many times. A compiled timeline is read-only and answers point and range queries by searching precomputed state segments.

from timegrid import TimeGridTimelineBatch, hours

timeline = calendar.compile(month_start, month_end)

point = timeline.analyze(now)
work = timeline.get_working_duration(day_start, day_end)
slot = timeline.find_first_slot(day_start, hours(4), 2)

capacities = timeline.get_capacities_at(instants)
analyses = timeline.analyze_many(instants)

fleet = TimeGridTimelineBatch(machine_timelines)
fleet_capacities = fleet.get_capacities_at(now)

API Style

Python code can use Python naming conventions while compatibility aliases preserve the original TimeGrid.NET-style names.

Surface Python style Compatibility style
Classes TimeGridCalendar, TimeWindow same
Methods and properties snake_case PascalCase
Constants DayOfWeek.MONDAY DayOfWeek.Monday

Why It Is Fast

Operation Runtime strategy
Point analysis Binary search over compiled state segments
Range analysis Binary search, then scan touched segments only
Transition lookup Segment boundary lookup
Working duration Sum usable segment durations
Slot search Scan continuous capacity-matching segments
Batch point queries One Python call, Rust loop over compiled timelines
JSON Rust serde source definition serialization

Local quick-query benchmark on CPython 3.12, Windows 10, Rust release wheel. The scenario matches the TimeGrid.NET QuickQueryPerf benchmark: 50,000 compiled state segments, 1,000 compiled machine timelines, 20,000 warmup calls, and 1,000,000 measured calls.

Common API, one Python call per query:

Scenario Operation Python/Rust TimeGrid.NET
50,000 compiled state segments get_capacity_at 0.153 us/query 0.052 us/query
50,000 compiled state segments analyze 0.225 us/query 0.064 us/query
1,000 compiled machine timelines get_capacity_at sweep 123.154 us 26.625 us
1,000 compiled machine timelines analyze sweep 189.991 us 34.463 us

Batch API, one Python call per batch:

Scenario Operation Python/Rust
50,000 compiled state segments get_capacities_at 0.076 us/query
50,000 compiled state segments analyze_many 0.220 us/query
1,000 compiled machine timelines TimeGridTimelineBatch.get_capacities_at sweep 28.342 us
1,000 compiled machine timelines TimeGridTimelineBatch.analyze sweep 118.398 us

Measurements exclude compile time and run against already compiled timelines.

Good Fit

Use TimeGrid for Use something else for
Business-hours and working-time calculations Calendar UI rendering
Manufacturing availability and machine downtime Queue dispatching
Capacity-aware slot search Optimization solving
SLA clocks and operational reporting Full timezone database behavior
JSON-backed schedule definitions General-purpose date-range value objects
Scheduler or simulator availability layer Running background jobs

Core Rules

  • Time windows are half-open: [start, end).
  • Capacity 0 means unavailable.
  • Capacity overrides split the timeline into state segments.
  • JSON stores source definitions, not compiled timelines.
  • Compiled timelines are read-only and optimized for repeated analysis.
  • Use naive datetime values consistently in your chosen local or UTC convention.

Direct APIs

calendar.can_work(now)
calendar.get_capacity_at(now)
calendar.get_windows_at(now)
calendar.get_previous_transition_time(now)
calendar.get_next_transition_time(now)
calendar.get_open_windows(start, end)
calendar.get_unavailable_windows(start, end)
calendar.get_state_windows(start, end)
calendar.get_working_duration(start, end)
calendar.find_first_slot(start, hours(2), 2)

timeline.get_capacities_at(instants)
timeline.analyze_many(instants)
TimeGridTimelineBatch(timelines).get_capacities_at(now)

Links

If TimeGrid gives you a wrong answer, a confusing error, or a missing API for a real scheduling or availability problem, please open a GitHub issue with the smallest calendar definition and query that reproduces it.

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

timegrid-0.1.3.tar.gz (23.8 kB view details)

Uploaded Source

Built Distribution

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

timegrid-0.1.3-cp312-cp312-win_amd64.whl (375.9 kB view details)

Uploaded CPython 3.12Windows x86-64

File details

Details for the file timegrid-0.1.3.tar.gz.

File metadata

  • Download URL: timegrid-0.1.3.tar.gz
  • Upload date:
  • Size: 23.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.13.3

File hashes

Hashes for timegrid-0.1.3.tar.gz
Algorithm Hash digest
SHA256 ca8439029f37a9ca928d06f13b1dafedd5100b43089d3c7a57e4b89ac4b36b7b
MD5 720a5144b35018596a42ac8cf275ec04
BLAKE2b-256 4cc73e28642749cfd8b9a17897e3aa89205d0547367dcdcc3f4bc634a4a1dcdc

See more details on using hashes here.

File details

Details for the file timegrid-0.1.3-cp312-cp312-win_amd64.whl.

File metadata

File hashes

Hashes for timegrid-0.1.3-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 5973648cad0c48fab1982d5e4086580ec3f0ebedfa35f447dd34369d20d2529c
MD5 1a149006f172e90b9428693f264fe2ff
BLAKE2b-256 8ca1522ac8709774b8307ab0aff1959376903029f37aeb33488438841a176cbf

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