Ver código fonte

Refs #34483 -- Fixed timesince()/timeuntil() with timezone-aware dates on different days and interval less than 1 day.

Follow up to 813015d67e2557fa859a07930a9becec4e5f64a0.
Regression in 8d67e16493c903adc9d049141028bc0fff43f8c8.
Mariusz Felisiak 1 ano atrás
pai
commit
198a19b692
2 arquivos alterados com 24 adições e 3 exclusões
  1. 6 3
      django/utils/timesince.py
  2. 18 0
      tests/utils_tests/test_timesince.py

+ 6 - 3
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)
 

+ 18 - 0
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)