Idriss Bellil
08/28/2025, 2:21 PMMarvin
08/28/2025, 2:21 PMMarvin
08/28/2025, 2:35 PMdatetime.timedelta
, the most reliable JSON input is a number representing seconds (int or float). Pydantic will coerce that into a timedelta
.
Examples
- Flow
from datetime import timedelta
from prefect import flow
@flow
def my_flow(window: timedelta):
print(window)
# window will be a real datetime.timedelta at runtime
- Parameters JSON (UI/API/etc.)
{"window": 86400} # 1 day
{"window": 90.5} # 90.5 seconds
What else “may” work
- ISO 8601 duration strings (e.g., "P1D"
, "PT1H30M"
) are generally accepted by Pydantic for timedeltas, but if you want a format that just works everywhere in Prefect, use numeric seconds.
If you hit any parsing issues with strings, switch to numeric seconds and it should resolve them. If you can share how you’re passing the parameter (UI, API, CLI) and an example value you tried, I can confirm exactly what will be accepted in that path.Idriss Bellil
08/28/2025, 3:10 PMMarvin
08/28/2025, 3:10 PMMarvin
08/28/2025, 3:11 PMtimedelta
. Prefixing with a minus sign is the standard way to express a negative duration.
- JSON examples:
{"window": "-P24D"} # 24 days ago
{"window": "PT-36H"} # 36 hours ago
{"window": "P2DT-3H"} # 2 days and 3 hours ago (note: some parsers prefer "-P2DT3H" instead)
- Caveat: exact string variants accepted can depend on the underlying parser. If you see a validation error, fall back to numeric seconds.
- Not supported out-of-the-box: shell-like strings such as "30 days ago" or date’s --date='30 days ago'
. Those won’t be parsed by Pydantic by default.
If you want first-class readability without guessing parser behavior, you can keep your flow type as timedelta
and accept friendly strings by adding a tiny validator. Example that supports ints/floats (seconds), ISO 8601, and simple “Xd/Xh/Xm/Xs” forms like "-24d":
from datetime import timedelta
from typing import Annotated
from pydantic import BeforeValidator
from prefect import flow
import re
def parse_duration(v):
if isinstance(v, timedelta):
return v
if isinstance(v, (int, float)):
return timedelta(seconds=float(v))
if isinstance(v, str):
s = v.strip()
# simple forms like "-24d", "36h", "90m", "45s"
m = re.fullmatch(r'([+-]?\d+(?:\.\d+)?)\s*([dhms])', s, flags=re.I)
if m:
n = float(m.group(1))
unit = m.group(2).lower()
mult = dict(d=86400, h=3600, m=60, s=1)[unit]
return timedelta(seconds=n * mult)
# try ISO 8601 durations like "P1D", "-PT36H"
try:
import isodate # pip install isodate
td = isodate.parse_duration(s)
# isodate returns timedelta for day/hour/minute/second durations
return td if isinstance(td, timedelta) else td.tdelta
except Exception:
pass
raise TypeError("Invalid duration format; use seconds, ISO 8601 (e.g. -P24D), or -24d/-36h/-90m/-45s")
Duration = Annotated[timedelta, BeforeValidator(parse_duration)]
@flow
def my_flow(window: Duration):
print(window)
If you can share how you’re passing the parameter (UI input, API call body, or a deployment’s default parameters), I can confirm exactly which string forms will be accepted there. My quick recommendation to try first is:
- JSON: {"window": "-P24D"}
If that doesn’t parse in your path, switch to:
- JSON: {"window": "-24d"}
with the small validator above, or
- JSON: {"window": -2073600}
for guaranteed compatibility.