diff --git a/django/utils/timesince.py b/django/utils/timesince.py index 16bce6c2d5..2c6b467870 100644 --- a/django/utils/timesince.py +++ b/django/utils/timesince.py @@ -95,9 +95,14 @@ def timesince(d, now=None, reversed=False, time_strings=None, depth=2): result = [] current_depth = 0 + if months <= 0: + months = 12 + months + while i < len(timesince_chunks_adjusted) and current_depth < depth: seconds, name = timesince_chunks_adjusted[i] count = since // seconds + if name == "month": + count = min(count, months) if count == 0: break result.append(avoid_wrapping(time_strings[name] % {"num": count})) diff --git a/tests/utils_tests/test_timesince.py b/tests/utils_tests/test_timesince.py index c14d34190d..9a5837d2ea 100644 --- a/tests/utils_tests/test_timesince.py +++ b/tests/utils_tests/test_timesince.py @@ -205,6 +205,37 @@ class TimesinceTests(TestCase): self.assertEqual(timesince(self.t, value, depth=depth), expected) self.assertEqual(timeuntil(value, self.t, depth=depth), expected) + def test_months_edge(self): + t = datetime.datetime(2022, 1, 1) + tests = [ + (datetime.datetime(2022, 1, 31), "4\xa0weeks, 2\xa0days"), + (datetime.datetime(2022, 2, 1), "1\xa0month"), + (datetime.datetime(2022, 2, 28), "1\xa0month, 3\xa0weeks"), + (datetime.datetime(2022, 3, 1), "2\xa0months"), + (datetime.datetime(2022, 3, 31), "2\xa0months, 4\xa0weeks"), + (datetime.datetime(2022, 4, 1), "3\xa0months"), + (datetime.datetime(2022, 4, 30), "3\xa0months, 4\xa0weeks"), + (datetime.datetime(2022, 5, 1), "4\xa0months"), + (datetime.datetime(2022, 5, 31), "4\xa0months, 4\xa0weeks"), + (datetime.datetime(2022, 6, 1), "5\xa0months"), + (datetime.datetime(2022, 6, 30), "5\xa0months, 4\xa0weeks"), + (datetime.datetime(2022, 7, 1), "6\xa0months"), + (datetime.datetime(2022, 7, 31), "6\xa0months, 4\xa0weeks"), + (datetime.datetime(2022, 8, 1), "7\xa0months"), + (datetime.datetime(2022, 8, 31), "7\xa0months, 4\xa0weeks"), + (datetime.datetime(2022, 9, 1), "8\xa0months"), + (datetime.datetime(2022, 9, 30), "8\xa0months, 4\xa0weeks"), + (datetime.datetime(2022, 10, 1), "9\xa0months"), + (datetime.datetime(2022, 10, 31), "9\xa0months, 4\xa0weeks"), + (datetime.datetime(2022, 11, 1), "10\xa0months"), + (datetime.datetime(2022, 11, 30), "10\xa0months, 4\xa0weeks"), + (datetime.datetime(2022, 12, 1), "11\xa0months"), + (datetime.datetime(2022, 12, 31), "11\xa0months, 4\xa0weeks"), + ] + for value, expected in tests: + with self.subTest(): + self.assertEqual(timesince(t, value), expected) + def test_depth_invalid(self): msg = "depth must be greater than 0." with self.assertRaisesMessage(ValueError, msg):