Merge pull request #822 from Cheukting/isoparse

BUG: Closes #820 Accepting 'z' as valid UTC in isoparser
diff --git a/changelog.d/822.bugfix.rst b/changelog.d/822.bugfix.rst
new file mode 100644
index 0000000..a032cfe
--- /dev/null
+++ b/changelog.d/822.bugfix.rst
@@ -0,0 +1 @@
+Accept 'z' as valid UTC time zone in isoparser. Reported by @cjgibson (gh issue #820). Fixed by @Cheukting (gh pr #822)
diff --git a/dateutil/parser/_parser.py b/dateutil/parser/_parser.py
index 044466d..0da0f3e 100644
--- a/dateutil/parser/_parser.py
+++ b/dateutil/parser/_parser.py
@@ -291,7 +291,7 @@
            ("s", "second", "seconds")]
     AMPM = [("am", "a"),
             ("pm", "p")]
-    UTCZONE = ["UTC", "GMT", "Z"]
+    UTCZONE = ["UTC", "GMT", "Z", "z"]
     PERTAIN = ["of"]
     TZOFFSET = {}
     # TODO: ERA = ["AD", "BC", "CE", "BCE", "Stardate",
@@ -388,7 +388,8 @@
         if res.year is not None:
             res.year = self.convertyear(res.year, res.century_specified)
 
-        if res.tzoffset == 0 and not res.tzname or res.tzname == 'Z':
+        if ((res.tzoffset == 0 and not res.tzname) or
+             (res.tzname == 'Z' or res.tzname == 'z')):
             res.tzname = "UTC"
             res.tzoffset = 0
         elif res.tzoffset != 0 and res.tzname and self.utczone(res.tzname):
@@ -1060,7 +1061,8 @@
                 tzname is None and
                 tzoffset is None and
                 len(token) <= 5 and
-                all(x in string.ascii_uppercase for x in token))
+                (all(x in string.ascii_uppercase for x in token)
+                 or token in self.info.UTCZONE))
 
     def _ampm_valid(self, hour, ampm, fuzzy):
         """
diff --git a/dateutil/parser/isoparser.py b/dateutil/parser/isoparser.py
index 172972b..e3cf6d8 100644
--- a/dateutil/parser/isoparser.py
+++ b/dateutil/parser/isoparser.py
@@ -341,7 +341,7 @@
         while pos < len_str and comp < 5:
             comp += 1
 
-            if timestr[pos:pos + 1] in b'-+Z':
+            if timestr[pos:pos + 1] in b'-+Zz':
                 # Detect time zone boundary
                 components[-1] = self._parse_tzstr(timestr[pos:])
                 pos = len_str
@@ -376,7 +376,7 @@
         return components
 
     def _parse_tzstr(self, tzstr, zero_as_utc=True):
-        if tzstr == b'Z':
+        if tzstr == b'Z' or tzstr == b'z':
             return tz.tzutc()
 
         if len(tzstr) not in {3, 5, 6}:
diff --git a/dateutil/test/test_isoparser.py b/dateutil/test/test_isoparser.py
index b0e6564..ecd6e84 100644
--- a/dateutil/test/test_isoparser.py
+++ b/dateutil/test/test_isoparser.py
@@ -228,6 +228,8 @@
     (b'20140204T123015.224', datetime(2014, 2, 4, 12, 30, 15, 224000)),
     (b'2014-02-04T12:30:15.224Z', datetime(2014, 2, 4, 12, 30, 15, 224000,
                                            tz.tzutc())),
+    (b'2014-02-04T12:30:15.224z', datetime(2014, 2, 4, 12, 30, 15, 224000,
+                                           tz.tzutc())),
     (b'2014-02-04T12:30:15.224+05:00',
         datetime(2014, 2, 4, 12, 30, 15, 224000,
                  tzinfo=tz.tzoffset(None, timedelta(hours=5))))])
diff --git a/dateutil/test/test_parser.py b/dateutil/test/test_parser.py
index c2d5d9a..dcaa7cc 100644
--- a/dateutil/test/test_parser.py
+++ b/dateutil/test/test_parser.py
@@ -472,6 +472,11 @@
         self.assertEqual(parse("1976-07-04T00:01:02Z", ignoretz=True),
                          datetime(1976, 7, 4, 0, 1, 2))
 
+    def testRandomFormat18(self):
+        self.assertEqual(parse("1986-07-05T08:15:30z",
+                               ignoretz=True),
+                         datetime(1986, 7, 5, 8, 15, 30))
+
     def testRandomFormat20(self):
         self.assertEqual(parse("Tue Apr 4 00:22:12 PDT 1995", ignoretz=True),
                          datetime(1995, 4, 4, 0, 22, 12))