Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Date processes #275

Merged
merged 9 commits into from
Sep 11, 2024
126 changes: 126 additions & 0 deletions openeo_processes_dask/process_implementations/dates.py
Original file line number Diff line number Diff line change
@@ -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))

Check warning on line 24 in openeo_processes_dask/process_implementations/dates.py

View check run for this annotation

Codecov / codecov/patch

openeo_processes_dask/process_implementations/dates.py#L24

Added line #L24 was not covered by tests
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(

Check warning on line 45 in openeo_processes_dask/process_implementations/dates.py

View check run for this annotation

Codecov / codecov/patch

openeo_processes_dask/process_implementations/dates.py#L45

Added line #L45 was not covered by tests
(
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]

Check warning on line 96 in openeo_processes_dask/process_implementations/dates.py

View check run for this annotation

Codecov / codecov/patch

openeo_processes_dask/process_implementations/dates.py#L96

Added line #L96 was not covered by tests
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}"

Check warning on line 114 in openeo_processes_dask/process_implementations/dates.py

View check run for this annotation

Codecov / codecov/patch

openeo_processes_dask/process_implementations/dates.py#L114

Added line #L114 was not covered by tests
new_daytime_numpy = np.datetime64(new_daytime)
return new_daytime

date = datetime_from_str(date)
return str(date_M + np.timedelta64(value, unit))

Check warning on line 119 in openeo_processes_dask/process_implementations/dates.py

View check run for this annotation

Codecov / codecov/patch

openeo_processes_dask/process_implementations/dates.py#L118-L119

Added lines #L118 - L119 were not covered by tests

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
50 changes: 50 additions & 0 deletions tests/test_dates.py
Original file line number Diff line number Diff line change
@@ -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"
Loading