diff --git a/beets/dbcore/query.py b/beets/dbcore/query.py index 337e3074c..51f011a1d 100644 --- a/beets/dbcore/query.py +++ b/beets/dbcore/query.py @@ -554,22 +554,25 @@ class Period(object): relative. An absolute date has to be like one of the date_formats '%Y' or '%Y-%m' or '%Y-%m-%d' - A relative date begins by '@ 'and has to follow the pattern_dq format - '@([+|-]?)(\d+)([y|m|w|d])' - - '@' indicates it's a date relative to now() - - the optional '+' or '-' sign, which defaults to '+' will increment or - decrement now() by a certain quantity - - that quantity can be expressed in days, weeks, months or years - respectively 'd', 'w', 'm', 'y' - Please note that this relative calculation is rather approximate as it - makes the assumption of 30 days per month and 365 days per year + A relative date consists of three parts: + - a ``+`` or ``-`` sign is optional and defaults to ``+``. The ``+`` + sign will add a time quantity to the current date while the ``-`` sign + will do the opposite + - a number follows and indicates the amount to add or substract + - a final letter ends and represents the amount in either days, weeks, + months or years (``d``, ``w``, ``m`` or ``y``) + Please note that this relative calculation makes the assumption of 30 + days per month and 365 days per year. """ - pattern_dq = '@([+|-]?)(\d+)([y|m|w|d])' + + pattern_dq = '(?P[+|-]?)(?P[0-9]+)(?P[y|m|w|d])' # noqa: E501 match_dq = re.match(pattern_dq, string) + # test if the string matches the relative date pattern, add the parsed + # quantity to now in that case if match_dq is not None: - sign = match_dq.group(1) - quantity = match_dq.group(2) - timespan = match_dq.group(3) + sign = match_dq.group('sign') + quantity = match_dq.group('quantity') + timespan = match_dq.group('timespan') multiplier = -1 if sign == '-' else 1 days = cls.relative[timespan] date = datetime.now() + multiplier * timedelta( diff --git a/docs/reference/query.rst b/docs/reference/query.rst index 4e379f70f..c9678589f 100644 --- a/docs/reference/query.rst +++ b/docs/reference/query.rst @@ -166,8 +166,7 @@ You can also use relative dates to the current time. A relative date begins with an ``@``. It looks like ``@-3w``, ``@2m`` or ``@-4d`` which means the date 3 weeks ago, the date 2 months from now and the date 4 days ago. -A relative date consists of four parts: -- ``@`` indicates it's a date relative from now +A relative date consists of three parts: - ``+`` or ``-`` sign is optional and defaults to ``+``. The ``+`` sign will add a time quantity to the current date while the ``-`` sign will do the opposite @@ -180,11 +179,11 @@ month and 365 days per year. Here is an example that finds all the albums added between now and last week:: - $ beet ls -a 'added:@-1w..' + $ beet ls -a 'added:-1w..' -Find all items added in a 2 weeks period 4 weeks ago:: +Find all items added in a 2 weeks period 4 weeks ago:: - $ beet ls -a 'added:@-6w..@-4w' + $ beet ls -a 'added:-6w..-4w' Date *intervals*, like the numeric intervals described above, are separated by two dots (``..``). You can specify a start, an end, or both. diff --git a/test/test_datequery.py b/test/test_datequery.py index d0c18e229..0864cac23 100644 --- a/test/test_datequery.py +++ b/test/test_datequery.py @@ -47,8 +47,8 @@ class DateIntervalTest(unittest.TestCase): self.assertContains('..2001', '2001-12-31T23:59:59') self.assertExcludes('..2001', '2002-01-01T00:00:00') - self.assertContains('@-1d..@1d', _datepattern(datetime.now())) - self.assertExcludes('@-2d..@-1d', _datepattern(datetime.now())) + self.assertContains('-1d..1d', _datepattern(datetime.now())) + self.assertExcludes('-2d..-1d', _datepattern(datetime.now())) def test_day_precision_intervals(self): self.assertContains('2000-06-20..2000-06-20', '2000-06-20T00:00:00') @@ -168,37 +168,37 @@ class DateQueryTestRelativeMore(_common.LibTestCase): def test_relative(self): for timespan in ['d', 'w', 'm', 'y']: - query = DateQuery('added', '@-4' + timespan + '..@+4' + timespan) + query = DateQuery('added', '-4' + timespan + '..+4' + timespan) matched = self.lib.items(query) self.assertEqual(len(matched), 1) def test_relative_fail(self): for timespan in ['d', 'w', 'm', 'y']: - query = DateQuery('added', '@-2' + timespan + '..@-1' + timespan) + query = DateQuery('added', '-2' + timespan + '..-1' + timespan) matched = self.lib.items(query) self.assertEqual(len(matched), 0) def test_start_relative(self): for timespan in ['d', 'w', 'm', 'y']: - query = DateQuery('added', '@-4' + timespan + '..') + query = DateQuery('added', '-4' + timespan + '..') matched = self.lib.items(query) self.assertEqual(len(matched), 1) def test_start_relative_fail(self): for timespan in ['d', 'w', 'm', 'y']: - query = DateQuery('added', '@4' + timespan + '..') + query = DateQuery('added', '4' + timespan + '..') matched = self.lib.items(query) self.assertEqual(len(matched), 0) def test_end_relative(self): for timespan in ['d', 'w', 'm', 'y']: - query = DateQuery('added', '..@+4' + timespan) + query = DateQuery('added', '..+4' + timespan) matched = self.lib.items(query) self.assertEqual(len(matched), 1) def test_end_relative_fail(self): for timespan in ['d', 'w', 'm', 'y']: - query = DateQuery('added', '..@-4' + timespan) + query = DateQuery('added', '..-4' + timespan) matched = self.lib.items(query) self.assertEqual(len(matched), 0)