Skip to content

Fix calendar-based multi-granularity humanization - #1367

Open
fhgffy wants to merge 6 commits into
arrow-py:masterfrom
fhgffy:fix-humanize-multi-granularity
Open

fhgffy wants to merge 6 commits into
arrow-py:masterfrom
fhgffy:fix-humanize-multi-granularity

Conversation

@fhgffy

@fhgffy fhgffy commented Oct 6, 2026 •

Copy link
Copy Markdown

Pull Request Checklist

  • Added tests for changed code.
  • All tests pass when run locally (pytest with the existing coverage gate).
  • All linting checks pass when run locally (tox -e lint or make lint).
  • Updated documentation for changed code.
  • Code is up-to-date with the master branch.

Description of Changes

Closes #948.

Multi-granularity humanize used a fixed 30.5-day month, which could discard calendar days. For example, 2017-01-01 to 2018-05-03 06:00:02 produced zero remaining days instead of two.

Decompose calendar years, quarters, and months from the original date anchor, then decompose the remaining rounded elapsed seconds into fixed units. Align the endpoint timezone only for calendar calculation, preserve the original aware endpoint for elapsed seconds, and preserve the original datetime when zero months are consumed so its DST fold survives. Fixed-only lists skip calendar conversion. Default and single-granularity paths retain their existing behavior.

When timezone projection exceeds datetime's year range, retain the aware endpoints, consume representable original month anchors, and decompose the remaining elapsed seconds; this does not require constructing a year-10000 month anchor.

Nine new regression tests cover the reported example, both directions, omitted units, leap days and month-end anchoring, subsecond rounding, DST transitions and fold, cross-timezone month boundaries, and datetime-range overflow.

Validation

Final commit: e14dcc31e59b090a9907ecc9cef40a5b8f971c7c.

  • Local JUnit report: 1910 passed, 1 skipped, zero failures or errors.
  • GitHub CI: 26 of 27 checks succeeded. Ubuntu Python 3.13 recorded 1913 passed and 99.93% coverage, passing the existing 99% gate. Linting (including black, flake8 and mypy), docs and 23 platform test jobs succeeded. Codecov patch/project checks both report 100% and success.
  • The only failed job is Windows PyPy, which stopped before tests while downloading PyYAML build dependencies with an IncompleteRead error. The contributor account cannot rerun this upstream workflow; a maintainer rerun is needed.
  • Independent focused review: nine new regressions, 73 existing granularity assertions, 480 default/string/single-element-list comparisons with upstream, and eight datetime-boundary cases spanning both directions passed. UTF-8, Python AST and the complete base diff check passed.

@codecov

codecov Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (2224255) to head (e14dcc3).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff            @@
##            master     #1367   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           10        10           
  Lines         2315      2346   +31     
  Branches       358       366    +8     
=========================================
+ Hits          2315      2346   +31     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@fhgffy fhgffy changed the title Fix inaccurate multi-granularity humanization using relativedelta Fix calendar-based multi-granularity humanization Oct 6, 2026
@fhgffy

fhgffy commented Oct 6, 2026

Copy link
Copy Markdown
Author

The remaining failure at e14dcc3 is a dependency-download failure before the test suite starts.

In Windows PyPy 3.11 job 112060119718, tox exits during install_deps (python -I -m pip install -r requirements/requirements-tests.txt). Installing PyYAML's build dependencies fails with:

Connection broken: IncompleteRead(190689 bytes read, 514 more expected)
ERROR: Failed to build 'pyyaml' when installing build dependencies for pyyaml

The earlier pip upgrade also reports an IncompleteRead. No test assertions ran in this job. This PR changes only arrow/arrow.py and tests/test_arrow.py; the workflow, packaging configuration, and requirements are unchanged. The other 23 platform test jobs and the lint/docs job passed, and both Codecov checks succeeded.

This failure does not call for a change to the PR's code or dependencies. Please rerun the failed Windows PyPy job to retry the interrupted downloads; the required check remains red until a successful rerun.

This branch has not been deployed

No deployments
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.

Humanize Bug when using multiple Granularities

1 participant