docs: def extract(self, text: str = None,
                  extract_first_date_only: bool = False,
                  additional_formats: List[str] = list(),
                  use_default_formats: bool = False,
                  ignore_dates_before: datetime.datetime = None,
                  ignore_dates_after: datetime.datetime = None,
                  detect_relative_dates: bool = False,
                  relative_base: datetime.datetime = None,
                  preferred_date_order: str = "MDY",
                  prefer_language_date_order: bool = True,
                  timezone: str = None,
                  to_timezone: str = None,
                  return_as_timezone_aware: bool = True,
                  prefer_day_of_month: str = "first",
                  prefer_dates_from: str = "current",
                  date_value_resolution: DateResolution = DateResolution.DAY,
                  ) -> List[Extraction]:
          """
          Args:
              text (str):  extract dates from this 'text', default to None
              extract_first_date_only (bool): extract the first valid date only or extract all, default to False
              additional_formats (List[str]):  user defined formats for extraction, default to empty list
              use_default_formats (bool): if use default formats together with addtional_formats, default to False
              ignore_dates_before (datetime.datetime): ignore dates before 'ignore_dates_before', default to None
              ignore_dates_after (datetime.datetime): ignore dates after 'ignore_dates_after', default to None
              detect_relative_dates (bool): if detect relative dates like '9 days before', default to False (pass in a ETK instance(with spaCy enabled) when init the DateExtractor is required for relative date extraction)
              relative_base (datetime.datetime): offset relative dates detected based on 'relative_base', default to None
              preferred_date_order (enum['MDY', 'DMY', 'YMD']): preferred date order when ambiguous, default to 'MDY'
              prefer_language_date_order (bool): if use the text language's preferred order, default to True
              timezone (str): add 'timezone' if there is no timezone information in the extracted date, default to None
              to_timezone (str): convert all dates extracted to this timezone, default to None
              return_as_timezone_aware (bool): returned datetime timezone awareness, default to None
              prefer_day_of_month (enum['first', 'current', 'last']): use which day of the month when there is no 'day', default to 'first'
              prefer_dates_from (enum['past', 'current', 'future']): use which date when there is few info(e.g. only month), default to 'current'
              date_value_resolution (enum[DateResolution.SECOND, DateResolution.MINUTE, DateResolution.HOUR, \
                  DateResolution.DAY, DateResolution.MONTH, DateResolution.YEAR]): specify resolution \
                  when convert to iso format string, default to DateResolution.DAY
  
          Returns:
              List[Extraction]: List of extractions, the information including::
  
                  Extraction._value: iso format string,
                  Extraction._provenance: provenance information including:
                  {
                      'start_char': int - start_char,
                      'end_char': int - end_char
                  },
                  Extraction._addition_inf: additional information including:
                  {
                      'date_object': datetime.datetime - the datetime object,
                      'original_text': str - the original str extracted from text,
                      'language': enum['en', 'es'] - language of the date
                  }
          """
  
          if return_as_timezone_aware:
              self._default_tz = pytz.timezone(timezone) if timezone else get_localzone()
              if ignore_dates_before and not ignore_dates_before.tzinfo:
                  ignore_dates_before = ignore_dates_before.astimezone(self._default_tz)
              if ignore_dates_after and not ignore_dates_after.tzinfo:
                  ignore_dates_after = ignore_dates_after.astimezone(self._default_tz)
              if relative_base and not relative_base.tzinfo:
                  relative_base = relative_base.astimezone(self._default_tz)
          else:
              if ignore_dates_before and ignore_dates_before.tzinfo:
                  ignore_dates_before = ignore_dates_before.replace(tzinfo=None)
              if ignore_dates_after and ignore_dates_after.tzinfo:
                  ignore_dates_after = ignore_dates_after.replace(tzinfo=None)
              if relative_base and relative_base.tzinfo:
                  relative_base = relative_base.replace(tzinfo=None)
  
          if prefer_language_date_order:
              try:
                  self._lan = detect(text)
              except Exception as e:
                  warn('DateExtractor: Catch LangDetectException ' + str(e))
                  warn(message='DateExtractor: Catch LangDetectException {}'.format(str(e)))
  
          self._settings = {
              EXTRACT_FIRST_DATE_ONLY: extract_first_date_only,
              ADDITIONAL_FORMATS: additional_formats,
              USE_DEFAULT_FORMATS: use_default_formats,
              IGNORE_DATES_BEFORE: ignore_dates_before,
              IGNORE_DATES_AFTER: ignore_dates_after,
              DETECT_RELATIVE_DATES: detect_relative_dates,
              RELATIVE_BASE: relative_base,
              PREFERRED_DATE_ORDER: preferred_date_order,
              PREFER_LANGUAGE_DATE_ORDER: prefer_language_date_order,
              TIMEZONE: timezone,
              TO_TIMEZONE: to_timezone,
              RETURN_AS_TIMEZONE_AWARE: return_as_timezone_aware,
              PREFER_DAY_OF_MONTH: prefer_day_of_month,
              PREFER_DATES_FROM: prefer_dates_from,
              DATE_VALUE_RESOLUTION: date_value_resolution
          }
  
          results = []
          additional_regex = []
          if additional_formats:
              for date_format in additional_formats:
                  order = ''
                  reg = date_format
                  for key in singleton_regex:
                      if key[0] == '%':
                          reg2 = re.sub(key, singleton_regex[key], reg)
                          if reg != reg2:
                              if key in units['M']:
                                  order += 'M'
                              elif key in units['Y']:
                                  order += 'Y'
                              elif key in units['D']:
                                  order += 'D'
                              reg = reg2
                  additional_regex.append({
                      'reg': reg,
                      'pattern': date_format,
                      'order': order,
                  })
              for r in additional_regex:
                  try:
                      matches = [self._wrap_date_match(r['order'], match, pattern=r['pattern']) for
                             match in re.finditer(r['reg'], text, re.I) if match]
                      if matches:
                          results.append(matches)
                  except:
                      warn('DateExtractor: Failed to extract with additional format ' + str(r) + '.')
              if use_default_formats:
                  for order in self._final_regex.keys():
                      matches = [self._wrap_date_match(order, match) for match
                                 in re.finditer(self._final_regex[order], text, re.I) if match]
                      if matches:
                          results.append(matches)
          else:
              for order in self._final_regex.keys():
                  matches = [self._wrap_date_match(order, match) for match
                             in re.finditer(self._final_regex[order], text, re.I) if match]
                  results.append(matches)
  
          # for absolute dates:
          ans = self._remove_overlapped_date_str(results)
          # for relative dates:
          if detect_relative_dates:
              ans += self._extract_relative_dates(text)
  
          return ans