Fixed #33879 - Adjusted month duration

Adjusted month duration to be relative to the months between d and now.
This commit is contained in:
Gianpaolo 2022-09-17 16:08:51 +02:00
parent 6ea0b9383d
commit bbfc0f946a
4 changed files with 29 additions and 10 deletions

View File

@ -23,6 +23,8 @@ TIMESINCE_CHUNKS = (
(60, "minute"),
)
MONTHS_DAYS = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
def timesince(d, now=None, reversed=False, time_strings=None, depth=2):
"""
@ -69,28 +71,36 @@ def timesince(d, now=None, reversed=False, time_strings=None, depth=2):
leapdays += 1
delta -= datetime.timedelta(leapdays)
# fix months duration to be relative to the months between d and now
months = now.month - d.month
if months > 0:
m_days = (sum(MONTHS_DAYS[d.month - 1 : now.month - 1])) / months
else:
m_days = (365 - sum(MONTHS_DAYS[now.month - 1 : d.month - 1])) / (12 + months)
timesince_chunks_adjusted = list(TIMESINCE_CHUNKS)
timesince_chunks_adjusted[1] = (int(m_days * 24 * 60 * 60), "month")
# ignore microseconds
since = delta.days * 24 * 60 * 60 + delta.seconds
if since <= 0:
# d is in the future compared to now, stop processing.
return avoid_wrapping(time_strings["minute"] % {"num": 0})
for i, (seconds, name) in enumerate(TIMESINCE_CHUNKS):
for i, (seconds, name) in enumerate(timesince_chunks_adjusted):
count = since // seconds
if count != 0:
break
else:
return avoid_wrapping(time_strings["minute"] % {"num": 0})
result = []
current_depth = 0
while i < len(TIMESINCE_CHUNKS) and current_depth < depth:
seconds, name = TIMESINCE_CHUNKS[i]
while i < len(timesince_chunks_adjusted) and current_depth < depth:
seconds, name = timesince_chunks_adjusted[i]
count = since // seconds
if count == 0:
break
result.append(avoid_wrapping(time_strings[name] % {"num": count}))
# prevent errors in long intervals
if name == "month" and count > 2:
seconds += 10 * 60 * 60
since -= seconds * count
current_depth += 1
i += 1

View File

@ -506,8 +506,8 @@ class HumanizeTests(SimpleTestCase):
# "%(delta)s from now" translations
now + datetime.timedelta(days=1),
now + datetime.timedelta(days=2),
now + datetime.timedelta(days=30),
now + datetime.timedelta(days=60),
now + datetime.timedelta(days=31),
now + datetime.timedelta(days=61),
now + datetime.timedelta(days=500),
now + datetime.timedelta(days=865),
]

View File

@ -147,7 +147,7 @@ class TimesinceTests(TimezoneTestCase):
)
self.assertEqual(output, "1\xa0day")
# Test for #33879 (wrong results for 11 months + several weeks)
# Tests for #33879 (wrong results for 11 months + several weeks)
@setup({"timesince19": "{{ earlier|timesince }}"})
def test_timesince19(self):
output = self.engine.render_to_string(
@ -155,6 +155,15 @@ class TimesinceTests(TimezoneTestCase):
)
self.assertEqual(output, "11\xa0months, 3\xa0weeks")
@setup({"timesince20": "{{ a|timesince:b }}"})
def test_timesince20(self):
now = datetime(2018, 5, 9)
output = self.engine.render_to_string(
"timesince20",
{"a": now, "b": now + timedelta(days=365) + timedelta(days=364)},
)
self.assertEqual(output, "1\xa0year, 11\xa0months")
class FunctionTests(SimpleTestCase):
def test_since_now(self):

View File

@ -16,7 +16,7 @@ class TimesinceTests(TestCase):
self.onehour = datetime.timedelta(hours=1)
self.oneday = datetime.timedelta(days=1)
self.oneweek = datetime.timedelta(days=7)
self.onemonth = datetime.timedelta(days=30)
self.onemonth = datetime.timedelta(days=31)
self.oneyear = datetime.timedelta(days=365)
def test_equal_datetimes(self):