diff --git a/deepdiff/helper.py b/deepdiff/helper.py index 5143a3b7..8cb6cfa2 100644 --- a/deepdiff/helper.py +++ b/deepdiff/helper.py @@ -691,9 +691,10 @@ def datetime_normalize( datetime.timezone, "BaseTzInfo" ] = datetime.timezone.utc, ) -> Any: - # A plain date has no time component, so truncation does not apply to it. - has_time = not (isinstance(obj, datetime.date) and not isinstance(obj, datetime.datetime)) - if truncate_datetime and has_time: + # Only datetime and time objects carry truncatable time fields. A plain + # date has no time component, and other types (e.g. timedelta) do not + # support .replace() with time fields, so truncation skips them. + if truncate_datetime and isinstance(obj, (datetime.datetime, datetime.time)): if truncate_datetime == 'second': obj = obj.replace(microsecond=0) elif truncate_datetime == 'minute': diff --git a/tests/test_diff_datetime.py b/tests/test_diff_datetime.py index c3905291..880e458e 100644 --- a/tests/test_diff_datetime.py +++ b/tests/test_diff_datetime.py @@ -1,5 +1,6 @@ +import pytest import pytz -from datetime import date, datetime, time, timezone +from datetime import date, datetime, time, timedelta, timezone from deepdiff import DeepDiff @@ -123,3 +124,23 @@ def test_datetime_within_array_with_timezone_diff(self): assert not DeepDiff(d1, d2) assert not DeepDiff(d1, d2, ignore_order=True) assert not DeepDiff(d1, d2, truncate_datetime='second') + + def test_truncate_datetime_with_timedelta(self): + """truncate_datetime must not crash on timedelta (no .replace()).""" + for truncate_datetime in ('second', 'minute', 'hour', 'day'): + d1 = {"a": timedelta(days=1)} + d2 = {"a": timedelta(days=1)} + assert not DeepDiff(d1, d2, truncate_datetime=truncate_datetime) + d2 = {"a": timedelta(days=2)} + assert DeepDiff(d1, d2, truncate_datetime=truncate_datetime) + + def test_truncate_datetime_with_np_datetime64(self): + """truncate_datetime must not crash on np.datetime64 (no .replace()).""" + np = pytest.importorskip("numpy") + from deepdiff import DeepHash + for truncate_datetime in ('second', 'minute', 'hour', 'day'): + h1 = DeepHash(np.datetime64('2020-05-17'), truncate_datetime=truncate_datetime) + h2 = DeepHash(np.datetime64('2020-05-17'), truncate_datetime=truncate_datetime) + assert h1 == h2 + h3 = DeepHash(np.datetime64('2020-05-18'), truncate_datetime=truncate_datetime) + assert h1 != h3