Merge pull request #34474 from AMR-Mannesmann/fix(utils)--format_duration-for-negative-values

fix(utils)!: format_duration for negative values
This commit is contained in:
Akhil Narang 2025-10-28 15:51:10 +05:30 committed by GitHub
commit 21fde3a507
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 44 additions and 26 deletions

View file

@ -64,6 +64,7 @@ from frappe.utils.data import (
duration_to_seconds,
evaluate_filters,
expand_relative_urls,
format_duration,
get_datetime,
get_first_day_of_week,
get_time,
@ -784,6 +785,24 @@ class TestDateUtils(IntegrationTestCase):
self.assertEqual(duration_to_seconds("110m"), 110 * 60)
self.assertEqual(duration_to_seconds("110m"), 110 * 60)
def test_format_duration(self):
# Basic positive durations
self.assertEqual(format_duration(0), "")
self.assertEqual(format_duration(45.7), "45s")
self.assertEqual(format_duration(90.9), "1m 30s")
self.assertEqual(format_duration(3600), "1h")
self.assertEqual(format_duration("12885"), "3h 34m 45s")
self.assertEqual(format_duration(86400), "1d")
self.assertEqual(format_duration(86401), "1d 1s")
# Negative durations
self.assertEqual(format_duration(-45.3), "-45s")
self.assertEqual(format_duration(-12885), "-3h 34m 45s")
# hide_days parameter
self.assertEqual(format_duration(86400, hide_days=True), "24h")
self.assertEqual(format_duration(90061, hide_days=True), "25h 1m 1s")
def test_get_timespan_date_range(self):
supported_timespans = [
"last week",

View file

@ -797,38 +797,37 @@ def format_datetime(datetime_string: DateTimeLikeObject, format_string: str | No
return formatted_datetime
def format_duration(seconds, hide_days=False):
"""Convert the given duration value in float(seconds) to duration format.
def format_duration(seconds: float | int, hide_days: bool = False) -> str:
"""Convert the given duration value in seconds to duration format.
example: convert 12885 to '3h 34m 45s' where 12885 = seconds in float
example:
convert 12885 to '3h 34m 45s' where 12885 = seconds in float
-12885 to '-3h 34m 45s'
"""
seconds = cint(seconds)
negative = seconds < 0
seconds = abs(seconds)
total_duration = {
"days": math.floor(seconds / (3600 * 24)),
"hours": math.floor(seconds % (3600 * 24) / 3600),
"minutes": math.floor(seconds % 3600 / 60),
"seconds": math.floor(seconds % 60),
}
days = (seconds // (3600 * 24)) if not hide_days else 0
hours = ((seconds % (3600 * 24)) // 3600) if not hide_days else (seconds // 3600)
minutes = (seconds % 3600) // 60
seconds = seconds % 60
if hide_days:
total_duration["hours"] = math.floor(seconds / 3600)
total_duration["days"] = 0
total_duration = []
duration = ""
if total_duration:
if total_duration.get("days"):
duration += str(total_duration.get("days")) + "d"
if total_duration.get("hours"):
duration += " " if len(duration) else ""
duration += str(total_duration.get("hours")) + "h"
if total_duration.get("minutes"):
duration += " " if len(duration) else ""
duration += str(total_duration.get("minutes")) + "m"
if total_duration.get("seconds"):
duration += " " if len(duration) else ""
duration += str(total_duration.get("seconds")) + "s"
if days:
total_duration.append(f"{days}d")
if hours:
total_duration.append(f"{hours}h")
if minutes:
total_duration.append(f"{minutes}m")
if seconds:
total_duration.append(f"{seconds}s")
duration = " ".join(total_duration)
if negative and duration:
duration = "-" + duration
return duration