Repository: planetlabs/planet-client-python

Issue:
Date range filter with timezone
Request with the `date_range` fails for `datetime.datetime` objects with the timezone specified
```
$ tz = pytz.timezone('UTC')
$ dt = datetime.datetime(2018,1,1, tzinfo=tz)
$ date_range('acquired', gte=dt)
>>> {'field_name': 'acquired', 'type': 'DateRangeFilter', 'config': {'gte': '2018-01-01T00:00:00+00:00Z'}}
```
It can be seen that `Z` is still appended to the end, which does not seem to be valid ISO8601 string.

Discussion:

Patch:
diff --git a/planet/api/filters.py b/planet/api/filters.py
index 60abaab..baa07d9 100644
--- a/planet/api/filters.py
+++ b/planet/api/filters.py
@@ -100,8 +100,10 @@ def not_filter(*predicates):
 def date_range(field_name, **kwargs):
     '''Build a DateRangeFilter.
 
-    Predicate arguments accept a value str that in ISO-8601 format or a value
-    that has a `isoformat` callable that returns an ISO-8601 str.
+    Predicate arguments accept a str that is ISO-8601 format or a value
+    that has an `isoformat` callable that returns an ISO-8601 compliant str.
+
+    If no timezone is provided, UTC is assumed for RFC 3339 compatability.
 
     :raises: ValueError if predicate value does not parse
 
@@ -116,7 +118,12 @@ def date_range(field_name, **kwargs):
             dt = strp_lenient(str(v))
             if dt is None:
                 raise ValueError("unable to use provided time: " + str(v))
-        kwargs[k] = dt.isoformat() + 'Z'
+        iso_date = dt.isoformat()
+        if not dt.tzinfo:
+            # assume UTC for datetimes without an explicit timezone
+            # necessary for RFC 3339 vs ISO 8601 compatability
+            iso_date += 'Z'
+        kwargs[k] = iso_date
     return _filter('DateRangeFilter', config=kwargs, field_name=field_name)
 
 
diff --git a/tox.ini b/tox.ini
index a410f23..ab3b9d2 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,10 +4,10 @@
 # and then run "tox" from this directory.
 
 [tox]
-envlist = py27, py34, py35, py36, py37
+envlist = py27, py36, py37
 
 [testenv]
 deps = pytest
 commands = 
     pip install -e .[dev]
-    pytest
+    pytest {posargs}


Test patch:
diff --git a/tests/test_filters.py b/tests/test_filters.py
new file mode 100644
index 0000000..ccbcd7d
--- /dev/null
+++ b/tests/test_filters.py
@@ -0,0 +1,27 @@
+import pytest
+from pytz import timezone
+from datetime import datetime
+from planet.api import filters
+
+
+@pytest.mark.parametrize('dt, expected', [
+    (datetime(1900, 1, 1, tzinfo=timezone("US/Central")),
+     {'field_name': 'acquired',
+      'type': 'DateRangeFilter',
+      'config': {'gte': '1900-01-01T00:00:00-05:51'}}),
+
+    (datetime(1999, 12, 31),
+     {'field_name': 'acquired',
+      'type': 'DateRangeFilter',
+      'config': {'gte': '1999-12-31T00:00:00Z'}}),
+
+    ("2018-01-01",
+     {'field_name': 'acquired',
+      'type': 'DateRangeFilter',
+      'config': {'gte': '2018-01-01T00:00:00Z'}}),
+])
+def test_date_range(dt, expected):
+    fieldname = "acquired"
+    arg = "gte"
+
+    assert filters.date_range(fieldname, **{arg: dt}) == expected
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 00b4405..53dafbc 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -148,7 +148,7 @@ def test_get_filename_from_url(url, expected):
 
 @pytest.mark.parametrize('content_type,check', [
     (None, lambda x: re.match(r'^planet-[a-z0-9]{8}$', x, re.I) is not None),
-    ('image/tiff', lambda x: x.endswith('.tif')),
+    ('image/tiff', lambda x: x.endswith(('.tif', '.tiff'))),
 ])
 def test_get_random_filename(content_type, check):
     assert check(utils.get_random_filename(content_type))