Skip to content

Preserve fractional seconds in naturaltime with subsecond units - #408

Open
9Kun wants to merge 1 commit into
python-humanize:mainfrom
9Kun:fix/naturaltime-subsecond-floats
Open

9Kun wants to merge 1 commit into
python-humanize:mainfrom
9Kun:fix/naturaltime-subsecond-floats

Conversation

@9Kun

@9Kun 9Kun commented Sep 22, 2026

Copy link
Copy Markdown

Changes proposed in this pull request:

  • Preserve fractional numeric seconds when minimum_unit requests milliseconds or microseconds, using the existing _date_and_delta(..., precise=...) path.
  • Keep the default seconds rounding, case-insensitive unit names, and numeric future behavior unchanged.
  • Extend the existing datetime test cases to cover numeric seconds and timedeltas, and add boundary/sign/tense/case and seconds-rounding regressions.

Reproduction

On main at 392aef707c0e74341ab4a51420984e9ea6b566c5:

import datetime as dt
import humanize

humanize.naturaltime(0.1, minimum_unit="milliseconds")
# Actual: '0 milliseconds ago'; expected: '100 milliseconds ago'
humanize.naturaltime(dt.timedelta(seconds=0.1), minimum_unit="milliseconds")
# '100 milliseconds ago'
humanize.naturaltime(0.0001, minimum_unit="microseconds")
# Actual: '0 microseconds ago'; expected: '100 microseconds ago'

naturaltime previously rounded numeric inputs to whole seconds before passing them to naturaldelta, even when finer resolution was explicitly requested. No matching open issue or PR was found; the reproduction is included here instead of opening a separate issue.

Validation

Executed locally on Windows, CPython 3.14.0, in a virtual environment:

  • Before the fix, the regression selection failed as expected: 23 failed, 29 passed.
  • python -m pytest tests/test_time.py -q: 414 passed.
  • python -m pytest -q --benchmark-disable --doctest-modules --cov=humanize -ra tests src/humanize: 891 passed, 2 skipped; humanize.time coverage 100%.
  • python -m ruff check --no-fix ., python -m black --check ., python -m mypy ., and python -m mkdocs build --strict: passed.
  • prek run --all-files --show-diff-on-failure --skip actionlint --skip yamlfmt: passed. The full run could not install Go due to a TLS/download failure, so those two Go-based hooks were not run. No workflow/YAML files are changed.

The two pytest skips need GNU gettext's xgettext/msgmerge/msgfmt, which are unavailable locally. The existing 36 translation catalogs were compiled locally using polib so translation-reading tests could run; no generated catalogs are included in this PR. Other OS/Python matrix jobs have not been run locally.

Black's project configuration includes Python 3.15, which produces an AST-check warning under 3.14. A separate check with all supported targets from 3.10 through 3.14 also passed with AST checking enabled.

AI assistance disclosure

This patch and its tests were prepared, reviewed, and executed by an AI coding agent (OpenAI Codex) at the account owner's request. No human review or manual verification is claimed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant