Skip to content

Precisedelta rounding #254

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

dangillet
Copy link
Contributor

@dangillet dangillet commented May 26, 2025

Fixes #14
Fixes #20
Fixes #30

Based on PR #39 .

Changes proposed in this pull request:

  • I rebased the work that had been done on top of the latest main and resolve the conflicts.
  • I removed the logic regarding regex for the format in favour of a new helper function which will evaluate the rounding based on the format provided
  • Added several additional test cases to highlight some of the differences between %d format and %.0f.

Copy link

codecov bot commented May 26, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 99.51%. Comparing base (bb99238) to head (1687b7d).
Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #254      +/-   ##
==========================================
+ Coverage   99.49%   99.51%   +0.01%     
==========================================
  Files          11       11              
  Lines         794      820      +26     
==========================================
+ Hits          790      816      +26     
  Misses          4        4              
Flag Coverage Δ
macos-latest 97.80% <100.00%> (+0.07%) ⬆️
ubuntu-latest 97.80% <100.00%> (+0.07%) ⬆️
windows-latest 95.85% <100.00%> (+0.13%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

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

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

%d and %0.0f do not produce the same values. So we will first apply the
required formatting and turn the formatted string back into a float or int.

YEARS needs to be treated slightly differently as it needs to be formatted
with `intcomma`. We first check if the resulting value does not have any
fractional part and if not, we turn it into an int, so that it string
output is what a human would expect.

Added several unittests to highlight some of the differences between
using %d and %.0f as a format in precisedelta.
@dangillet dangillet force-pushed the precisedelta-rounding branch from 036417f to 191f093 Compare May 26, 2025 15:45
We only try to round the value based on the format provided if we are
dealing with the minimum_unit.
@dangillet
Copy link
Contributor Author

I need a bit more time. I think I can even fix #30 with this PR.

@dangillet
Copy link
Contributor Author

I added one more commit to address #30 issue.

Unittests hopefully describe what is the expected behaviour. I had to make some decisions for corner cases. I'm happy to discuss if there is a disagreement on any of this.

@dangillet dangillet force-pushed the precisedelta-rounding branch 2 times, most recently from 3bf9f15 to 3ae5e73 Compare May 26, 2025 21:19
The logic about rounding due to formatting has been moved to
_quotient_and_remainder because this is where we have all the logic regarding
the minimum unit and suppress units.

Also removed _carry function. Instead use the same logic than was used for
calculating the `secs` based on the remaining amount of days. It is done
now also for `usecs` based on the `secs` remaining.

Add another block of logic to check after rounding if any units should be
promoted to a higher unit, in case of a rounding up.
@dangillet dangillet force-pushed the precisedelta-rounding branch from 3ae5e73 to efa5e60 Compare May 27, 2025 07:33
@hugovk hugovk added the changelog: Fixed For any bug fixes label May 27, 2025
def _rounding_by_fmt(format: str, value: float) -> float | int:
"""Round a number according to the string format provided.

The string format is the old printf-style String Formatting.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The string format is the old printf-style String Formatting.
The string format is the old printf-style string formatting.

Comment on lines 566 to 573
(dt.timedelta(days=31), "seconds", "1 month and 12 hours"),
(dt.timedelta(days=32), "seconds", "1 month, 1 day and 12 hours"),
(dt.timedelta(days=62), "seconds", "2 months and 1 day"),
(dt.timedelta(days=92), "seconds", "3 months and 12 hours"),
(dt.timedelta(days=31), "days", "1 month and 0.50 days"),
(dt.timedelta(days=32), "days", "1 month and 1.50 days"),
(dt.timedelta(days=62), "days", "2 months and 1 day"),
(dt.timedelta(days=92), "days", "3 months and 0.50 days"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR!

I know we use 30.5 days = month for some approximations but I think this extra 12 hours may be unexpected?

import datetime as dt
from humanize.time import precisedelta

for days in (30, 31, 32):
    print(f"{days} -> {precisedelta(dt.timedelta(days=days))}")

Before:

30 -> 30 days
31 -> 1 month and 0 days
32 -> 1 month and 1 days

After:

30 -> 30 days
31 -> 1 month and 12 hours
32 -> 1 month, 1 day and 12 hours

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you mean and I understand it's indeed confusing. I took it a bit too literally that one month is 30.5 days.

I pushed a new commit where we only consider months to be 30.5 days on average. We round down any remainder when we try to determine the number of months. This means that 31 days is 1 month and 61 days is 2 months.

Although 1 month is 30.5 days on average, we want 31 days to be one
month, and not remainder of 0.5 days which would not be intuitive.
@dangillet dangillet force-pushed the precisedelta-rounding branch from 32d399b to 1687b7d Compare July 5, 2025 16:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
changelog: Fixed For any bug fixes
Projects
None yet
4 participants