Repository: dask/dask

Issue:
Adding support for string timedelta in map_overlap before/after parameters
It would be convenient to allow string timedelta in _map_overlap_ _before_ and _after_ parameters:

`dask.dataframe.rolling.map_overlap(func, dd, before='5min', after=0)`

Also setting a default value to zero could improve readability:

`dask.dataframe.rolling.map_overlap(func, dd, before='5min')`

I can work on a PR, if it makes sense.




Discussion:
@epizut a PR would certainly be welcome! I imagine this should just involve using `pandas.to_timedelta`?

Resolving patch:
diff --git a/dask/dataframe/core.py b/dask/dataframe/core.py
--- a/dask/dataframe/core.py
+++ b/dask/dataframe/core.py
@@ -882,10 +882,10 @@ def map_overlap(self, func, before, after, *args, **kwargs):
         ----------
         func : function
             Function applied to each partition.
-        before : int or timedelta
+        before : int, timedelta or string timedelta
             The rows to prepend to partition ``i`` from the end of
             partition ``i - 1``.
-        after : int or timedelta
+        after : int, timedelta or string timedelta
             The rows to append to partition ``i`` from the beginning
             of partition ``i + 1``.
         args, kwargs :
@@ -984,7 +984,7 @@ def map_overlap(self, func, before, after, *args, **kwargs):
         4  4.0  1.0
 
         If you have a ``DatetimeIndex``, you can use a ``pd.Timedelta`` for time-
-        based windows.
+        based windows or any ``pd.Timedelta`` convertible string:
 
         >>> ts = pd.Series(range(10), index=pd.date_range('2017', periods=10))
         >>> dts = dd.from_pandas(ts, npartitions=2)
diff --git a/dask/dataframe/rolling.py b/dask/dataframe/rolling.py
--- a/dask/dataframe/rolling.py
+++ b/dask/dataframe/rolling.py
@@ -121,10 +121,10 @@ def map_overlap(
         This will rename and reorder columns for each partition,
         and will raise an error if this doesn't work,
         but it won't raise if dtypes don't match.
-    before : int or timedelta
+    before : int, timedelta or string timedelta
         The rows to prepend to partition ``i`` from the end of
         partition ``i - 1``.
-    after : int or timedelta
+    after : int, timedelta or string timedelta
         The rows to append to partition ``i`` from the beginning
         of partition ``i + 1``.
     transform_divisions : bool, default True
@@ -149,6 +149,11 @@ def map_overlap(
 
     dfs = [df for df in args if isinstance(df, _Frame)]
 
+    if isinstance(before, str):
+        before = pd.to_timedelta(before)
+    if isinstance(after, str):
+        after = pd.to_timedelta(after)
+
     if isinstance(before, datetime.timedelta) or isinstance(after, datetime.timedelta):
         if not is_datetime64_any_dtype(dfs[0].index._meta_nonempty.inferred_type):
             raise TypeError(


Test patch:
diff --git a/dask/dataframe/tests/test_rolling.py b/dask/dataframe/tests/test_rolling.py
--- a/dask/dataframe/tests/test_rolling.py
+++ b/dask/dataframe/tests/test_rolling.py
@@ -202,10 +202,14 @@ def test_map_overlap_errors():
     with pytest.raises(NotImplementedError):
         ddf.map_overlap(shifted_sum, 0, 100, 0, 100, c=2).compute()
 
-    # Offset with non-datetime
+    # Timedelta offset with non-datetime
     with pytest.raises(TypeError):
         ddf.map_overlap(shifted_sum, pd.Timedelta("1s"), pd.Timedelta("1s"), 0, 2, c=2)
 
+    # String timedelta offset with non-datetime
+    with pytest.raises(TypeError):
+        ddf.map_overlap(shifted_sum, "1s", "1s", 0, 2, c=2)
+
 
 def test_map_overlap_provide_meta():
     df = pd.DataFrame(
@@ -459,10 +463,16 @@ def test_time_rolling_large_window_variable_chunks(window):
 @pytest.mark.parametrize("before, after", [("6s", "6s"), ("2s", "2s"), ("6s", "2s")])
 def test_time_rolling(before, after):
     window = before
+    expected = dts.compute().rolling(window).count()
+
+    # String timedelta
+    result = dts.map_overlap(lambda x: x.rolling(window).count(), before, after)
+    assert_eq(result, expected)
+
+    # Timedelta
     before = pd.Timedelta(before)
     after = pd.Timedelta(after)
     result = dts.map_overlap(lambda x: x.rolling(window).count(), before, after)
-    expected = dts.compute().rolling(window).count()
     assert_eq(result, expected)