docs: def from_iso8601(s):
      """ convert iso8601 string to datetime object.
      refer to http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14
      for details.
  
      :param str s: time in ISO-8601
      :rtype: datetime.datetime
      """
      m = _iso8601_fmt.match(s)
      if not m:
          m = _iso8601_fmt_date.match(s)
  
      if not m:
          raise ValueError('not a valid iso 8601 format string:[{0}]'.format(s))
  
      g = m.groupdict()
  
      def _default_zero(key):
          v = g.get(key, None)
          return int(v) if v else 0
  
      def _default_none(key):
          v = g.get(key, None)
          return int(v) if v else None
  
      year = _default_zero('year')
      month = _default_zero('month')
      day = _default_zero('day')
      hour = _default_none('hour')
      minute = _default_none('minute')
      second = _default_none('second')
      microsecond = g.get('microsecond', None)
      if microsecond is not None:
          # append zero when not matching 6 digits
          microsecond = int(microsecond + '0' * (6 - len(microsecond)))
      tz_s = g.get('tz')
  
      if not (year and month and day):
          raise ValueError('missing y-m-d: [{0}]'.format(s))
  
      # only date part, time part is none
      if hour == None and minute == None and second == None:
          return datetime.datetime(year, month, day)
  
      # prepare tz info
      tz = None
      if tz_s:
          if hour is None and minute is None:
              raise ValueError('missing h:m when tzinfo is provided: [{0}]'.format(s))
  
          negtive = hh = mm = 0
  
          if tz_s != 'Z':
              negtive = -1 if tz_s[0] == '-' else 1
              hh = int(tz_s[1:3])
              mm = int(tz_s[4:6]) if len(tz_s) > 5 else 0
  
          tz = FixedTZ(h=hh*negtive, m=mm*negtive)
  
      return datetime.datetime(
          year=year,
          month=month,
          day=day,
          hour=hour or 0,
          minute=minute or 0,
          second=second or 0,
          microsecond=microsecond or 0,
          tzinfo=tz
      )