From ed6c3b0206ae91e4efc73d9cebbbf80b6bae8fff Mon Sep 17 00:00:00 2001 From: Alexander Rodionov Date: Mon, 27 Feb 2023 03:03:51 +0400 Subject: [PATCH] support timezone-aware datetimes in naturaltime #17 --- src/humanize/time.py | 4 ++++ tests/test_time.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/humanize/time.py b/src/humanize/time.py index a84f0cd..1c65d8e 100644 --- a/src/humanize/time.py +++ b/src/humanize/time.py @@ -246,6 +246,10 @@ def naturaltime( str: A natural representation of the input in a resolution that makes sense. """ now = when or _now() + + if isinstance(value, dt.datetime) and value.tzinfo is not None: + value = dt.datetime.fromtimestamp(value.timestamp()) + date, delta = _date_and_delta(value, now=now) if date is None: return str(value) diff --git a/tests/test_time.py b/tests/test_time.py index 2e64df0..c62de4b 100644 --- a/tests/test_time.py +++ b/tests/test_time.py @@ -418,6 +418,40 @@ def test_naturaltime_minimum_unit_explicit( assert humanize.naturaltime(datetime, minimum_unit=minimum_unit) == expected +@freeze_time("2020-02-02") +@pytest.mark.parametrize( + "test_input, expected", + [ + (NOW_UTC, "now"), + (NOW_UTC - dt.timedelta(seconds=1), "a second ago"), + (NOW_UTC - dt.timedelta(seconds=30), "30 seconds ago"), + (NOW_UTC - dt.timedelta(minutes=1, seconds=30), "a minute ago"), + (NOW_UTC - dt.timedelta(minutes=2), "2 minutes ago"), + (NOW_UTC - dt.timedelta(hours=1, minutes=30, seconds=30), "an hour ago"), + (NOW_UTC - dt.timedelta(hours=23, minutes=50, seconds=50), "23 hours ago"), + (NOW_UTC - dt.timedelta(days=1), "a day ago"), + (NOW_UTC - dt.timedelta(days=500), "1 year, 4 months ago"), + (NOW_UTC - dt.timedelta(days=365 * 2 + 35), "2 years ago"), + (NOW_UTC + dt.timedelta(seconds=1), "a second from now"), + (NOW_UTC + dt.timedelta(seconds=30), "30 seconds from now"), + (NOW_UTC + dt.timedelta(minutes=1, seconds=30), "a minute from now"), + (NOW_UTC + dt.timedelta(minutes=2), "2 minutes from now"), + (NOW_UTC + dt.timedelta(hours=1, minutes=30, seconds=30), "an hour from now"), + (NOW_UTC + dt.timedelta(hours=23, minutes=50, seconds=50), "23 hours from now"), + (NOW_UTC + dt.timedelta(days=1), "a day from now"), + (NOW_UTC + dt.timedelta(days=500), "1 year, 4 months from now"), + (NOW_UTC + dt.timedelta(days=365 * 2 + 35), "2 years from now"), + # regression tests for bugs in post-release humanize + (NOW_UTC + dt.timedelta(days=10000), "27 years from now"), + (NOW_UTC - dt.timedelta(days=365 + 35), "1 year, 1 month ago"), + (NOW_UTC - dt.timedelta(days=365 * 2 + 65), "2 years ago"), + (NOW_UTC - dt.timedelta(days=365 + 4), "1 year, 4 days ago"), + ], +) +def test_naturaltime_timezone(test_input: dt.datetime, expected: str) -> None: + assert humanize.naturaltime(test_input) == expected + + @pytest.mark.parametrize( "val, min_unit, expected", [