49
49
from openeogeotrellis .constants import EVAL_ENV_KEY
50
50
from openeogeotrellis .geopysparkcubemetadata import GeopysparkCubeMetadata
51
51
from openeogeotrellis .geopysparkdatacube import GeopysparkDataCube
52
+ from openeogeotrellis .util .datetime import to_datetime_utc_unless_none
52
53
from openeogeotrellis .utils import normalize_temporal_extent , get_jvm , to_projected_polygons , map_optional , unzip
53
54
from openeogeotrellis .integrations .stac import ResilientStacIO
54
55
@@ -93,7 +94,6 @@ def load_stac(
93
94
to_date = (dt .datetime .combine (until_date , dt .time .max , until_date .tzinfo ) if from_date == until_date
94
95
else until_date - dt .timedelta (milliseconds = 1 ))
95
96
96
- # TODO: move date preparation to __init__ of _SpatioTemporalExtent
97
97
spatiotemporal_extent = _SpatioTemporalExtent (bbox = requested_bbox , from_date = from_date , to_date = to_date )
98
98
99
99
def get_pixel_value_offset (itm : pystac .Item , asst : pystac .Asset ) -> float :
@@ -712,44 +712,26 @@ def intersects_temporally(interval) -> bool:
712
712
713
713
class _TemporalExtent :
714
714
"""
715
- Helper to represent a temporal extent with a from_date and to_date
715
+ Helper to represent a load_collection/load_stac-style temporal extent
716
+ with a from_date (inclusive) and to_date (exclusive)
716
717
and calculate intersection with STAC entities
717
- (nominal datetime or start_datetime+end_datetime).
718
- """
718
+ based on nominal datetime or start_datetime+end_datetime
719
719
720
+ refs:
721
+ - https://github.com/radiantearth/stac-spec/blob/master/item-spec/item-spec.md#datetime
722
+ - https://github.com/radiantearth/stac-spec/blob/master/commons/common-metadata.md#date-and-time-range
723
+ """
720
724
# TODO: move this to a more generic location for better reuse
725
+
721
726
__slots__ = ("from_date" , "to_date" )
722
727
723
728
def __init__ (
724
729
self ,
725
730
from_date : Union [str , datetime .datetime , datetime .date , None ],
726
731
to_date : Union [str , datetime .datetime , datetime .date , None ],
727
732
):
728
- self .from_date : Union [datetime .datetime , None ] = self ._to_datetime_utc_unless_none (from_date )
729
- self .to_date : Union [datetime .datetime , None ] = self ._to_datetime_utc_unless_none (to_date )
730
-
731
- @staticmethod
732
- def _to_datetime_utc (d : Union [str , datetime .datetime , datetime .date ]) -> datetime .datetime :
733
- """Parse/convert to datetime in UTC."""
734
- if isinstance (d , str ):
735
- d = dateutil .parser .parse (d )
736
- elif isinstance (d , datetime .datetime ):
737
- pass
738
- elif isinstance (d , datetime .date ):
739
- d = datetime .datetime .combine (d , datetime .time .min )
740
- else :
741
- raise ValueError ("Expected str/datetime, but got {type(d)}" )
742
- if d .tzinfo is None :
743
- d = d .replace (tzinfo = dt .timezone .utc )
744
- else :
745
- d = d .astimezone (dt .timezone .utc )
746
- return d
747
-
748
- @classmethod
749
- def _to_datetime_utc_unless_none (
750
- cls , d : Union [str , datetime .datetime , datetime .date , None ]
751
- ) -> Union [datetime .datetime , None ]:
752
- return None if d is None else cls ._to_datetime_utc (d )
733
+ self .from_date : Union [datetime .datetime , None ] = to_datetime_utc_unless_none (from_date )
734
+ self .to_date : Union [datetime .datetime , None ] = to_datetime_utc_unless_none (to_date )
753
735
754
736
def intersects (
755
737
self ,
@@ -764,9 +746,9 @@ def intersects(
764
746
:param start_datetime: start of the interval (e.g. "start_datetime" property of a STAC Item)
765
747
:param end_datetime: end of the interval (e.g. "end_datetime" property of a STAC Item)
766
748
"""
767
- start_datetime = self . _to_datetime_utc_unless_none (start_datetime )
768
- end_datetime = self . _to_datetime_utc_unless_none (end_datetime )
769
- nominal = self . _to_datetime_utc_unless_none (nominal )
749
+ start_datetime = to_datetime_utc_unless_none (start_datetime )
750
+ end_datetime = to_datetime_utc_unless_none (end_datetime )
751
+ nominal = to_datetime_utc_unless_none (nominal )
770
752
771
753
# If available, start+end are preferred (cleanly defined interval)
772
754
# fall back on nominal otherwise
@@ -787,7 +769,6 @@ class _SpatialExtent:
787
769
Helper to represent a spatial extent with a bounding box
788
770
and calculate intersection with STAC entities (e.g. bbox of a STAC Item).
789
771
"""
790
-
791
772
# TODO: move this to a more generic location for better reuse
792
773
793
774
__slots__ = ("bbox" , "_bbox_lonlat_shape" )
@@ -810,8 +791,8 @@ def __init__(
810
791
self ,
811
792
* ,
812
793
bbox : Union [BoundingBox , None ],
813
- from_date : Union [str , datetime .datetime , None ],
814
- to_date : Union [str , datetime .datetime , None ],
794
+ from_date : Union [str , datetime .datetime , datetime . date , None ],
795
+ to_date : Union [str , datetime .datetime , datetime . date , None ],
815
796
):
816
797
self ._spatial_extent = _SpatialExtent (bbox = bbox )
817
798
self ._temporal_extent = _TemporalExtent (from_date = from_date , to_date = to_date )
0 commit comments