Skip to content

Commit

Permalink
Refs #34483 -- Fixed timesince()/timeuntil() with timezone-aware date…
Browse files Browse the repository at this point in the history
…s on different days and interval less than 1 day.

Follow up to 813015d.
Regression in 8d67e16.
  • Loading branch information
felixxm authored Apr 14, 2023
1 parent 53aee47 commit 198a19b
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 3 deletions.
9 changes: 6 additions & 3 deletions django/utils/timesince.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)

Expand Down
18 changes: 18 additions & 0 deletions tests/utils_tests/test_timesince.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,24 @@ def test_less_than_a_day_with_zoneinfo(self):
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)
Expand Down

0 comments on commit 198a19b

Please sign in to comment.