A lightweight compiled timeline engine for operational availability, downtime, capacity, and JSON-backed definitions.
Project description
TimeGrid
TimeGrid is a lightweight compiled timeline engine for Python, powered by Rust.
Define availability, breaks, downtime, holidays, capacity, and named schedule entries. Serialize the source definition as JSON. Compile it once. Analyze timestamps and ranges fast.
Not a scheduler. Not a simulator. Not a DateRange wrapper. TimeGrid is the operational time layer those systems can depend on.
Install
pip install timegrid
What It Answers
| Question | API |
|---|---|
| Can this machine work now? | timeline.Analyze(now).CanWork |
| Which state window contains this timestamp? | analysis.CurrentWindow |
| What is the effective capacity? | analysis.Capacity |
| When does the state change? | analysis.NextTransition |
| Why is this timestamp blocked? | calendar.At(now).Analyze().Matches |
| How much usable time exists in a range? | timeline.GetWorkingDuration(start, end) |
| Where is the first slot with enough capacity? | timeline.FindFirstSlot(start, Hours(2), 3) |
| What are many capacities at once? | timeline.GetCapacitiesAt(instants) |
| What is the state of many machines now? | TimeGridTimelineBatch(machines).GetCapacitiesAt(now) |
Quick Start
from datetime import date, datetime, time
from timegrid import Hours, TimeGridCalendar
month_start = datetime(2026, 1, 1)
month_end = datetime(2026, 2, 1)
timeline = (
TimeGridCalendar
.Weekdays(time(9), time(18))
.BreakWeekdays(time(12), time(13))
.Close(date(2026, 1, 1))
.Down(datetime(2026, 1, 5, 15), datetime(2026, 1, 5, 16))
.Capacity(datetime(2026, 1, 5, 9), datetime(2026, 1, 5, 12), 3)
.Compile(month_start, month_end)
)
state = timeline.Analyze(datetime(2026, 1, 5, 10, 30))
print(state.CanWork)
print(state.Capacity)
print(state.CurrentWindow)
print(state.NextTransition)
JSON Definitions
Store source schedules, not compiled runtime state.
from datetime import datetime, time
from timegrid import TimeGridCalendar
calendar = (
TimeGridCalendar
.Weekdays(time(8), time(20))
.BreakWeekdays(time(12), time(13))
.SetClosedWindow("machine-17-maintenance", down_start, down_end)
.SetCapacityWindow("machine-17-boost", boost_start, boost_end, 4)
)
json = calendar.ToJson(indented=True)
restored = (
TimeGridCalendar
.FromJson(json)
.Compile(month_start, month_end)
)
Manufacturing Pattern
Use one shared template and add equipment-specific exceptions.
template = (
TimeGridCalendar
.Weekdays(time(9), time(18))
.BreakWeekdays(time(12), time(13))
.ToDefinition()
)
machine = (
template
.ToCalendar()
.SetClosedWindow("maintenance", maintenance_start, maintenance_end)
.SetCapacityWindow("extra-line", boost_start, boost_end, 3)
.Compile(month_start, month_end)
)
state = machine.Analyze(now)
This keeps common schedule rules reusable while each machine carries only its own downtime and capacity changes.
Why It Is Fast
Use Compile(start, end) for read-heavy systems:
timeline = calendar.Compile(month_start, month_end)
point = timeline.Analyze(now)
work = timeline.GetWorkingDuration(day_start, day_end)
slot = timeline.FindFirstSlot(day_start, Hours(4), minimumCapacity=2)
For repeated reads, batch the natural unit of work:
capacities = timeline.GetCapacitiesAt(instants)
analyses = timeline.AnalyzeMany(instants)
fleet = TimeGridTimelineBatch(machine_timelines)
fleet_capacities = fleet.GetCapacitiesAt(now)
fleet_analyses = fleet.Analyze(now)
| 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 common 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 | GetCapacityAt |
0.152 us/query | 0.053 us/query |
| 50,000 compiled state segments | Analyze |
0.224 us/query | 0.066 us/query |
| 1,000 compiled machine timelines | GetCapacityAt sweep |
122.539 us | 27.202 us |
| 1,000 compiled machine timelines | Analyze sweep |
190.991 us | 33.581 us |
Batch API, one Python call per batch:
| Scenario | Operation | Python/Rust |
|---|---|---|
| 50,000 compiled state segments | GetCapacitiesAt |
0.074 us/query |
| 50,000 compiled state segments | AnalyzeMany |
0.219 us/query |
| 1,000 compiled machine timelines | TimeGridTimelineBatch.GetCapacitiesAt sweep |
27.962 us |
| 1,000 compiled machine timelines | TimeGridTimelineBatch.Analyze sweep |
120.159 us |
Measurements exclude compile time and run against already compiled timelines. Common API checksums matched TimeGrid.NET at 14277834; the combined Common + Batch verification checksum was 28681706. Batch capacity queries remove most Python method-dispatch overhead, while analysis still pays for creating Python result objects.
Before / After
Without TimeGrid, operational time rules spread across conditionals:
if instant.weekday() >= 5:
return False
if time(9) > instant.time() or instant.time() >= time(18):
return False
if time(12) <= instant.time() < time(13):
return False
if instant.date() in holidays:
return False
if downtime_start <= instant < downtime_end:
return False
return capacity > 0
With TimeGrid, rules are data and queries stay small:
analysis = timeline.Analyze(now)
if analysis.CanWork:
print(f"capacity: {analysis.Capacity}")
Named Timeline Entries
calendar = (
TimeGridCalendar
.Create()
.SetOpenWindow("shift-a", start, end)
.SetClosedWindow("maintenance", down_start, down_end)
.SetCapacityWindow("line-boost", boost_start, boost_end, 4)
)
maintenance = calendar.GetEntry("maintenance")
calendar.SetClosedWindow("maintenance", new_down_start, new_down_end)
calendar.RemoveEntry("maintenance")
Good Fit
| Use TimeGrid for | Use something else for |
|---|---|
| Manufacturing availability | Running background jobs |
| Machine downtime analysis | Queue dispatching |
| Capacity-aware slot search | Calendar UI rendering |
| SLA working-time math | Full time-zone database behavior |
| Scheduler/simulator time layer | Optimization solving |
| JSON-backed schedule definitions | General-purpose DateRange value objects |
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.CanWork(now)
calendar.GetCapacityAt(now)
calendar.GetWindowsAt(now)
calendar.GetPreviousTransitionTime(now)
calendar.GetNextTransitionTime(now)
calendar.GetOpenWindows(start, end)
calendar.GetUnavailableWindows(start, end)
calendar.GetStateWindows(start, end)
calendar.GetWorkingDuration(start, end)
calendar.FindFirstSlot(start, Hours(2), minimumCapacity=2)
timeline.GetCapacitiesAt(instants)
timeline.AnalyzeMany(instants)
TimeGridTimelineBatch(timelines).GetCapacitiesAt(now)
TimeGridTimelineBatch(timelines).Analyze(now)
Development
python -m venv .venv
.venv\Scripts\python -m pip install maturin pytest pytest-benchmark
.venv\Scripts\maturin develop --manifest-path .\timegrid\Cargo.toml --release
.venv\Scripts\python -m pytest -q
.venv\Scripts\maturin build --manifest-path .\timegrid\Cargo.toml --release
Links
- PyPI: https://pypi.org/project/timegrid/
- Repository: https://github.com/code-gihan/timegrid-python
- License: MIT
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file timegrid-0.1.1-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: timegrid-0.1.1-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 372.4 kB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
49c46b63dc4d0b2cefa696a4b1d8d0556e9bc383d30c48e5ccdc01acb0342cf6
|
|
| MD5 |
2e32e2f82d9529cbc255425fd517ce25
|
|
| BLAKE2b-256 |
cdd5595660b72a2a9d7f7d892cfd9d5c93576403674d0dd5b31ca13954cf5d14
|