docs: def extract_time_info(text):
      """
      Extract valid time(-range) information from a string according to our specs.
  
      Args:
          text (text_type): Raw string containing encoded time(-span) information.
              Date/Time-combinations are expected in a ``YYYY-MM-DD hh:mm`` format.
              Relative  times can be given with ``-minutes``.
              Please note that either *relative* or *absolute* times will be considered.
              It is possible to either just specify a start date (as time, date,
              or datetime) or a timerange (start and end). If a timerange is given
              start and end need to be delimited exactly by ' - '.
  
      Returns:
          tuple: ``(timeframe, rest)`` tuple. Where ``timeframe`` is a tuple that
              provides convinient access to all seperate elements extracted from
              the raw string and ``rest`` is any substring stat has not been
              matched to valid time/date info.
  
      Note:
          * Relative times always return just ``(None, None, None, None, timedelta)``.
      """
  
      # [TODO] Add a list of supported formats.
  
      def get_time(time, seconds=None):
          """Convert a times string representation to datetime.time instance."""
          if time is None:
              return time
  
          if seconds:
              time_format = '%H:%M:%S'
          else:
              time_format = '%H:%M'
  
          return datetime.datetime.strptime(time.strip(), time_format).time()
  
      def get_date(date):
          """Convert a dates string representation to datetime.date instance."""
          if date:
              date = datetime.datetime.strptime(date.strip(), "%Y-%m-%d").date()
          return date
  
      def date_time_from_groupdict(groupdict):
          """Return a date/time tuple by introspecting a passed dict."""
          if groupdict['datetime']:
              dt = parse_time(groupdict['datetime'])
              time = dt.time()
              date = dt.date()
          else:
              date = get_date(groupdict.get('date'))
              time = get_time(groupdict.get('time'), groupdict.get('seconds'))
          return (date, time)
  
      # Baseline/default values.
      result = {
          'start_date': None,
          'start_time': None,
          'end_date': None,
          'end_time': None,
          'offset': None
      }
      rest = None
  
      # Individual patterns for time/date  substrings.
      relative_pattern = '(?P<relative>-\d+)'
      time_pattern = '(?P<time>\d{2}:\d{2}(?P<seconds>:\d{2})?)'
      date_pattern = '(?P<date>\d{4}-\d{2}-\d{2})'
      datetime_pattern = '(?P<datetime>\d{4}-\d{2}-\d{2} \d{2}:\d{2}(:\d{2})?)'
  
      start = re.match('^({}|{}|{}|{}) (?P<rest>.+)'.format(relative_pattern, datetime_pattern,
          date_pattern, time_pattern), text)
      if start:
          start_groups = start.groupdict()
          if start_groups['relative']:
              result['offset'] = datetime.timedelta(minutes=abs(int(start_groups['relative'])))
          else:
              date, time = date_time_from_groupdict(start_groups)
              result['start_date'] = date
              result['start_time'] = time
          rest = start_groups['rest']
  
          if rest:
              end = re.match('^- ({}|{}|{}) (?P<rest>.+)'.format(datetime_pattern, date_pattern,
                  time_pattern), rest)
          else:
              end = None
  
          if end and not start_groups['relative']:
              end_groups = end.groupdict()
              date, time = date_time_from_groupdict(end_groups)
              result['end_date'] = date
              result['end_time'] = time
              rest = end_groups['rest']
  
      result = TimeFrame(result['start_date'], result['start_time'], result['end_date'],
          result['end_time'], result['offset'])
  
      # Consider the whole string as 'rest' if no time/date info was extracted
      if not rest:
          rest = text
      return (result, rest.strip())