Skip to content

Commit aefdce7

Browse files
Yuri ZmytrakovYuri Zmytrakov
authored andcommitted
fix: round milliseconds instead of truncating
1 parent 0517b4b commit aefdce7

File tree

2 files changed

+56
-1
lines changed

2 files changed

+56
-1
lines changed

stac_fastapi/core/stac_fastapi/core/datetime_utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ def normalize(dt):
2323
return ".."
2424
dt_obj = rfc3339_str_to_datetime(dt)
2525
dt_utc = dt_obj.astimezone(timezone.utc)
26-
return dt_utc.isoformat(timespec="milliseconds").replace("+00:00", "Z")
26+
rounded_dt = dt_utc.replace(microsecond=round(dt_utc.microsecond / 1000) * 1000)
27+
return rounded_dt.isoformat(timespec="milliseconds").replace("+00:00", "Z")
2728

2829
if not isinstance(date_str, str):
2930
return "../.."

stac_fastapi/tests/api/test_api.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1625,3 +1625,57 @@ async def test_use_datetime_false(app_client, load_test_data, txn_client, monkey
16251625

16261626
assert "test-item-datetime-only" not in found_ids
16271627
assert "test-item-start-end-only" in found_ids
1628+
1629+
@pytest.mark.asyncio
1630+
async def test_format_datetime_range_microsecond_rounding(app_client, txn_client, load_test_data):
1631+
"""Test that microseconds are rounded to milliseconds"""
1632+
1633+
test_collection = load_test_data("test_collection.json")
1634+
test_collection_id = "test-collection-microseconds"
1635+
test_collection["id"] = test_collection_id
1636+
await create_collection(txn_client, test_collection)
1637+
1638+
item = load_test_data("test_item.json")
1639+
item["id"] = "test-item-1"
1640+
item["collection"] = test_collection_id
1641+
item["properties"]["datetime"] = "2020-01-01T12:00:00.123Z"
1642+
await create_item(txn_client, item)
1643+
1644+
test_cases = [
1645+
("2020-01-01T12:00:00.123678Z", False),
1646+
("2020-01-01T12:00:00.123499Z", True),
1647+
("2020-01-01T12:00:00.123500Z", False),
1648+
]
1649+
1650+
for datetime_input, should_match in test_cases:
1651+
# Test GET /collections/{id}/items
1652+
resp = await app_client.get(
1653+
f"/collections/{test_collection_id}/items",
1654+
params={"datetime": datetime_input}
1655+
)
1656+
assert resp.status_code == 200
1657+
resp_json = resp.json()
1658+
1659+
if should_match:
1660+
assert len(resp_json["features"]) == 1
1661+
assert resp_json["features"][0]["id"] == "test-item-1"
1662+
else:
1663+
assert len(resp_json["features"]) == 0
1664+
1665+
# Test GET /search
1666+
resp = await app_client.get(
1667+
"/search",
1668+
params={
1669+
"collections": test_collection_id,
1670+
"datetime": datetime_input
1671+
}
1672+
)
1673+
assert resp.status_code == 200
1674+
resp_json = resp.json()
1675+
1676+
if should_match:
1677+
assert len(resp_json["features"]) == 1
1678+
assert resp_json["features"][0]["id"] == "test-item-1"
1679+
else:
1680+
assert len(resp_json["features"]) == 0
1681+

0 commit comments

Comments
 (0)