#34483: Negative result of django.utils.timesince.timesince
-------------------------------------+-------------------------------------
     Reporter:  Lorenzo Peña         |                    Owner:  Natalia
                                     |  Bidart
         Type:  Bug                  |                   Status:  assigned
    Component:  Utilities            |                  Version:  4.2
     Severity:  Release blocker      |               Resolution:
     Keywords:  timesince            |             Triage Stage:  Accepted
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------

Comment (by Mariusz Felisiak):

 It seems that `now` must be in the same time zone (as you suggested at the
 beginning), however we also have to change time zone when `now` is passed,
 e.g.
 {{{#!diff
 diff --git a/django/utils/timesince.py b/django/utils/timesince.py
 index 94ba24d48a..9b9dd45af9 100644
 --- a/django/utils/timesince.py
 +++ b/django/utils/timesince.py
 @@ -63,7 +63,10 @@ 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)
 +    if is_aware(d):
 +        now = now.astimezone(d.tzinfo) if now else
 datetime.datetime.now(tz=d.tzinfo)
 +    else:
 +        now = now or datetime.datetime.now()

      if reversed:
          d, now = now, d
 @@ -77,8 +80,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)


 }}}

 see a regression test:
 {{{#!diff
 diff --git a/tests/utils_tests/test_timesince.py
 b/tests/utils_tests/test_timesince.py
 index d54fce2be6..e023e95148 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)

 }}}

 What do you think?

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34483#comment:12>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/010701877e6011b3-690bf969-fce2-46d5-887b-6ceba92beef6-000000%40eu-central-1.amazonses.com.

Reply via email to