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

For supported platforms, pip automatically selects the matching prebuilt wheel from PyPI.

Operating system CPU architecture Python Wheel support
Windows x86_64 / AMD64 CPython 3.9+ Prebuilt win_amd64 wheel
Linux x86_64 / AMD64 CPython 3.9+ Prebuilt manylinux2014_x86_64 wheel
macOS Intel x86_64 and Apple Silicon arm64 CPython 3.9+ Prebuilt universal2 wheel

The wheels use Python's stable ABI (abi3), so one wheel per OS/architecture supports CPython 3.9 and newer. Platforms or architectures not listed above are not shipped as prebuilt wheels yet; build from a source checkout with Rust when you need another target.

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 Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

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

timegrid-0.1.6-cp39-abi3-win_amd64.whl (376.0 kB view details)

Uploaded CPython 3.9+Windows x86-64

timegrid-0.1.6-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (546.9 kB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ x86-64

timegrid-0.1.6-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (994.4 kB view details)

Uploaded CPython 3.9+macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

File details

Details for the file timegrid-0.1.6-cp39-abi3-win_amd64.whl.

File metadata

  • Download URL: timegrid-0.1.6-cp39-abi3-win_amd64.whl
  • Upload date:
  • Size: 376.0 kB
  • Tags: CPython 3.9+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for timegrid-0.1.6-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 f1b4731986f66e63b487d4ea1e36479c011708c3632639a9be80aa42471743c1
MD5 18319731086d39e2ba23528270508f4e
BLAKE2b-256 8bc1e596052c3f373906200a283b2d1b6f63d78a48361beec9b4a1540133defc

See more details on using hashes here.

File details

Details for the file timegrid-0.1.6-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for timegrid-0.1.6-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 69aec52a18b1fd373c24f2d6ca9971cce63c1bfcc00dc88ba64067e3cc17c348
MD5 b47c8bcfa0e890193fd62bc368b267fe
BLAKE2b-256 fd2f7b4c8662ff0aaaf315781191bf6f6d227759a98fd8af6df30ef122e856e8

See more details on using hashes here.

File details

Details for the file timegrid-0.1.6-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.

File metadata

File hashes

Hashes for timegrid-0.1.6-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 6e656f3a38c3304a707cb318c2d8f7fc7d3d871acc64714203593780a6b742e1
MD5 0466e45915929a542df60b27cd6d8615
BLAKE2b-256 b5dfcc4b7e4267d961054fdfc025f333dea9fe0a041e9ea10eada40fe10f16d8

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