diff --git a/superset/utils/core.py b/superset/utils/core.py
index 7a74eb43335a..88f8df1fc776 100644
--- a/superset/utils/core.py
+++ b/superset/utils/core.py
@@ -349,6 +349,23 @@ def datetime_f(dttm):
return "{}".format(dttm)
+def format_timedelta(td: timedelta) -> str:
+ """
+ Ensures negative time deltas are easily interpreted by humans
+
+ >>> td = timedelta(0) - timedelta(days=1, hours=5,minutes=6)
+ >>> str(td)
+ '-2 days, 18:54:00'
+ >>> format_timedelta(td)
+ '-1 day, 5:06:00'
+ """
+ if td < timedelta(0):
+ return "-" + str(abs(td))
+ else:
+ # Change this to format positive time deltas the way you want
+ return str(td)
+
+
def base_json_conv(obj):
if isinstance(obj, memoryview):
obj = obj.tobytes()
@@ -363,7 +380,7 @@ def base_json_conv(obj):
elif isinstance(obj, uuid.UUID):
return str(obj)
elif isinstance(obj, timedelta):
- return str(obj)
+ return format_timedelta(obj)
elif isinstance(obj, bytes):
try:
return obj.decode("utf-8")
diff --git a/tests/utils_tests.py b/tests/utils_tests.py
index 5efd44d99342..a0765834c6fd 100644
--- a/tests/utils_tests.py
+++ b/tests/utils_tests.py
@@ -32,6 +32,7 @@
base_json_conv,
convert_legacy_filters_into_adhoc,
datetime_f,
+ format_timedelta,
get_or_create_db,
get_since_until,
get_stacktrace,
@@ -120,6 +121,7 @@ def test_base_json_conv(self):
assert isinstance(base_json_conv(set([1])), list) is True
assert isinstance(base_json_conv(Decimal("1.0")), float) is True
assert isinstance(base_json_conv(uuid.uuid4()), str) is True
+ assert isinstance(base_json_conv(timedelta(0)), str) is True
@patch("superset.utils.core.datetime")
def test_parse_human_timedelta(self, mock_datetime):
@@ -535,6 +537,19 @@ def test_datetime_f(self):
[a, b, c] = [int(v) for v in iso]
self.assertEquals(datetime_f(datetime(a, b, c)), "00:00:00")
+ def test_format_timedelta(self):
+ self.assertEquals(format_timedelta(timedelta(0)), "0:00:00")
+ self.assertEquals(format_timedelta(timedelta(days=1)), "1 day, 0:00:00")
+ self.assertEquals(format_timedelta(timedelta(minutes=-6)), "-0:06:00")
+ self.assertEquals(
+ format_timedelta(timedelta(0) - timedelta(days=1, hours=5, minutes=6)),
+ "-1 day, 5:06:00",
+ )
+ self.assertEquals(
+ format_timedelta(timedelta(0) - timedelta(days=16, hours=4, minutes=3)),
+ "-16 days, 4:03:00",
+ )
+
def test_json_encoded_obj(self):
obj = {"a": 5, "b": ["a", "g", 5]}
val = '{"a": 5, "b": ["a", "g", 5]}'