Skip to main content
Loss of provenance

A previous release had provenance metadata, but this release does not. View details.

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.

Metadata

Release files for timegrid 0.1.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Loss of provenance

These files do not have provenance metadata, despite files in a prior release including this data.

We recommend further investigation before installing these files. View details.

Built distributions (wheels)

Table of built distributions (wheels) for timegrid 0.1.6
File Interpreter ABI Platform
timegrid-0.1.6-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
timegrid-0.1.6-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.9 abi3 Linux glibc 2.17+ x86-64 Details
timegrid-0.1.6-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl CPython 3.9 abi3 macOS 10.12+ x86-64, macOS 10.12+ universal2 (ARM64, x86-64), macOS 11.0+ ARM64 Details

Total release size: 1.9 MB

Release files / timegrid-0.1.6-cp39-abi3-win_amd64.whl

Loss of provenance

This file belongs to a release without provenance metadata, despite a prior release including this data.

We recommend further investigation before installing this file. View details.

Download URL timegrid-0.1.6-cp39-abi3-win_amd64.whl
Size 376.0 kB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
f1b4731986f66e63b487d4ea1e36479c011708c3632639a9be80aa42471743c1
BLAKE2b-256 checksum
How to use checksums
8bc1e596052c3f373906200a283b2d1b6f63d78a48361beec9b4a1540133defc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Release files / timegrid-0.1.6-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Loss of provenance

This file belongs to a release without provenance metadata, despite a prior release including this data.

We recommend further investigation before installing this file. View details.

Download URL timegrid-0.1.6-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 546.9 kB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
69aec52a18b1fd373c24f2d6ca9971cce63c1bfcc00dc88ba64067e3cc17c348
BLAKE2b-256 checksum
How to use checksums
fd2f7b4c8662ff0aaaf315781191bf6f6d227759a98fd8af6df30ef122e856e8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Release files / timegrid-0.1.6-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl

Loss of provenance

This file belongs to a release without provenance metadata, despite a prior release including this data.

We recommend further investigation before installing this file. View details.

Download URL timegrid-0.1.6-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Size 994.4 kB
Tags CPython 3.9 abi3 macOS 10.12+ universal2 (ARM64, x86-64) macOS 10.12+ x86-64 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
6e656f3a38c3304a707cb318c2d8f7fc7d3d871acc64714203593780a6b742e1
BLAKE2b-256 checksum
How to use checksums
b5dfcc4b7e4267d961054fdfc025f333dea9fe0a041e9ea10eada40fe10f16d8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Security for timegrid 0.1.6

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Loss of provenance

A previous release of these files had provenance metadata, but this release does not.

While this could reflect a routine change by the project maintainers, it may also indicate that the release files have been compromised.

Release comparison

  • Removed 0.1.4 3 files With provenance
  • Added 0.1.6 3 files Without provenance

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page