diff --git a/django/utils/timesince.py b/django/utils/timesince.py index 94ba24d48a..766b6f7030 100644 --- a/django/utils/timesince.py +++ b/django/utils/timesince.py @@ -63,7 +63,11 @@ def timesince(d, now=None, reversed=False, time_strings=None, depth=2): if now and not isinstance(now, datetime.datetime): now = datetime.datetime(now.year, now.month, now.day) - now = now or datetime.datetime.now(datetime.timezone.utc if is_aware(d) else None) + # Compared datetimes must be in the same time zone. + if not now: + now = datetime.datetime.now(d.tzinfo if is_aware(d) else None) + elif is_aware(now) and is_aware(d): + now = now.astimezone(d.tzinfo) if reversed: d, now = now, d @@ -77,8 +81,7 @@ def timesince(d, now=None, reversed=False, time_strings=None, depth=2): # Get years and months. total_months = (now.year - d.year) * 12 + (now.month - d.month) - time_delta = delta - datetime.timedelta(days=delta.days) - if d.day > now.day or (d.day == now.day and time_delta.total_seconds() < 0): + if d.day > now.day or (d.day == now.day and d.time() > now.time()): total_months -= 1 years, months = divmod(total_months, 12) diff --git a/tests/utils_tests/test_timesince.py b/tests/utils_tests/test_timesince.py index d54fce2be6..0727e65af4 100644 --- a/tests/utils_tests/test_timesince.py +++ b/tests/utils_tests/test_timesince.py @@ -258,6 +258,24 @@ class TimesinceTests(TestCase): with self.subTest(value): self.assertEqual(timesince(value), expected) + @requires_tz_support + def test_less_than_a_day_cross_day_with_zoneinfo(self): + now_with_zoneinfo = timezone.make_aware( + datetime.datetime(2023, 4, 14, 1, 30, 30), + zoneinfo.ZoneInfo(key="Asia/Kathmandu"), # UTC+05:45 + ) + now_utc = now_with_zoneinfo.astimezone(datetime.timezone.utc) + tests = [ + (now_with_zoneinfo, "0\xa0minutes"), + (now_with_zoneinfo - self.onemicrosecond, "0\xa0minutes"), + (now_with_zoneinfo - self.onesecond, "0\xa0minutes"), + (now_with_zoneinfo - self.oneminute, "1\xa0minute"), + (now_with_zoneinfo - self.onehour, "1\xa0hour"), + ] + for value, expected in tests: + with self.subTest(value): + self.assertEqual(timesince(value, now_utc), expected) + @requires_tz_support @override_settings(USE_TZ=True)