# How to Query Temporal Graphs Using TemporalGraphQuery.querytimerange() in Semantica

> Learn to query temporal graphs using Semantica's TemporalGraphQuery.querytimerange() method. Filter edges by validity intervals and run queries efficiently.

- Repository: [Semantica /semantica](https://github.com/semantica-agi/semantica)
- Tags: how-to-guide
- Published: 2026-08-17

---

**Use `TemporalGraphQuery.querytimerange()` with the `at`, `after`, `before`, `start`, or `end` parameters to filter bi-temporal knowledge graph edges by their validity intervals, then execute with `.run()` or `.to_pandas()`.**

The `semantica-agi/semantica` repository implements bi-temporal knowledge graphs where every edge carries `valid_from` and `valid_until` timestamps. To query temporal graphs and retrieve relationships active during specific time windows, developers use the `TemporalGraphQuery` class and its `querytimerange()` method, which abstracts Cypher predicate generation for temporal filtering.

## TemporalGraphQuery.querytimerange() Method Overview

In [`semantica/kg/query.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/kg/query.py), the `TemporalGraphQuery` class provides `querytimerange()` as the primary API for temporal filtering. The method accepts ISO-8601 timestamps and translates them into database predicates that check edge validity intervals. All parameters are optional and mutually exclusive in logical groups.

### Exact Point-in-Time Queries

Use the `at` parameter to retrieve edges that were valid at a specific instant. This returns items where `valid_from <= timestamp < valid_until`, or where the timestamp falls within the stored validity interval.

```python
from semantica.kg.query import TemporalGraphQuery

tgq = TemporalGraphQuery()
results = (
    tgq.filter_by_relation("EMPLOYED_BY")
       .querytimerange(at="2023-03-15T00:00:00Z")
       .run()
)

```

### Open-Ended Range Queries

Use `after` (inclusive lower bound) or `before` (exclusive upper bound) to query edges valid after or before a specific time. These parameters support unbounded temporal searches without requiring an explicit end date.

```python
tgq = TemporalGraphQuery()
df = (
    tgq.filter_by_property("status", "ACTIVE")
       .querytimerange(after="2022-06-01")
       .run()
)

```

### Closed Range Queries

Combine `start` (inclusive) and `end` (exclusive) to define a explicit time window. The method returns edges whose validity intervals intersect with the supplied window, meaning they were active for at least part of the specified period.

```python
tgq = TemporalGraphQuery()
df = (
    tgq.querytimerange(start="2020-01-01", end="2021-12-31")
       .to_pandas()
)

```

## Internal Query Logic

According to [`semantica/kg/query.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/kg/query.py), `querytimerange()` constructs a Cypher `WHERE` clause resembling the following pseudo-code:

```cypher
WHERE
  (e.valid_from IS NULL OR e.valid_from <= $upper)
  AND (e.valid_until IS NULL OR e.valid_until >= $lower)

```

Here, `$lower` and `$upper` are derived from the supplied temporal arguments. If the graph stores point-in-time snapshots with only a single timestamp per edge, the logic collapses to simple equality or inequality filters. The optional `timezone` parameter interprets naive timestamps according to the specified tz name before query execution.

## Step-by-Step Implementation Workflow

1. **Instantiate `TemporalGraphQuery`** – Optionally inject a custom graph client from [`semantica/kg/methods.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/kg/methods.py) to target specific database backends.

2. **Apply Domain Filters** – Chain methods like `filter_by_relation()` or `filter_by_property()` to narrow the search space before applying temporal constraints.

3. **Invoke `querytimerange()`** – Pass temporal boundaries using `at`, `after`/`before`, or `start`/`end` depending on your query requirements.

4. **Execute and Retrieve Results** – Call `.run()` to return raw results or `.to_pandas()` to obtain a DataFrame for analysis.

## Practical Code Examples

The following examples demonstrate common patterns for querying temporal graphs in Semantica:

**Example 1: Retrieve relationships active on a specific date**

```python
from semantica.kg.query import TemporalGraphQuery

tgq = TemporalGraphQuery()
results = (
    tgq.filter_by_relation("EMPLOYED_BY")
       .querytimerange(at="2023-03-15T00:00:00Z")
       .run()
)
print(results)

```

**Example 2: Find edges active within a historical window**

```python
tgq = TemporalGraphQuery()
df = (
    tgq.querytimerange(start="2020-01-01", end="2021-12-31")
       .to_pandas()
)
print(df.head())

```

**Example 3: Combine temporal constraints with attribute filters**

```python
tgq = TemporalGraphQuery()
df = (
    tgq.filter_by_property("status", "ACTIVE")
       .querytimerange(after="2022-06-01")
       .run()
)

```

## Key Source Files and References

- **[`semantica/kg/query.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/kg/query.py)** – Contains the `TemporalGraphQuery` class and `querytimerange()` implementation.
- **[`semantica/kg/methods.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/kg/methods.py)** – Provides utility functions for building and executing graph queries.
- **[`docs/reference/kg.md`](https://github.com/semantica-agi/semantica/blob/main/docs/reference/kg.md)** – Documents the Knowledge-Graph API with temporal query examples.
- **`cookbook/advanced/10_Temporal_Knowledge_Graphs.ipynb`** – Demonstrates practical temporal graph construction and queries.
- **[`semantica/visualization/temporal_visualizer.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/visualization/temporal_visualizer.py)** – Renders query results over time for visual analysis.

## Summary

- **`querytimerange()`** is the primary method for temporal filtering in `TemporalGraphQuery`, implemented in [`semantica/kg/query.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/kg/query.py).
- The method supports **exact point-in-time** (`at`), **open-ended ranges** (`after`, `before`), and **closed intervals** (`start`/`end`).
- Internally, it generates Cypher predicates that check `valid_from` and `valid_until` timestamps against supplied bounds.
- Results can be retrieved via **`.run()`** for raw output or **`.to_pandas()`** for DataFrame analysis.

## Frequently Asked Questions

### What is the difference between the `at` and `start`/`end` parameters in `querytimerange()`?

The `at` parameter queries for edges valid at a single specific instant, checking if the timestamp falls within the edge's validity interval. The `start` and `end` parameters define a duration window, returning any edges that were active for at least part of that range through interval intersection logic.

### How does `querytimerange()` handle edges with null validity timestamps?

The generated Cypher predicate treats null `valid_from` or `valid_until` values as unbounded. An edge with `valid_from IS NULL` is considered to have been valid since the beginning of time, while `valid_until IS NULL` indicates it remains valid indefinitely.

### Can I chain `querytimerange()` with other filters like `filter_by_relation()`?

Yes, `TemporalGraphQuery` supports method chaining. You can combine `filter_by_relation()`, `filter_by_property()`, and `querytimerange()` in any order before calling `.run()` or `.to_pandas()` to execute the final query with all constraints applied.

### What timestamp formats are supported when querying temporal graphs?

The method accepts ISO-8601 formatted strings (e.g., `"2023-05-01T12:00:00Z"`). You may also provide naive timestamps, which will be interpreted according to the optional `timezone` parameter passed to `querytimerange()`.