A previous release had provenance metadata, but this release does not. View details.
TimeGrid for Python
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
0means 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
datetimevalues 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
- PyPI: https://pypi.org/project/timegrid/
- Repository: https://github.com/code-gihan/timegrid-python
- Issues: https://github.com/code-gihan/timegrid-python/issues
- TimeGrid.NET: https://www.nuget.org/packages/TimeGrid.NET
- License: MIT
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)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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.