diff --git a/changes/3899-07pepa.md b/changes/3899-07pepa.md new file mode 100644 index 0000000..47d195c --- /dev/null +++ b/changes/3899-07pepa.md @@ -0,0 +1,2 @@ +Fix incorrect deserialization of python timedelta object to ISO 8601 for negative time deltas. +Minus was serialized in incorrect place ("P-1DT23H59M59.888735S" instead of correct "-P1DT23H59M59.888735S") diff --git a/pydantic/json.py b/pydantic/json.py index 0769228..b358b85 100644 --- a/pydantic/json.py +++ b/pydantic/json.py @@ -105,8 +105,8 @@ def custom_pydantic_encoder(type_encoders: Dict[Any, Callable[[Type[Any]], Any]] def timedelta_isoformat(td: datetime.timedelta) -> str: """ - ISO 8601 encoding for timedeltas. + ISO 8601 encoding for Python timedelta object. """ minutes, seconds = divmod(td.seconds, 60) hours, minutes = divmod(minutes, 60) - return f'P{td.days}DT{hours:d}H{minutes:d}M{seconds:d}.{td.microseconds:06d}S' + return f'{"-" if td.days < 0 else ""}P{abs(td.days)}DT{hours:d}H{minutes:d}M{seconds:d}.{td.microseconds:06d}S' diff --git a/tests/test_json.py b/tests/test_json.py index 6f3cdc3..1aa210c 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -46,6 +46,7 @@ class MyEnum(Enum): (datetime.datetime(2032, 1, 1), '"2032-01-01T00:00:00"'), (datetime.time(12, 34, 56), '"12:34:56"'), (datetime.timedelta(days=12, seconds=34, microseconds=56), '1036834.000056'), + (datetime.timedelta(seconds=-1), '-1.0'), ({1, 2, 3}, '[1, 2, 3]'), (frozenset([1, 2, 3]), '[1, 2, 3]'), ((v for v in range(4)), '[0, 1, 2, 3]'), @@ -142,6 +143,8 @@ def test_invalid_model(): [ (datetime.timedelta(days=12, seconds=34, microseconds=56), 'P12DT0H0M34.000056S'), (datetime.timedelta(days=1001, hours=1, minutes=2, seconds=3, microseconds=654_321), 'P1001DT1H2M3.654321S'), + (datetime.timedelta(seconds=-1), '-P1DT23H59M59.000000S'), + (datetime.timedelta(), 'P0DT0H0M0.000000S'), ], ) def test_iso_timedelta(input, output):