Skip to content

Commit 8fb8a8e

Browse files
author
Phil Varner
authored
Merge pull request #41 from stac-utils/pv/datetime-fixes
rework datetime values
2 parents c5a6564 + 6e4c1f8 commit 8fb8a8e

File tree

4 files changed

+38
-20
lines changed

4 files changed

+38
-20
lines changed

stac_fastapi/elasticsearch/setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"pytest-asyncio",
2727
"pre-commit",
2828
"requests",
29+
"ciso8601",
2930
],
3031
"docs": ["mkdocs", "mkdocs-material", "pdocs"],
3132
"server": ["uvicorn[standard]>=0.12.0,<0.14.0"],
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
"""A few datetime methods."""
2+
from datetime import datetime, timezone
3+
4+
from pystac.utils import datetime_to_str
5+
6+
7+
def now_in_utc() -> datetime:
8+
"""Return a datetime value of now with the UTC timezone applied."""
9+
return datetime.now(timezone.utc)
10+
11+
12+
def now_to_rfc3339_str() -> str:
13+
"""Return an RFC 3339 string representing now."""
14+
return datetime_to_str(now_in_utc())

stac_fastapi/elasticsearch/stac_fastapi/elasticsearch/serializers.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
"""Serializers."""
22
import abc
3-
from datetime import datetime
43
from typing import TypedDict
54

65
import attr
7-
from stac_pydantic.shared import DATETIME_RFC339
86

7+
from stac_fastapi.elasticsearch.datetime_utils import now_to_rfc3339_str
98
from stac_fastapi.types import stac as stac_types
109
from stac_fastapi.types.links import CollectionLinks, ItemLinks, resolve_links
1110

@@ -42,10 +41,10 @@ def stac_to_db(cls, stac_data: TypedDict, base_url: str) -> stac_types.Item:
4241
v = float(v)
4342
wave.update({k: v})
4443

45-
now = datetime.utcnow().strftime(DATETIME_RFC339)
44+
now = now_to_rfc3339_str()
4645
if "created" not in stac_data["properties"]:
47-
stac_data["properties"]["created"] = str(now)
48-
stac_data["properties"]["updated"] = str(now)
46+
stac_data["properties"]["created"] = now
47+
stac_data["properties"]["updated"] = now
4948
return stac_data
5049

5150
@classmethod

stac_fastapi/elasticsearch/tests/resources/test_item.py

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,21 @@
77
from random import randint
88
from urllib.parse import parse_qs, urlparse, urlsplit
99

10+
import ciso8601
1011
import pystac
1112
import pytest
1213
from geojson_pydantic.geometries import Polygon
13-
from stac_pydantic.shared import DATETIME_RFC339
14+
from pystac.utils import datetime_to_str
1415

1516
from stac_fastapi.elasticsearch.core import CoreCrudClient
17+
from stac_fastapi.elasticsearch.datetime_utils import now_to_rfc3339_str
1618
from stac_fastapi.types.core import LandingPageMixin
1719

1820

21+
def rfc3339_str_to_datetime(s: str) -> datetime:
22+
return ciso8601.parse_rfc3339(s)
23+
24+
1925
@pytest.mark.skip(reason="unknown")
2026
def test_create_and_delete_item(app_client, load_test_data):
2127
"""Test creation and deletion of a single item (transactions extension)"""
@@ -275,7 +281,7 @@ def test_pagination(app_client, load_test_data):
275281
def test_item_timestamps(app_client, load_test_data):
276282
"""Test created and updated timestamps (common metadata)"""
277283
test_item = load_test_data("test_item.json")
278-
start_time = datetime.utcnow().strftime(DATETIME_RFC339)
284+
start_time = now_to_rfc3339_str()
279285
time.sleep(1)
280286
# Confirm `created` timestamp
281287
resp = app_client.post(
@@ -285,9 +291,7 @@ def test_item_timestamps(app_client, load_test_data):
285291
created_dt = item["properties"]["created"]
286292
time.sleep(1)
287293
assert resp.status_code == 200
288-
assert (
289-
str(start_time) < created_dt < str(datetime.utcnow().strftime(DATETIME_RFC339))
290-
)
294+
assert start_time < created_dt < now_to_rfc3339_str()
291295

292296
time.sleep(1)
293297
# Confirm `updated` timestamp
@@ -364,13 +368,13 @@ def test_item_search_temporal_query_post(app_client, load_test_data):
364368
)
365369
assert resp.status_code == 200
366370

367-
item_date = datetime.strptime(test_item["properties"]["datetime"], DATETIME_RFC339)
371+
item_date = rfc3339_str_to_datetime(test_item["properties"]["datetime"])
368372
item_date = item_date + timedelta(seconds=1)
369373

370374
params = {
371375
"collections": [test_item["collection"]],
372376
"intersects": test_item["geometry"],
373-
"datetime": f"../{item_date.strftime(DATETIME_RFC339)}",
377+
"datetime": f"../{datetime_to_str(item_date)}",
374378
}
375379
resp = app_client.post("/search", json=params)
376380
resp_json = resp.json()
@@ -391,14 +395,14 @@ def test_item_search_temporal_window_post(app_client, load_test_data):
391395
)
392396
assert resp.status_code == 200
393397

394-
item_date = datetime.strptime(test_item["properties"]["datetime"], DATETIME_RFC339)
398+
item_date = rfc3339_str_to_datetime(test_item["properties"]["datetime"])
395399
item_date_before = item_date - timedelta(seconds=1)
396400
item_date_after = item_date + timedelta(seconds=1)
397401

398402
params = {
399403
"collections": [test_item["collection"]],
400404
"intersects": test_item["geometry"],
401-
"datetime": f"{item_date_before.strftime(DATETIME_RFC339)}/{item_date_after.strftime(DATETIME_RFC339)}",
405+
"datetime": f"{datetime_to_str(item_date_before)}/{datetime_to_str(item_date_after)}",
402406
}
403407
resp = app_client.post("/search", json=params)
404408
resp_json = resp.json()
@@ -438,7 +442,7 @@ def test_item_search_temporal_open_window(app_client, load_test_data):
438442
def test_item_search_sort_post(app_client, load_test_data):
439443
"""Test POST search with sorting (sort extension)"""
440444
first_item = load_test_data("test_item.json")
441-
item_date = datetime.strptime(first_item["properties"]["datetime"], DATETIME_RFC339)
445+
item_date = rfc3339_str_to_datetime(first_item["properties"]["datetime"])
442446
resp = app_client.post(
443447
f"/collections/{first_item['collection']}/items", json=first_item
444448
)
@@ -447,7 +451,7 @@ def test_item_search_sort_post(app_client, load_test_data):
447451
second_item = load_test_data("test_item.json")
448452
second_item["id"] = "another-item"
449453
another_item_date = item_date - timedelta(days=1)
450-
second_item["properties"]["datetime"] = another_item_date.strftime(DATETIME_RFC339)
454+
second_item["properties"]["datetime"] = datetime_to_str(another_item_date)
451455
resp = app_client.post(
452456
f"/collections/{second_item['collection']}/items", json=second_item
453457
)
@@ -542,14 +546,14 @@ def test_item_search_temporal_window_get(app_client, load_test_data):
542546
)
543547
assert resp.status_code == 200
544548

545-
item_date = datetime.strptime(test_item["properties"]["datetime"], DATETIME_RFC339)
549+
item_date = rfc3339_str_to_datetime(test_item["properties"]["datetime"])
546550
item_date_before = item_date - timedelta(seconds=1)
547551
item_date_after = item_date + timedelta(seconds=1)
548552

549553
params = {
550554
"collections": test_item["collection"],
551555
"bbox": ",".join([str(coord) for coord in test_item["bbox"]]),
552-
"datetime": f"{item_date_before.strftime(DATETIME_RFC339)}/{item_date_after.strftime(DATETIME_RFC339)}",
556+
"datetime": f"{datetime_to_str(item_date_before)}/{datetime_to_str(item_date_after)}",
553557
}
554558
resp = app_client.get("/search", params=params)
555559
resp_json = resp.json()
@@ -565,7 +569,7 @@ def test_item_search_temporal_window_get(app_client, load_test_data):
565569
def test_item_search_sort_get(app_client, load_test_data):
566570
"""Test GET search with sorting (sort extension)"""
567571
first_item = load_test_data("test_item.json")
568-
item_date = datetime.strptime(first_item["properties"]["datetime"], DATETIME_RFC339)
572+
item_date = rfc3339_str_to_datetime(first_item["properties"]["datetime"])
569573
resp = app_client.post(
570574
f"/collections/{first_item['collection']}/items", json=first_item
571575
)
@@ -574,7 +578,7 @@ def test_item_search_sort_get(app_client, load_test_data):
574578
second_item = load_test_data("test_item.json")
575579
second_item["id"] = "another-item"
576580
another_item_date = item_date - timedelta(days=1)
577-
second_item["properties"]["datetime"] = another_item_date.strftime(DATETIME_RFC339)
581+
second_item["properties"]["datetime"] = datetime_to_str(another_item_date)
578582
resp = app_client.post(
579583
f"/collections/{second_item['collection']}/items", json=second_item
580584
)

0 commit comments

Comments
 (0)