Skip to content

Commit 85debd3

Browse files
authored
feat: Add ability to use datetime objects or time-shift strings in TimestampRange (#2432)
1 parent 29bb729 commit 85debd3

7 files changed

Lines changed: 45 additions & 17 deletions

File tree

cognite/client/_api/simulators/models_revisions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ async def list(
7373
>>> res = client.simulators.models.revisions.list(
7474
... model_external_ids=["model1", "model2"],
7575
... all_versions=True,
76-
... created_time=TimestampRange(min=0, max=1000000),
77-
... last_updated_time=TimestampRange(min=0, max=1000000),
76+
... created_time=TimestampRange(min="1d-ago", max="now"),
77+
... last_updated_time=TimestampRange(min="1d-ago", max="now"),
7878
... sort=PropertySort(order="asc", property="createdTime"),
7979
... limit=10,
8080
... )

cognite/client/_api/simulators/runs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,8 @@ async def list(
197197
Filter runs by time ranges:
198198
>>> from cognite.client.data_classes.shared import TimestampRange
199199
>>> res = client.simulators.runs.list(
200-
... created_time=TimestampRange(min=0, max=1_700_000_000_000),
201-
... simulation_time=TimestampRange(min=0, max=1_700_000_000_000),
200+
... created_time=TimestampRange(min="1d-ago", max="now"),
201+
... simulation_time=TimestampRange(min="1d-ago", max="now"),
202202
... )
203203
"""
204204

cognite/client/_sync_api/simulators/models_revisions.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""
22
===============================================================================
3-
143e2ea035bde172593740ba9733e0e2
3+
03b4ddd2ad52415dca0fe62f12b4a3c1
44
This file is auto-generated from the Async API modules, - do not edit manually!
55
===============================================================================
66
"""
@@ -72,8 +72,8 @@ def list(
7272
>>> res = client.simulators.models.revisions.list(
7373
... model_external_ids=["model1", "model2"],
7474
... all_versions=True,
75-
... created_time=TimestampRange(min=0, max=1000000),
76-
... last_updated_time=TimestampRange(min=0, max=1000000),
75+
... created_time=TimestampRange(min="1d-ago", max="now"),
76+
... last_updated_time=TimestampRange(min="1d-ago", max="now"),
7777
... sort=PropertySort(order="asc", property="createdTime"),
7878
... limit=10,
7979
... )

cognite/client/_sync_api/simulators/runs.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""
22
===============================================================================
3-
183a4d1e3ee0ff2c01d10dadfbdda9a0
3+
c2ccaaf731fd07a67787a512a5a9acd2
44
This file is auto-generated from the Async API modules, - do not edit manually!
55
===============================================================================
66
"""
@@ -185,8 +185,8 @@ def list(
185185
Filter runs by time ranges:
186186
>>> from cognite.client.data_classes.shared import TimestampRange
187187
>>> res = client.simulators.runs.list(
188-
... created_time=TimestampRange(min=0, max=1_700_000_000_000),
189-
... simulation_time=TimestampRange(min=0, max=1_700_000_000_000),
188+
... created_time=TimestampRange(min="1d-ago", max="now"),
189+
... simulation_time=TimestampRange(min="1d-ago", max="now"),
190190
... )
191191
"""
192192
return run_sync(

cognite/client/data_classes/shared.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,29 @@
11
from __future__ import annotations
22

33
from collections.abc import Collection, Sequence
4+
from datetime import datetime
45
from typing import Any, Literal
56

67
from typing_extensions import Self
78

89
from cognite.client.data_classes._base import CogniteFilter, CogniteResource, UnknownCogniteResource
10+
from cognite.client.utils._time import timestamp_to_ms
911

1012

1113
class TimestampRange(CogniteResource):
1214
"""Range between two timestamps.
1315
1416
Args:
15-
max (int | None): The number of milliseconds since 00:00:00 Thursday, 1 January 1970, Coordinated Universal Time (UTC), minus leap seconds.
16-
min (int | None): The number of milliseconds since 00:00:00 Thursday, 1 January 1970, Coordinated Universal Time (UTC), minus leap seconds.
17+
max (int | float | str | datetime | None): The number of milliseconds since 00:00:00 Thursday, 1 January 1970, Coordinated Universal Time (UTC), minus leap seconds, a string in time-shift format or a datetime object.
18+
min (int | float | str | datetime | None): The number of milliseconds since 00:00:00 Thursday, 1 January 1970, Coordinated Universal Time (UTC), minus leap seconds, a string in time-shift format or a datetime object.
1719
**_ (Any): No description.
1820
"""
1921

20-
def __init__(self, max: int | None = None, min: int | None = None, **_: Any) -> None:
21-
self.max = max
22-
self.min = min
22+
def __init__(
23+
self, max: int | float | str | datetime | None = None, min: int | float | str | datetime | None = None, **_: Any
24+
) -> None:
25+
self.max = timestamp_to_ms(max) if max is not None else None
26+
self.min = timestamp_to_ms(min) if min is not None else None
2327

2428
@classmethod
2529
def _load(cls, resource: dict[str, Any]) -> Self:

tests/tests_unit/test_api/test_data_sets.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import re
4+
from datetime import datetime, timezone
45
from typing import TYPE_CHECKING, Any
56

67
import pytest
@@ -65,8 +66,11 @@ def test_retrieve_multiple(
6566
assert isinstance(res, DataSetList)
6667
assert [example_data_set] == res.dump(camel_case=True)
6768

68-
def test_list_with_timestamp_range(self, cognite_client: CogniteClient, mock_ds_response: HTTPXMock) -> None:
69-
cognite_client.data_sets.list(created_time=TimestampRange(min=20))
69+
@pytest.mark.parametrize("min_time", [20, datetime.fromtimestamp(20 / 1000, timezone.utc)])
70+
def test_list_with_timestamp_range(
71+
self, cognite_client: CogniteClient, mock_ds_response: HTTPXMock, min_time: int | datetime
72+
) -> None:
73+
cognite_client.data_sets.list(created_time=TimestampRange(min=min_time))
7074
assert 20 == jsgz_load(mock_ds_response.get_requests()[0].content)["filter"]["createdTime"]["min"]
7175
assert "max" not in jsgz_load(mock_ds_response.get_requests()[0].content)["filter"]["createdTime"]
7276

tests/tests_unit/test_data_classes/test_timestamp_range.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
from __future__ import annotations
22

3+
from datetime import datetime, timedelta, timezone
4+
5+
import pytest
6+
37
from cognite.client.data_classes import AggregateResultItem, TimestampRange
48

59

@@ -27,3 +31,19 @@ def test_camels(self) -> None:
2731
ag = AggregateResultItem(child_count=23, depth=1, path=[])
2832
assert 23 == ag.child_count
2933
assert {"childCount": 23, "depth": 1, "path": []} == ag.dump(camel_case=True)
34+
35+
def test_datetime(self) -> None:
36+
min_time = datetime.fromtimestamp(1767222000, timezone.utc) # 2026-01-01 00:00:00 GMT+01
37+
max_time = datetime.fromtimestamp(1767308400, timezone.utc) # 2026-01-02 00:00:00 GMT+01
38+
tsr = TimestampRange(min=min_time, max=max_time)
39+
assert tsr.min == 1767222000000
40+
assert tsr.max == 1767308400000
41+
assert {"min": 1767222000000, "max": 1767308400000} == tsr.dump()
42+
43+
def test_time_shift_string(self) -> None:
44+
now_time = int(datetime.now(timezone.utc).timestamp() * 1000)
45+
day_ago_time = now_time - timedelta(days=1) // timedelta(milliseconds=1)
46+
tsr = TimestampRange(min="1d-ago", max="now")
47+
# NOTE: Using approx because of the small time difference between calls
48+
assert tsr.min == pytest.approx(day_ago_time, 100)
49+
assert tsr.max == pytest.approx(now_time, 100)

0 commit comments

Comments
 (0)