Skip to content

Commit 6b86f49

Browse files
authored
Merge pull request #451 from vincentsarago/vincents/allow-datetime-object-for-temporal-queries
allow datetime object to be provided for temporal queries
2 parents e187ae0 + c1f62ce commit 6b86f49

File tree

3 files changed

+71
-21
lines changed

3 files changed

+71
-21
lines changed

earthaccess/search.py

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import datetime as dt
22
from inspect import getmembers, ismethod
3-
from typing import Any, Dict, List, Optional, Tuple, Type
3+
from typing import Any, Dict, List, Optional, Tuple, Type, Union
44

55
import dateutil.parser as parser # type: ignore
66
from cmr import CollectionQuery, GranuleQuery # type: ignore
@@ -312,31 +312,36 @@ def get(self, limit: int = 2000) -> list:
312312
return results
313313

314314
def temporal(
315-
self, date_from: str, date_to: str, exclude_boundary: bool = False
315+
self,
316+
date_from: Optional[Union[str, dt.datetime]] = None,
317+
date_to: Optional[Union[str, dt.datetime]] = None,
318+
exclude_boundary: bool = False,
316319
) -> Type[CollectionQuery]:
317320
"""Filter by an open or closed date range. Dates can be provided as datetime objects
318321
or ISO 8601 formatted strings. Multiple ranges can be provided by successive calls
319322
to this method before calling execute().
320323
321324
Parameters:
322-
date_from: earliest date of temporal range
323-
date_to: latest date of temporal range
324-
exclude_boundary: whether to exclude the date_from/to in the matched range
325+
date_from (String or Datetime object): earliest date of temporal range
326+
date_to (String or Datetime object): latest date of temporal range
327+
exclude_boundary (Boolean): whether or not to exclude the date_from/to in the matched range.
325328
"""
326329
DEFAULT = dt.datetime(1979, 1, 1)
327-
if date_from is not None:
330+
if date_from is not None and not isinstance(date_from, dt.datetime):
328331
try:
329-
parsed_from = parser.parse(date_from, default=DEFAULT).isoformat() + "Z"
332+
date_from = parser.parse(date_from, default=DEFAULT).isoformat() + "Z"
330333
except Exception:
331334
print("The provided start date was not recognized")
332-
parsed_from = ""
333-
if date_to is not None:
335+
date_from = ""
336+
337+
if date_to is not None and not isinstance(date_to, dt.datetime):
334338
try:
335-
parsed_to = parser.parse(date_to, default=DEFAULT).isoformat() + "Z"
339+
date_to = parser.parse(date_to, default=DEFAULT).isoformat() + "Z"
336340
except Exception:
337341
print("The provided end date was not recognized")
338-
parsed_to = ""
339-
super().temporal(parsed_from, parsed_to, exclude_boundary)
342+
date_to = ""
343+
344+
super().temporal(date_from, date_to, exclude_boundary)
340345
return self
341346

342347

@@ -675,8 +680,8 @@ def debug(self, debug: bool = True) -> Type[GranuleQuery]:
675680

676681
def temporal(
677682
self,
678-
date_from: Optional[str] = None,
679-
date_to: Optional[str] = None,
683+
date_from: Optional[Union[str, dt.datetime]] = None,
684+
date_to: Optional[Union[str, dt.datetime]] = None,
680685
exclude_boundary: bool = False,
681686
) -> Type[GranuleQuery]:
682687
"""Filter by an open or closed date range.
@@ -689,19 +694,21 @@ def temporal(
689694
exclude_boundary: whether to exclude the date_from/to in the matched range
690695
"""
691696
DEFAULT = dt.datetime(1979, 1, 1)
692-
if date_from is not None:
697+
if date_from is not None and not isinstance(date_from, dt.datetime):
693698
try:
694-
parsed_from = parser.parse(date_from, default=DEFAULT).isoformat() + "Z"
699+
date_from = parser.parse(date_from, default=DEFAULT).isoformat() + "Z"
695700
except Exception:
696701
print("The provided start date was not recognized")
697-
parsed_from = ""
698-
if date_to is not None:
702+
date_from = ""
703+
704+
if date_to is not None and not isinstance(date_to, dt.datetime):
699705
try:
700-
parsed_to = parser.parse(date_to, default=DEFAULT).isoformat() + "Z"
706+
date_to = parser.parse(date_to, default=DEFAULT).isoformat() + "Z"
701707
except Exception:
702708
print("The provided end date was not recognized")
703-
parsed_to = ""
704-
super().temporal(parsed_from, parsed_to, exclude_boundary)
709+
date_to = ""
710+
711+
super().temporal(date_from, date_to, exclude_boundary)
705712
return self
706713

707714
def version(self, version: str = "") -> Type[GranuleQuery]:

tests/unit/test_collection_queries.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,26 @@
11
# package imports
2+
import datetime as dt
3+
4+
import pytest
25
from earthaccess.search import DataCollections
36

7+
valid_single_dates = [
8+
("2001-12-12", "2001-12-21", "2001-12-12T00:00:00Z,2001-12-21T00:00:00Z"),
9+
("2021-02-01", "", "2021-02-01T00:00:00Z,"),
10+
("1999-02-01 06:00", "2009-01-01", "1999-02-01T06:00:00Z,2009-01-01T00:00:00Z"),
11+
(
12+
dt.datetime(2021, 2, 1),
13+
dt.datetime(2021, 2, 2),
14+
"2021-02-01T00:00:00Z,2021-02-02T00:00:00Z",
15+
),
16+
]
17+
18+
invalid_single_dates = [
19+
("2001-12-45", "2001-12-21", None),
20+
("2021w1", "", None),
21+
("2999-02-01", "2009-01-01", None),
22+
]
23+
424

525
def test_query_can_find_cloud_provider():
626
query = DataCollections().daac("PODAAC").cloud_hosted(True)
@@ -18,3 +38,19 @@ def test_querybuilder_can_handle_doi():
1838
assert query.params["doi"] == doi
1939
query = DataCollections().cloud_hosted(True).daac("PODAAC").doi(doi)
2040
assert query.params["doi"] == doi
41+
42+
43+
@pytest.mark.parametrize("start,end,expected", valid_single_dates)
44+
def test_query_can_parse_single_dates(start, end, expected):
45+
query = DataCollections().temporal(start, end)
46+
assert query.params["temporal"][0] == expected
47+
48+
49+
@pytest.mark.parametrize("start,end,expected", invalid_single_dates)
50+
def test_query_can_handle_invalid_dates(start, end, expected):
51+
query = DataCollections()
52+
try:
53+
query = query.temporal(start, end)
54+
except Exception as e:
55+
assert isinstance(e, ValueError)
56+
assert "temporal" not in query.params

tests/unit/test_granule_queries.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
# package imports
2+
import datetime as dt
3+
24
import pytest
35
from earthaccess.search import DataGranules
46

57
valid_single_dates = [
68
("2001-12-12", "2001-12-21", "2001-12-12T00:00:00Z,2001-12-21T00:00:00Z"),
79
("2021-02-01", "", "2021-02-01T00:00:00Z,"),
810
("1999-02-01 06:00", "2009-01-01", "1999-02-01T06:00:00Z,2009-01-01T00:00:00Z"),
11+
(
12+
dt.datetime(2021, 2, 1),
13+
dt.datetime(2021, 2, 2),
14+
"2021-02-01T00:00:00Z,2021-02-02T00:00:00Z",
15+
),
916
]
1017

1118
invalid_single_dates = [

0 commit comments

Comments
 (0)