Skip to main content

A lightweight compiled timeline engine for operational availability, downtime, capacity, and JSON-backed definitions.

Project description

TimeGrid

PyPI Version License Runtime

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 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.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

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 Distribution

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

timegrid-0.1.1-cp312-cp312-win_amd64.whl (372.4 kB view details)

Uploaded CPython 3.12Windows x86-64

File details

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

File metadata

File hashes

Hashes for timegrid-0.1.1-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 49c46b63dc4d0b2cefa696a4b1d8d0556e9bc383d30c48e5ccdc01acb0342cf6
MD5 2e32e2f82d9529cbc255425fd517ce25
BLAKE2b-256 cdd5595660b72a2a9d7f7d892cfd9d5c93576403674d0dd5b31ca13954cf5d14

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