Commit 154d98d2 authored by Jacek Sowiński's avatar Jacek Sowiński

Add recurrence and postponing by business days

Inspired and also supported by simpletask[1].

`rec:1b` will recur after 1 business day and `rec:5b` after one full
business week. Negative values are supported.

This feature doesn't of course take holidays into account.

[1]: https://github.com/mpcjanssen/simpletask-android/blob/master/src/main/assets/index.en.md
parent 314b21a1
...@@ -40,6 +40,18 @@ class RelativeDateTester(TopydoTest): ...@@ -40,6 +40,18 @@ class RelativeDateTester(TopydoTest):
result = relative_date_to_date('1d') result = relative_date_to_date('1d')
self.assertEqual(result, self.tomorrow) self.assertEqual(result, self.tomorrow)
def test_zero_bdays(self):
result = relative_date_to_date('0b')
self.assertEqual(result, self.today)
def test_one_bday(self):
result = relative_date_to_date('1b')
self.assertEqual(result, self.monday)
def test_one_bweek(self):
result = relative_date_to_date('5b')
self.assertEqual(result, self.friday)
def test_one_week(self): def test_one_week(self):
result = relative_date_to_date('1w') result = relative_date_to_date('1w')
self.assertEqual(result, date(2015, 11, 13)) self.assertEqual(result, date(2015, 11, 13))
...@@ -152,6 +164,14 @@ class RelativeDateTester(TopydoTest): ...@@ -152,6 +164,14 @@ class RelativeDateTester(TopydoTest):
result = relative_date_to_date('-0d') result = relative_date_to_date('-0d')
self.assertTrue(result, self.today) self.assertTrue(result, self.today)
def test_negative_period3(self):
result = relative_date_to_date('-1b')
self.assertEqual(result, date(2015, 11, 5))
def test_negative_period4(self):
result = relative_date_to_date('-5b')
self.assertEqual(result, date(2015, 10, 30))
def test_weekday_next_week(self): def test_weekday_next_week(self):
""" """
When entering "Friday" on a Friday, return next week Friday instead of When entering "Friday" on a Friday, return next week Friday instead of
......
...@@ -37,9 +37,26 @@ def _add_months(p_sourcedate, p_months): ...@@ -37,9 +37,26 @@ def _add_months(p_sourcedate, p_months):
return date(year, month, day) return date(year, month, day)
def _add_business_days(p_sourcedate, p_bdays):
""" Adds a number of business days to the source date. """
result = p_sourcedate
delta = 1 if p_bdays > 0 else -1
while abs(p_bdays) > 0:
result += timedelta(delta)
weekday = result.weekday()
if weekday >= 5:
continue
p_bdays = p_bdays - 1 if delta > 0 else p_bdays + 1
return result
def _convert_pattern(p_length, p_periodunit, p_offset=None): def _convert_pattern(p_length, p_periodunit, p_offset=None):
""" """
Converts a pattern in the form [0-9][dwmy] and returns a date from the Converts a pattern in the form [0-9][dwmyb] and returns a date from the
offset with the period of time added to it. offset with the period of time added to it.
""" """
result = None result = None
...@@ -55,6 +72,8 @@ def _convert_pattern(p_length, p_periodunit, p_offset=None): ...@@ -55,6 +72,8 @@ def _convert_pattern(p_length, p_periodunit, p_offset=None):
result = _add_months(p_offset, p_length) result = _add_months(p_offset, p_length)
elif p_periodunit == 'y': elif p_periodunit == 'y':
result = _add_months(p_offset, p_length * 12) result = _add_months(p_offset, p_length * 12)
elif p_periodunit == 'b':
result = _add_business_days(p_offset, p_length)
return result return result
...@@ -98,7 +117,8 @@ def relative_date_to_date(p_date, p_offset=None): ...@@ -98,7 +117,8 @@ def relative_date_to_date(p_date, p_offset=None):
p_date = p_date.lower() p_date = p_date.lower()
p_offset = p_offset or date.today() p_offset = p_offset or date.today()
relative = re.match('(?P<length>-?[0-9]+)(?P<period>[dwmy])$', p_date, re.I) relative = re.match('(?P<length>-?[0-9]+)(?P<period>[dwmyb])$',
p_date, re.I)
monday = 'mo(n(day)?)?$' monday = 'mo(n(day)?)?$'
tuesday = 'tu(e(sday)?)?$' tuesday = 'tu(e(sday)?)?$'
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment