Factor rrule datetime value parsing into a method

The logic for DTSTART, EXDATE and RDATE is substantially similar, so it
makes sense to factor this out into a separate method.
diff --git a/dateutil/rrule.py b/dateutil/rrule.py
index 3fe5e21..20a0c4a 100644
--- a/dateutil/rrule.py
+++ b/dateutil/rrule.py
@@ -1412,6 +1412,8 @@
         self._len = total
 
 
+
+
 class _rrulestr(object):
     """ Parses a string representation of a recurrence rule or set of
     recurrence rules.
@@ -1557,6 +1559,58 @@
                 raise ValueError("invalid '%s': %s" % (name, value))
         return rrule(dtstart=dtstart, cache=cache, **rrkwargs)
 
+    def _parse_date_value(self, date_value, parms, rule_tzids,
+                          ignoretz, tzids, tzinfos):
+        global parser
+        if not parser:
+            from dateutil import parser
+
+        datevals = []
+        value_found = False
+        TZID = None
+
+        for parm in parms:
+            if parm.startswith("TZID="):
+                try:
+                    tzkey = rule_tzids[parm.split('TZID=')[-1]]
+                except KeyError:
+                    continue
+                if tzids is None:
+                    from . import tz
+                    tzlookup = tz.gettz
+                elif callable(tzids):
+                    tzlookup = tzids
+                else:
+                    tzlookup = getattr(tzids, 'get', None)
+                    if tzlookup is None:
+                        msg = ('tzids must be a callable, mapping, or None, '
+                               'not %s' % tzids)
+                        raise ValueError(msg)
+
+                TZID = tzlookup(tzkey)
+                continue
+
+            # RFC 5445 3.8.2.4: The VALUE parameter is optional, but may be found
+            # only once.
+            if parm not in {"VALUE=DATE-TIME", "VALUE=DATE"}:
+                raise ValueError("unsupported parm: " + parm)
+            else:
+                if value_found:
+                    msg = ("Duplicate value parameter found in: " + parm)
+                    raise ValueError(msg)
+                value_found = True
+
+        for datestr in date_value.split(','):
+            date = parser.parse(datestr, ignoretz=ignoretz, tzinfos=tzinfos)
+            if TZID is not None:
+                if date.tzinfo is None:
+                    date = date.replace(tzinfo=TZID)
+                else:
+                    raise ValueError('DTSTART/EXDATE specifies multiple timezone')
+            datevals.append(date)
+
+        return datevals
+
     def _parse_rfc(self, s,
                    dtstart=None,
                    cache=False,
@@ -1629,92 +1683,18 @@
                         raise ValueError("unsupported EXRULE parm: "+parm)
                     exrulevals.append(value)
                 elif name == "EXDATE":
-                    value_found = False
-                    TZID = None
-                    for parm in parms:
-                        if parm.startswith("TZID="):
-                            try:
-                                tzkey = TZID_NAMES[parm.split('TZID=')[-1]]
-                            except KeyError:
-                                continue
-                            if tzids is None:
-                                from . import tz
-                                tzlookup = tz.gettz
-                            elif callable(tzids):
-                                tzlookup = tzids
-                            else:
-                                tzlookup = getattr(tzids, 'get', None)
-                                if tzlookup is None:
-                                    msg = ('tzids must be a callable, ' +
-                                           'mapping, or None, ' +
-                                           'not %s' % tzids)
-                                    raise ValueError(msg)
-
-                            TZID = tzlookup(tzkey)
-                            continue
-                        if parm not in {"VALUE=DATE-TIME", "VALUE=DATE"}:
-                            raise ValueError("unsupported EXDATE parm: "
-                                             + parm)
-                        else:
-                            if value_found:
-                                msg = ("Duplicate value parameter found in "
-                                       "EXDATE: " + parm)
-                                raise ValueError(msg)
-                            value_found = True
-                    for datestr in value.split(','):
-                        exdate = parser.parse(datestr, ignoretz=ignoretz,
-                                             tzinfos=tzinfos)
-                        if TZID is not None:
-                            if exdate.tzinfo is None:
-                                exdate = exdate.replace(tzinfo=TZID)
-                            else:
-                                raise ValueError(
-                                    'EXDATE specifies multiple timezone')
-                        exdatevals.append(exdate)
+                    exdatevals.extend(
+                        self._parse_date_value(value, parms,
+                                               TZID_NAMES, ignoretz,
+                                               tzids, tzinfos)
+                    )
                 elif name == "DTSTART":
-                    # RFC 5445 3.8.2.4: The VALUE parameter is optional, but
-                    # may be found only once.
-                    value_found = False
-                    TZID = None
-                    valid_values = {"VALUE=DATE-TIME", "VALUE=DATE"}
-                    for parm in parms:
-                        if parm.startswith("TZID="):
-                            try:
-                                tzkey = TZID_NAMES[parm.split('TZID=')[-1]]
-                            except KeyError:
-                                continue
-                            if tzids is None:
-                                from . import tz
-                                tzlookup = tz.gettz
-                            elif callable(tzids):
-                                tzlookup = tzids
-                            else:
-                                tzlookup = getattr(tzids, 'get', None)
-                                if tzlookup is None:
-                                    msg = ('tzids must be a callable, ' +
-                                           'mapping, or None, ' +
-                                           'not %s' % tzids)
-                                    raise ValueError(msg)
-
-                            TZID = tzlookup(tzkey)
-                            continue
-                        if parm not in valid_values:
-                            raise ValueError("unsupported DTSTART parm: "+parm)
-                        else:
-                            if value_found:
-                                msg = ("Duplicate value parameter found in " +
-                                       "DTSTART: " + parm)
-                                raise ValueError(msg)
-                            value_found = True
-                    if not parser:
-                        from dateutil import parser
-                    dtstart = parser.parse(value, ignoretz=ignoretz,
-                                           tzinfos=tzinfos)
-                    if TZID is not None:
-                        if dtstart.tzinfo is None:
-                            dtstart = dtstart.replace(tzinfo=TZID)
-                        else:
-                            raise ValueError('DTSTART specifies multiple timezones')
+                    dtvals = self._parse_date_value(value, parms, TZID_NAMES,
+                                                    ignoretz, tzids, tzinfos)
+                    if len(dtvals) != 1:
+                        raise ValueError("Multiple DTSTART values specified:" +
+                                         value)
+                    dtstart = dtvals[0]
                 else:
                     raise ValueError("unsupported property: "+name)
             if (forceset or len(rrulevals) > 1 or rdatevals