Skip to main content

Minimal stateless ClickHouse library for 3-dimensional time series

Project description

⏱️ TimeDB

A minimal, stateless Python client for 3-dimensional time series on ClickHouse.

PyPI Python Versions License Slack


TimeDB stores overlapping forecast revisions, auditable corrections, and "time-of-knowledge" history as plain rows in ClickHouse. Every value carries a three-dimensional timestamp so you can replay exactly what was known at any past instant.

Traditional time-series stores assume one immutable value per timestamp. TimeDB is built for the messy reality of forecasts that get revised, observations that get corrected, and backtests that need strict point-in-time audits.


🧊 The 3D Temporal Data Model

At the heart of TimeDB is its three-dimensional approach to time. We track not just when data is valid, but when it became known and when it was altered.

Dimension Description Real-World Example
📅 valid_time The time the value represents a fact for. "Wind speed forecast for Wednesday 12:00"
⏰ knowledge_time The time when the value was predicted/known. "Generated on Monday 18:00"
✏️ change_time The time when the value was written or changed. "Manually overridden on Tuesday 09:00"

Audit & Metadata: Every row also carries changed_by and annotation text fields so corrections leave a readable trail instead of silent overwrites.


✨ Why Choose TimeDB?

  • 📊 Forecast Revisions: Store overlapping forecasts side-by-side — every knowledge_time is preserved.
  • 🔄 Auditable Updates: Corrections are new rows with a fresh change_time; reads collapse them into the latest state, with full history available on demand.
  • True Backtesting: Query historical data as of any point in time ("What did our model know last Monday?"), or use read_relative() for per-window day-ahead cutoffs.
  • 🗂️ Retention Tiers: Pick short / medium / long / forever per series; ClickHouse drops whole partitions when TTLs expire.
  • 🪶 Stateless & Minimal: One class, two tables, no catalog. Series identity (series_id) is owned by the caller — no naming, units, or labels to keep in sync.

🚀 Quick Start

1. Installation

pip install timedb

Requires Python 3.12+ and a reachable ClickHouse instance. TimeDB reads its connection string from TIMEDB_CH_URL (also picked up from a .env file).

2. Usage Example

import polars as pl
from datetime import datetime, timezone
from timedb import TimeDBClient

td = TimeDBClient()  # reads TIMEDB_CH_URL
td.create()          # creates series_values + run_series tables

# 1. Write a forecast run for series_id=42, issued at 06:00.
kt = datetime(2025, 1, 1, 6, tzinfo=timezone.utc)
df = pl.DataFrame({
    "series_id":  [42] * 24,
    "valid_time": [datetime(2025, 1, 1, h, tzinfo=timezone.utc) for h in range(24)],
    "value":      [100.0 + i * 2 for i in range(24)],
})
td.write(df, retention="medium", knowledge_time=kt)

# 2. A later forecast revision — same valid_time window, higher knowledge_time.
kt2 = datetime(2025, 1, 1, 12, tzinfo=timezone.utc)
td.write(df.with_columns(pl.col("value") + 5), retention="medium", knowledge_time=kt2)

# 3. Latest value per valid_time (the second run wins).
latest = td.read(series_ids=[42])

# 4. Full forecast history — one row per (knowledge_time, valid_time).
history = td.read(series_ids=[42], include_knowledge_time=True)

Required write columns are series_id, valid_time, value. Everything else (change_time, run_id, changed_by, annotation, valid_time_end) is optional and stamped with safe defaults per batch. All timestamp columns must be timezone-aware.


🤝 The Full Stack — TimeDB + EnergyDB

TimeDB stores rows keyed by integer series_id and nothing else. That's enough when you're managing identity in your own application — but for the energy domain, we ship the full stack.

EnergyDB adds, on top of the same ClickHouse store (plus a thin PostgreSQL catalog):

  • 🌳 Typed asset trees: PortfolioSiteWindTurbine / PVArray / Battery, etc. — every asset class from EnergyDataModel.
  • 🔗 Grid edges: Line, transformer, pipe — connect any two nodes, attach their own time series.
  • 🧭 Fluent path scopes: client.get_node("my-portfolio", "Offshore-1", "T01").read(name="power", data_type="actual") resolves to one indexed SQL query.
  • ⚖️ Per-series canonical units: declare MW once; pint converts on every read and write via a unit= kwarg.
  • 🧬 Run/workflow provenance: workflow_id, model_name, run_start_time, etc. attached at write time.
  • 📋 Diffable structural changes: dry_run=True previews every rename, move, delete, or insert as a TreeDiff before you commit.

Use TimeDB for the raw storage primitive. Use EnergyDB for an asset-aware catalog of energy portfolios.


🧪 Try it in Google Colab

Want to try TimeDB without a local setup? Open our Quickstart in Colab — the first cell automatically installs ClickHouse inside the VM.

Open In Colab

Note: Data persists only within the active Colab session. Additional notebooks are available in the examples/ directory.


📚 Documentation & Resources


🤝 Contributing

Contributions are welcome! If you're interested in improving TimeDB, please see our Development Guide for local setup instructions.


Licensed under the Apache-2.0 License.

Find a bug or have a feature request? Open an Issue.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

timedb-0.7.0.tar.gz (25.2 kB view details)

Uploaded Source

Built Distribution

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

timedb-0.7.0-py3-none-any.whl (21.2 kB view details)

Uploaded Python 3

File details

Details for the file timedb-0.7.0.tar.gz.

File metadata

  • Download URL: timedb-0.7.0.tar.gz
  • Upload date:
  • Size: 25.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for timedb-0.7.0.tar.gz
Algorithm Hash digest
SHA256 8697e7ec4548a1cfe01ec5155d32d38d7b1c38800c6c3674753a989ea6a31894
MD5 de789dac69332a938b3dc0372ee32608
BLAKE2b-256 7afd4a54f13dc9173604761b0a92da07e832940b32d98fa9696f6c434be34500

See more details on using hashes here.

Provenance

The following attestation bundles were made for timedb-0.7.0.tar.gz:

Publisher: publish.yml on rebase-energy/timedb

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file timedb-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: timedb-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 21.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for timedb-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 70e7145a3d75d3fcdd7c8326a81a90dd69f00865519651fb70f60d7aee602f73
MD5 15b587a8620b0de1df8d5e329f2064d6
BLAKE2b-256 236701db7fa6c59d9cba90be76acdd3f4a7790a2451cc81b494a3ce3f6c8b24b

See more details on using hashes here.

Provenance

The following attestation bundles were made for timedb-0.7.0-py3-none-any.whl:

Publisher: publish.yml on rebase-energy/timedb

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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