From cb5e7f973c2ae4483cbabf3cbc5a6f5ffae4f946 Mon Sep 17 00:00:00 2001 From: Dylan Pulver Date: Tue, 1 Sep 2026 21:24:18 +0300 Subject: [PATCH] Fix diff_for_humans crashing for the zh locale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit zh/custom.py used a NAMED placeholder in "after"/"before" ("{time}后", "{time}前") while DifferenceFormatter.format() substitutes positionally (difference_formatter.py:115,159 call locale.get(key).format(time)). So the two-datetime form raises KeyError: 'time' for every unit: a.diff_for_humans(b, locale="zh") -> KeyError: 'time' All 28 other locales use "{0}". zh is switched to match; no code change. The relative-to-now form was unaffected because it reads the CLDR translations table rather than these custom entries, and there was no tests/localization/test_zh.py at all, so nothing exercised this path. Adds that test file, covering the relative-to-now form and the two-datetime form that was crashing. --- src/pendulum/locales/zh/custom.py | 4 +-- tests/localization/test_zh.py | 45 +++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 tests/localization/test_zh.py diff --git a/src/pendulum/locales/zh/custom.py b/src/pendulum/locales/zh/custom.py index cf47a403..08df7d85 100644 --- a/src/pendulum/locales/zh/custom.py +++ b/src/pendulum/locales/zh/custom.py @@ -6,8 +6,8 @@ translations = { # Relative time - "after": "{time}后", - "before": "{time}前", + "after": "{0}后", + "before": "{0}前", # Date formats "date_formats": { "LTS": "Ah点m分s秒", diff --git a/tests/localization/test_zh.py b/tests/localization/test_zh.py new file mode 100644 index 00000000..79592daa --- /dev/null +++ b/tests/localization/test_zh.py @@ -0,0 +1,45 @@ +from __future__ import annotations + +import pendulum + + +locale = "zh" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "1秒钟前" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "2分钟前" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "2小时前" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "2天前" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "2周前" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "2个月前" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "2年前" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "1秒钟后" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "1秒钟后" + assert d2.diff_for_humans(d, locale=locale) == "1秒钟前" + + assert d.diff_for_humans(d2, True, locale=locale) == "1秒钟" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "2秒钟"