Skip to main content

⏱️ 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.
  • 🧹 Idempotent Writes: Opt into write(..., skip_unchanged=True) and rows that only duplicate the latest stored value are dropped before insert — writing the same window repeatedly stops bloating storage. Off by default; full provenance kept unless you ask. unchanged_scope="auto" applies a different comparison key per series in one call, so a frame mixing plain actuals with versioned publications dedupes each correctly.
  • 🪶 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.

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.9.0.tar.gz (37.5 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.9.0-py3-none-any.whl (28.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: timedb-0.9.0.tar.gz
  • Upload date:
  • Size: 37.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for timedb-0.9.0.tar.gz
Algorithm Hash digest
SHA256 362b32e2b1a8516890e4faf680fb18dcb7b5aea903447d38832c05b706c672e0
MD5 628738e0778279b2acc49507ffc08d68
BLAKE2b-256 7e7d43b5aae5ad6407e4e1d90e28d47ec3d40ab3d02b1386b10473dbca0b28ee

See more details on using hashes here.

Provenance

The following attestation bundles were made for timedb-0.9.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.9.0-py3-none-any.whl.

File metadata

  • Download URL: timedb-0.9.0-py3-none-any.whl
  • Upload date:
  • Size: 28.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for timedb-0.9.0-py3-none-any.whl
Algorithm Hash digest
SHA256 13fb3d810a80536d8adfe7b4802a3b4a4fb08cafc79fc826b77578b1f23e6127
MD5 61cbe04f19c42c898531d2e04deb97f7
BLAKE2b-256 07473e878e78a2249c84c6b333e9b6e2d81eb490c79ef867a9acc68e2c63e3cf

See more details on using hashes here.

Provenance

The following attestation bundles were made for timedb-0.9.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.

Release history Release notifications | RSS feed

0.11.0

2 files

0.10.0

2 files

This release

0.9.0 This release

2 files

0.8.1

2 files

0.8.0

2 files

0.7.0

2 files

0.6.0

2 files

0.5.0

2 files

0.2.1

2 files

0.2.0

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

1 file

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page