Repository: pimutils/khal

Issue:
Permissive parsing of DELTA
I often enter the DELTA using `khal add` with a leading plus, e.g. because it's how stuff works in TaskWarrior, among others. So: `khal add tomorrow 10:00 +90m Test`, but this generates an event with title "+90m Test".

My suggestion would be to swallow a leading `+` in what might be a DELTA value, and try both.

Happy to try to submit a patch.

Discussion:

Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 2731900..fdf730a 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -16,6 +16,7 @@ not released yet
   an event
 * NEW properties of ikhal themes (dark and light) can now be overriden from the
   config file (via the new [palette] section, check the documenation)
+* NEW timedelta strings can now have a leading `+`, e.g. `+1d`
 
 0.11.2
 ======
diff --git a/khal/parse_datetime.py b/khal/parse_datetime.py
index c3915b2..c060579 100644
--- a/khal/parse_datetime.py
+++ b/khal/parse_datetime.py
@@ -289,7 +289,7 @@ def guesstimedeltafstr(delta_string: str) -> dt.timedelta:
     :param delta_string: string encoding time-delta, e.g. '1h 15m'
     """
 
-    tups = re.split(r'(-?\d+)', delta_string)
+    tups = re.split(r'(-?\+?\d+)', delta_string)
     if not re.match(r'^\s*$', tups[0]):
         raise ValueError(f'Invalid beginning of timedelta string "{delta_string}": "{tups[0]}"')
     tups = tups[1:]
@@ -297,6 +297,8 @@ def guesstimedeltafstr(delta_string: str) -> dt.timedelta:
 
     for num, unit in zip(tups[0::2], tups[1::2]):
         try:
+            if num[0] == '+':
+                num = num[1:]
             numint = int(num)
         except ValueError:
             raise DateTimeParseError(


Test patch:
diff --git a/tests/parse_datetime_test.py b/tests/parse_datetime_test.py
index e40507a..1dd9cd8 100644
--- a/tests/parse_datetime_test.py
+++ b/tests/parse_datetime_test.py
@@ -193,6 +193,15 @@ class TestGuessTimedeltafstr:
     def test_seconds(self):
         assert dt.timedelta(seconds=10) == guesstimedeltafstr('10s')
 
+    def test_single_plus(self):
+        assert dt.timedelta(minutes=10) == guesstimedeltafstr('+10m')
+
+    def test_seconds_plus(self):
+        assert dt.timedelta(seconds=10) == guesstimedeltafstr('+10s')
+
+    def test_days_plus(self):
+        assert dt.timedelta(days=10) == guesstimedeltafstr('+10days')
+
     def test_negative(self):
         assert dt.timedelta(minutes=-10) == guesstimedeltafstr('-10m')
 
@@ -200,6 +209,14 @@ class TestGuessTimedeltafstr:
         assert dt.timedelta(days=1, hours=-3, minutes=10) == \
             guesstimedeltafstr(' 1d -3H 10min ')
 
+    def test_multi_plus(self):
+        assert dt.timedelta(days=1, hours=3, minutes=10) == \
+            guesstimedeltafstr(' 1d +3H 10min ')
+
+    def test_multi_plus_minus(self):
+        assert dt.timedelta(days=0, hours=21, minutes=10) == \
+            guesstimedeltafstr('+1d -3H 10min ')
+
     def test_multi_nospace(self):
         assert dt.timedelta(days=1, hours=-3, minutes=10) == \
             guesstimedeltafstr('1D-3hour10m')