diff --git a/openeo_processes_dask/process_implementations/dates.py b/openeo_processes_dask/process_implementations/dates.py new file mode 100644 index 00000000..59dd76f5 --- /dev/null +++ b/openeo_processes_dask/process_implementations/dates.py @@ -0,0 +1,126 @@ +from typing import Optional + +import numpy as np + +__all__ = [ + "date_between", + "date_difference", + "date_shift", +] + + +def datetime_from_str(date: str): + daytime = np.datetime64(date) + return daytime + + +def date_between( + x: str, min: str, max: str, exclude_max: bool = False +) -> Optional[bool]: + x = datetime_from_str(x) + min = datetime_from_str(min) + max = datetime_from_str(max) + if exclude_max: + return bool((x >= min) and (x < max)) + else: + return bool((x >= min) and (x <= max)) + + +def date_difference(date1: str, date2: str, unit: Optional[str] = "second") -> float: + date1 = datetime_from_str(date1) + date2 = datetime_from_str(date2) + units = { + "millisecond": 1, + "second": 1000, + "minute": 1000 * 60, + "hour": 1000 * 60 * 60, + "day": 1000 * 60 * 60 * 24, + "week": 1000 * 60 * 60 * 24 * 7, + "month": "M", + "year": "Y", + } + if unit in units: + unit = units[unit] + if unit in ["M", "Y"]: + return float( + ( + date2.astype(f"datetime64[{unit}]") + - date1.astype(f"datetime64[{unit}]") + ).astype(float) + ) + else: + # we do this, so the examples are fulfilled: + # date_difference(date1 = "2020-01-01T00:00:00.0Z", date2 = "2020-01-01T00:00:15.5Z") -> 15.5 + return ( + float( + ( + date2.astype(f"datetime64[ms]") - date1.astype(f"datetime64[ms]") + ).astype(float) + ) + / unit + ) + + +def date_shift(date: str, value: int, unit: str) -> str: + if date.endswith("Z"): + end = "Z" + elif "+" in date: + end = "+" + date.split("+")[-1] + date = date.split("+")[0] + else: + end = "" + units = { + "millisecond": "ms", + "second": "s", + "minute": "m", + "hour": "h", + "day": "D", + "week": "W", + "month": "M", + "year": "Y", + } + if unit in units: + unit = units[unit] + if unit in ["M", "Y"]: + if len(date) > 7: + date_M = np.datetime64(date, "M") + day = ( + int( + (np.datetime64(date, "D") - date_M.astype("datetime64[D]")).astype( + int + ) + ) + + 1 + ) + if " " in date: + time = "T" + date.split(" ")[-1] + elif "T" in date: + time = "T" + date.split("T")[-1] + else: + time = "" + new_date = str(date_M + np.timedelta64(value, unit)) + if day in [29, 30, 31]: + for i in range(3): + try: + new_daytime = f"{new_date}-{day-i}" + new_daytime_numpy = np.datetime64(new_daytime) + result = f"{new_daytime}{time}" + return result + except: + pass + elif int(day) < 10: + new_daytime = f"{new_date}-0{day}{time}" + else: + new_daytime = f"{new_date}-{day}T{time}" + new_daytime_numpy = np.datetime64(new_daytime) + return new_daytime + + date = datetime_from_str(date) + return str(date_M + np.timedelta64(value, unit)) + + date = datetime_from_str(date) + if unit in ["ms"]: + result = str((date + np.timedelta64(value, unit)).astype(f"datetime64[{unit}]")) + else: + result = str((date + np.timedelta64(value, unit)).astype(date.dtype)) + return result + end diff --git a/tests/test_dates.py b/tests/test_dates.py new file mode 100644 index 00000000..41ec0e1f --- /dev/null +++ b/tests/test_dates.py @@ -0,0 +1,50 @@ +from openeo_processes_dask.process_implementations.dates import ( + date_between, + date_difference, + date_shift, +) + + +def test_date_between(): + assert not date_between(x="2020-01-01", min="2021-01-01", max="2022-01-01") + + +def test_date_difference(): + assert ( + date_difference(date1="2020-01-01T00:00:00.0Z", date2="2020-01-01T00:00:15.5Z") + == 15.5 + ) + assert ( + date_difference(date1="2020-01-01T00:00:00Z", date2="2020-01-01T01:00:00+01:00") + == 0 + ) + assert date_difference(date1="2020-01-02", date2="2020-01-01") == -86400 + assert date_difference(date1="2020-01-02", date2="2020-01-01", unit="day") == -1 + + +def test_date_shift(): + month_shift = date_shift(date="2020-02-01T17:22:45Z", value=6, unit="month") + assert month_shift == "2020-08-01T17:22:45Z" + + day_shift = date_shift(date="2021-03-31T00:00:00+02:00", value=-7, unit="day") + assert day_shift == "2021-03-24T00:00:00+02:00" + + year_shift = date_shift(date="2020-02-29T17:22:45Z", value=1, unit="year") + assert year_shift == "2021-02-28T17:22:45Z" + + month_shift = date_shift(date="2020-01-31", value=1, unit="month") + assert month_shift == "2020-02-29" + + second_shift = date_shift(date="2016-12-31T23:59:59Z", value=1, unit="second") + assert second_shift == "2017-01-01T00:00:00Z" + + millisecond_shift = date_shift( + date="2018-12-31T17:22:45Z", value=1150, unit="millisecond" + ) + assert millisecond_shift == "2018-12-31T17:22:46.150Z" + + hour_shift = date_shift(date="2018-01-01", value=25, unit="hour") + assert hour_shift == "2018-01-02" + + hour_shift = date_shift(date="2018-01-01", value=-1, unit="hour") + assert hour_shift == "2017-12-31"