Repository: joke2k/faker

Issue:
Can't produce a time_delta with a maximum value
When using time_delta from the date_time provider it doesn't seem possible to provide a maximum value.
The provider takes an `end_datetime` parameter but what it does with that is beyond me, certainly not what I'd expect.

### Steps to reproduce

```
>>> from faker import Faker
>>> from datetime import timedelta
>>> Faker().time_delta(end_datetime=timedelta(minutes=60))
datetime.timedelta(days=5892, seconds=74879)
```

### Expected behavior

I'd expect to receive a `datetime.timedelta` with a value no greater than 60 minutes.

### Actual behavior

I receive a `datetime.timedelta` with seemingly unbounded value.

Can't produce a time_delta with a maximum value
When using time_delta from the date_time provider it doesn't seem possible to provide a maximum value.
The provider takes an `end_datetime` parameter but what it does with that is beyond me, certainly not what I'd expect.

### Steps to reproduce

```
>>> from faker import Faker
>>> from datetime import timedelta
>>> Faker().time_delta(end_datetime=timedelta(minutes=60))
datetime.timedelta(days=5892, seconds=74879)
```

### Expected behavior

I'd expect to receive a `datetime.timedelta` with a value no greater than 60 minutes.

### Actual behavior

I receive a `datetime.timedelta` with seemingly unbounded value.



Discussion:

Resolving patch:
diff --git a/faker/providers/date_time/__init__.py b/faker/providers/date_time/__init__.py
--- a/faker/providers/date_time/__init__.py
+++ b/faker/providers/date_time/__init__.py
@@ -1379,8 +1379,11 @@ def time_delta(self, end_datetime=None):
         """
         Get a timedelta object
         """
+        start_datetime = self._parse_start_datetime('now')
         end_datetime = self._parse_end_datetime(end_datetime)
-        ts = self.generator.random.randint(0, end_datetime)
+        seconds = end_datetime - start_datetime
+
+        ts = self.generator.random.randint(*sorted([0, seconds]))
         return timedelta(seconds=ts)
 
     def date_time(self, tzinfo=None, end_datetime=None):
@@ -1507,20 +1510,20 @@ def _parse_timedelta(cls, value):
         raise ParseError("Invalid format for timedelta '{0}'".format(value))
 
     @classmethod
-    def _parse_date_time(cls, text, tzinfo=None):
-        if isinstance(text, (datetime, date, real_datetime, real_date)):
-            return datetime_to_timestamp(text)
+    def _parse_date_time(cls, value, tzinfo=None):
+        if isinstance(value, (datetime, date, real_datetime, real_date)):
+            return datetime_to_timestamp(value)
         now = datetime.now(tzinfo)
-        if isinstance(text, timedelta):
-            return datetime_to_timestamp(now - text)
-        if is_string(text):
-            if text == 'now':
+        if isinstance(value, timedelta):
+            return datetime_to_timestamp(now + value)
+        if is_string(value):
+            if value == 'now':
                 return datetime_to_timestamp(datetime.now(tzinfo))
-            time_params = cls._parse_date_string(text)
+            time_params = cls._parse_date_string(value)
             return datetime_to_timestamp(now + timedelta(**time_params))
-        if isinstance(text, int):
-            return datetime_to_timestamp(now + timedelta(text))
-        raise ParseError("Invalid format for date '{0}'".format(text))
+        if isinstance(value, int):
+            return datetime_to_timestamp(now + timedelta(value))
+        raise ParseError("Invalid format for date '{0}'".format(value))
 
     @classmethod
     def _parse_date(cls, value):
@@ -1530,7 +1533,7 @@ def _parse_date(cls, value):
             return value
         today = date.today()
         if isinstance(value, timedelta):
-            return today - value
+            return today + value
         if is_string(value):
             if value in ('today', 'now'):
                 return today


Test patch:
diff --git a/tests/providers/test_date_time.py b/tests/providers/test_date_time.py
--- a/tests/providers/test_date_time.py
+++ b/tests/providers/test_date_time.py
@@ -91,7 +91,7 @@ def test_parse_date_time(self):
         timestamp = DatetimeProvider._parse_date_time('+30d')
         now = DatetimeProvider._parse_date_time('now')
         assert timestamp > now
-        delta = timedelta(days=-30)
+        delta = timedelta(days=30)
         from_delta = DatetimeProvider._parse_date_time(delta)
         from_int = DatetimeProvider._parse_date_time(30)
 
@@ -114,7 +114,7 @@ def test_parse_date(self):
         assert DatetimeProvider._parse_date(datetime.now()) == today
         assert DatetimeProvider._parse_date(parsed) == parsed
         assert DatetimeProvider._parse_date(30) == parsed
-        assert DatetimeProvider._parse_date(timedelta(days=-30)) == parsed
+        assert DatetimeProvider._parse_date(timedelta(days=30)) == parsed
 
     def test_timezone_conversion(self):
         from faker.providers.date_time import datetime_to_timestamp
@@ -168,6 +168,22 @@ def test_date_object(self):
     def test_time_object(self):
         assert isinstance(self.factory.time_object(), datetime_time)
 
+    def test_timedelta(self):
+        delta = self.factory.time_delta(end_datetime=timedelta(seconds=60))
+        assert delta.seconds <= 60
+
+        delta = self.factory.time_delta(end_datetime=timedelta(seconds=-60))
+        assert delta.seconds >= -60
+
+        delta = self.factory.time_delta(end_datetime='+60s')
+        assert delta.seconds <= 60
+
+        delta = self.factory.time_delta(end_datetime='-60s')
+        assert delta.seconds >= 60
+
+        delta = self.factory.time_delta(end_datetime='now')
+        assert delta.seconds <= 0
+
     def test_date_time_between_dates(self):
         timestamp_start = random.randint(0, 2000000000)
         timestamp_end = timestamp_start + 1