-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Can no longer parse str() of timedelta #8248
Comments
Hi @brasie, Thanks for reporting this. Pydantic now uses The Pydantic v1 -> v2 migration guide provides this table with information about how Pydantic converts data during validation. The table also illustrates that when you pass a If you still want to be able to validate data in this format, I'd recommend a custom field validator. Here's an example I threw together quite quickly, there might be some oversights here re behavior with days / without days included in the timedelta: import datetime
import json
from pydantic import BaseModel, field_validator
class Foo(BaseModel):
td: datetime.timedelta
@field_validator('td', mode='before')
def td_to_timedelta(cls, v):
if isinstance(v, datetime.timedelta):
return v
elif isinstance(v, str):
dt = datetime.datetime.strptime(v, '%d days, %H:%M:%S') if 'days' in v else datetime.datetime.strptime(v, '%H:%M:%S')
return datetime.timedelta(days=dt.day, hours=dt.hour, minutes=dt.minute, seconds=dt.second)
else:
return v
# Works
Foo.model_validate({'td': str(datetime.timedelta(hours=10))})
Foo.model_validate({'td': str(datetime.timedelta(days=3, hours=10))})
Foo.model_validate({'td': str(datetime.timedelta(days=3, hours=10, minutes=5, seconds=10))})
Foo.model_validate_json(json.dumps({'td': str(datetime.timedelta(days=3, hours=9, minutes=5, seconds=10))})) An even cleaner approach would be to just pad the hours if a single digit it used. Closing for now, as this is more of a question than a bug. Thanks! |
I see, I suppose; Thanks for the explanation. It's just, you're already parsing more than ISO8601, assuming my understanding is correct that ISO8601 does not include a Hence why it seemed bug-like. But if it is expected behavior on your side, then perhaps this is more of a feature request for |
I think it makes sense to support all timedelta str representations in speedate. |
In my case v1 serialised "session_expiry": 10800, and v2 serialises it to: "session_expiry": "PT10800S", I fixed it by: @field_serializer("session_expiry", mode="plain")
def session_expiry_to_seconds(self, session_expiry: datetime.timedelta) -> int:
return session_expiry.seconds Edit: |
@rafrafek, thanks! I would notice that your solution can give an unexpected answer as Example: >>> td = datetime.timedelta(days=4, seconds=20, microseconds=69)
>>> td.seconds
20
>>> td.total_seconds()
345620.000069 So this code can be re-written in this to avoid issues: @field_serializer("session_expiry", mode="plain")
def session_expiry_to_seconds(self, session_expiry: datetime.timedelta) -> float: # now it returns a float
return session_expiry.total_seconds() # now it returns all seconds |
Initial Checks
Description
In V1, one could parse the a
str()
ed timedelta:But the equivalent in V2 breaks:
This seems simply because the V2 parser is more strict about a leading zero in the hours part of the timedelta, i.e.
3:00:00
is rejected (as output bytimedelta.str
), but03:00:00
is ok.It would be nice to preserve the ability to parse the result of
timedelta.str
Example Code
Python, Pydantic & OS Version
The text was updated successfully, but these errors were encountered: