TimeSeries Operations

A TimeSeries is not just a data container — it supports arithmetic, comparisons, and transformations. This notebook demonstrates how to manipulate time series data without dropping down to raw arrays.

[1]:
from datetime import datetime, timedelta, timezone

import timedatamodel as tdm

base = datetime(2024, 1, 15, tzinfo=timezone.utc)
timestamps = [base + timedelta(hours=i) for i in range(24)]

generation = tdm.TimeSeries(
    tdm.Frequency.PT1H,
    timestamps=timestamps,
    values=[
        120.0, 115.0, 108.0, 105.0, 102.0, 100.0,
        110.0, 135.0, 160.0, 175.0, 180.0, 178.0,
        172.0, 170.0, 168.0, 165.0, 175.0, 190.0,
        200.0, 195.0, 180.0, 165.0, 145.0, 130.0,
    ],
    name="generation",
    unit="MW",
    data_type=tdm.DataType.MEASUREMENT,
)

consumption = tdm.TimeSeries(
    tdm.Frequency.PT1H,
    timestamps=timestamps,
    values=[
        90.0, 85.0, 80.0, 78.0, 77.0, 80.0,
        95.0, 120.0, 145.0, 155.0, 160.0, 158.0,
        155.0, 150.0, 148.0, 150.0, 160.0, 170.0,
        165.0, 155.0, 140.0, 120.0, 105.0, 95.0,
    ],
    name="consumption",
    unit="MW",
    data_type=tdm.DataType.MEASUREMENT,
)
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[1], line 3
      1 from datetime import datetime, timedelta, timezone
----> 3 import timedatamodel as tdm
      5 base = datetime(2024, 1, 15, tzinfo=timezone.utc)
      6 timestamps = [base + timedelta(hours=i) for i in range(24)]

ModuleNotFoundError: No module named 'timedatamodel'

Scalar arithmetic

Scale, offset, negate, or round values with natural Python operators. The result is a new TimeSeries with metadata preserved.

[2]:
generation_kw = generation * 1000
generation_kw
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[2], line 1
----> 1 generation_kw = generation * 1000
      2 generation_kw

NameError: name 'generation' is not defined
[3]:
offset = generation + 10.0
negated = -generation
rounded = round(generation / 3, 1)

print(f"Original first value:  {generation[0].value}")
print(f"+ 10:                  {offset[0].value}")
print(f"Negated:               {negated[0].value}")
print(f"Divided by 3, rounded: {rounded[0].value}")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[3], line 1
----> 1 offset = generation + 10.0
      2 negated = -generation
      3 rounded = round(generation / 3, 1)

NameError: name 'generation' is not defined

Element-wise arithmetic between two TimeSeries

Subtract consumption from generation to get net surplus. Both series must share the same timestamps.

[4]:
surplus = generation - consumption
surplus
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[4], line 1
----> 1 surplus = generation - consumption
      2 surplus

NameError: name 'generation' is not defined

Comparison operators

Comparisons return a TimeSeries of 1.0 / 0.0 (or NaN for missing). Useful for flagging thresholds.

[5]:
high_gen = generation > 170.0
high_gen
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[5], line 1
----> 1 high_gen = generation > 170.0
      2 high_gen

NameError: name 'generation' is not defined
[6]:
gen_exceeds_cons = generation > consumption
gen_exceeds_cons
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[6], line 1
----> 1 gen_exceeds_cons = generation > consumption
      2 gen_exceeds_cons

NameError: name 'generation' is not defined

abs() — absolute values

Handy when you have signed deviations or residuals.

[7]:
deviation = generation - consumption
abs_deviation = abs(deviation)
abs_deviation.head(6)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[7], line 1
----> 1 deviation = generation - consumption
      2 abs_deviation = abs(deviation)
      3 abs_deviation.head(6)

NameError: name 'generation' is not defined

head(), tail(), and copy()

Quickly preview or duplicate a series.

[8]:
print("First 3:")
for dp in generation.head(3):
    print(f"  {dp.timestamp:%H:%M}  {dp.value:.1f} MW")

print("\nLast 3:")
for dp in generation.tail(3):
    print(f"  {dp.timestamp:%H:%M}  {dp.value:.1f} MW")
First 3:
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[8], line 2
      1 print("First 3:")
----> 2 for dp in generation.head(3):
      3     print(f"  {dp.timestamp:%H:%M}  {dp.value:.1f} MW")
      5 print("\nLast 3:")

NameError: name 'generation' is not defined
[ ]:

[ ]:

Handling missing values in arithmetic

Missing values (None) propagate through operations as NaN, just like numpy.

[9]:
ts_with_gaps = tdm.TimeSeries(
    tdm.Frequency.PT1H,
    timestamps=timestamps[:6],
    values=[100.0, None, 110.0, None, 105.0, 108.0],
    name="sensor",
    unit="MW",
)

doubled = ts_with_gaps * 2
for dp in doubled:
    print(f"{dp.timestamp:%H:%M}  {dp.value}")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[9], line 1
----> 1 ts_with_gaps = tdm.TimeSeries(
      2     tdm.Frequency.PT1H,
      3     timestamps=timestamps[:6],
      4     values=[100.0, None, 110.0, None, 105.0, 108.0],
      5     name="sensor",
      6     unit="MW",
      7 )
      9 doubled = ts_with_gaps * 2
     10 for dp in doubled:

NameError: name 'tdm' is not defined

Summary

You can treat TimeSeries like a numeric object:

  • Scalar ops: +, -, *, /, -ts, abs(), round()

  • Element-wise ops between aligned series

  • Comparisons: >, >=, <, <=, ==, !=

  • Missing values propagate cleanly

Next up: nb_05 introduces multivariate time series with TimeSeriesTable.