diff --git a/django/utils/dateparse.py b/django/utils/dateparse.py index c3d7eb06b9..b2020b5281 100644 --- a/django/utils/dateparse.py +++ b/django/utils/dateparse.py @@ -30,9 +30,9 @@ datetime_re = re.compile( standard_duration_re = re.compile( r'^' r'(?:(?P-?\d+) (days?, )?)?' - r'((?:(?P\d+):)(?=\d+:\d+))?' - r'(?:(?P\d+):)?' - r'(?P\d+)' + r'((?:(?P-?\d+):)(?=\d+:\d+))?' + r'(?:(?P-?\d+):)?' + r'(?P-?\d+)' r'(?:\.(?P\d{1,6})\d{0,6})?' r'$' ) @@ -125,5 +125,7 @@ def parse_duration(value): sign = -1 if kw.pop('sign', '+') == '-' else 1 if kw.get('microseconds'): kw['microseconds'] = kw['microseconds'].ljust(6, '0') + if kw.get('seconds') and kw.get('microseconds') and kw['seconds'].startswith('-'): + kw['microseconds'] = '-' + kw['microseconds'] kw = {k: float(v) for k, v in six.iteritems(kw) if v is not None} return sign * datetime.timedelta(**kw) diff --git a/tests/utils_tests/test_dateparse.py b/tests/utils_tests/test_dateparse.py index ee4f907b55..0bb81ed0b0 100644 --- a/tests/utils_tests/test_dateparse.py +++ b/tests/utils_tests/test_dateparse.py @@ -108,6 +108,10 @@ class DurationParseTests(unittest.TestCase): def test_negative(self): self.assertEqual(parse_duration('-4 15:30'), timedelta(days=-4, minutes=15, seconds=30)) + self.assertEqual(parse_duration('-172800'), timedelta(days=-2)) + self.assertEqual(parse_duration('-15:30'), timedelta(minutes=-15, seconds=30)) + self.assertEqual(parse_duration('-1:15:30'), timedelta(hours=-1, minutes=15, seconds=30)) + self.assertEqual(parse_duration('-30.1'), timedelta(seconds=-30, milliseconds=-100)) def test_iso_8601(self): self.assertIsNone(parse_duration('P4Y'))