From ae4b3145bdf02b8ed810a679de4fd21759bbd417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0brahim=20Sait=20Akar=C3=A7e=C5=9Fme?= <72226290+saitakarcesme@users.noreply.github.com> Date: Tue, 22 Sep 2026 02:46:59 +0200 Subject: [PATCH] Correct past and future directions for datetime durations --- CHANGELOG | 6 ++++++ flask_babel/__init__.py | 9 ++++++--- tests/test_date_formatting.py | 27 +++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a2ee470..4e174ec 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,9 @@ +Unreleased +---------- + +- Correct past and future directions for datetime values in + `format_timedelta(..., add_direction=True)` and the `timedeltaformat` filter. + v3.1.0 ------ diff --git a/flask_babel/__init__.py b/flask_babel/__init__.py index c25155f..6d781c6 100644 --- a/flask_babel/__init__.py +++ b/flask_babel/__init__.py @@ -445,14 +445,17 @@ def format_timedelta( add_direction=False, threshold=0.85, ): - """Format the elapsed time from the given date to now or the given - timedelta. + """Format the time between now and the given date or the given timedelta. + + With ``add_direction=True``, future dates and positive timedeltas use + wording such as "in 1 hour"; past dates and negative timedeltas use + "1 hour ago". This function is also available in the template context as filter named `timedeltaformat`. """ if isinstance(datetime_or_timedelta, datetime): - datetime_or_timedelta = datetime.utcnow() - datetime_or_timedelta + datetime_or_timedelta = datetime_or_timedelta - datetime.utcnow() return dates.format_timedelta( datetime_or_timedelta, granularity, diff --git a/tests/test_date_formatting.py b/tests/test_date_formatting.py index 58b0bbd..83a521f 100644 --- a/tests/test_date_formatting.py +++ b/tests/test_date_formatting.py @@ -1,11 +1,38 @@ from datetime import datetime, timedelta import flask +import pytest import flask_babel as babel from flask_babel import get_babel +@pytest.mark.parametrize("hours, expected", [(-1, "1 hour ago"), (1, "in 1 hour")]) +@pytest.mark.parametrize("use_datetime", [True, False]) +def test_timedelta_direction(monkeypatch, hours, expected, use_datetime): + class FixedDatetime(datetime): + @classmethod + def utcnow(cls): + return cls(2026, 1, 1, 12) + + monkeypatch.setattr(babel, "datetime", FixedDatetime) + app = flask.Flask(__name__) + babel.Babel(app) + value = timedelta(hours=hours) + if use_datetime: + value = FixedDatetime.utcnow() + value + + with app.test_request_context(): + assert babel.format_timedelta(value, add_direction=True) == expected + assert ( + flask.render_template_string( + "{{ value|timedeltaformat(add_direction=True) }}", value=value + ) + == expected + ) + assert babel.format_timedelta(value) == "1 hour" + + def test_basics(): app = flask.Flask(__name__) babel.Babel(app)