Example #1
0
def goTZBot(user_id, channel, message):
    """
    Parse message and construct bot reply

    Parameters:
    user_id (str): the unique id of sender
    channel (str): the unique id of the channel/group
    message (str): contents of message from user_id

    Returns:
    (str): the message the slackbot will send
    """
    #search for a time
    result = re.search(
        pattern = 
        '(([0-9]|[0-1][0-9]|[2][0-3]):([0-5][0-9]))|(((^[0-9]|\s[0-9]|@[0-9])|[1][0-9]|[2][0-3])(\s{0,1})(AM|PM|am|pm|aM|Am|pM|Pm{2,2}))',
        string = message)

    #if message includes time
    if result:
        #get the senders UTC offset
        _, sender_offset, _ = getUserTZ(user_id)
        #get the datetime
        default = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(seconds=sender_offset)
        message_dt = parse(message, fuzzy=True, default=default)
        #get timezones and names for channel
        tz_dict, tz_name_dict = getChannelUsersTZ(channel)

        return getTZReply(tz_dict, tz_name_dict, message_dt, sender_offset)

    else:
        #if dateutil has problems parsing - catch it
        raise ParserError()
Example #2
0
def parse_date(
    string: str,
    date_format: Optional[str] = None,
    fuzzy: Optional[Dict] = None,
    zero_time: bool = False,
) -> datetime:
    """Parse date from string using specified format (setting any time elements to 0 if zero_time is True).
    If no format is supplied, the function will guess. For unambiguous formats, this should be fine.
    Returns a datetime object. Raises exception for dates that are missing year, month or day.
    If a dictionary is supplied in the fuzzy parameter, then dateutil's fuzzy parsing is used and the results
    returned in the dictionary in keys startdate, enddate, date (the string elements used to make the date) and
    nondate (the non date part of the string).

    Args:
        string (str): Dataset date string
        date_format (Optional[str]): Date format. If None is given, will attempt to guess. Defaults to None.
        fuzzy (Optional[Dict]): If dict supplied, fuzzy matching will be used and results returned in dict
        zero_time (bool): Zero time elements of datetime if True. Defaults to False.

    Returns:
        datetime: The parsed date
    """
    startdate, enddate = parse_date_range(string,
                                          date_format=date_format,
                                          fuzzy=fuzzy,
                                          zero_time=zero_time)
    if startdate != enddate:
        raise ParserError("date is not a specific day!")
    return startdate
Example #3
0
 def partition_datetime_columns(self) -> Tuple[List, List]:
   """Partitions dataframe columns into non-datetime vs. datetime"""
   # Time-series column labels are packed to the right
   first_date_col = None
   for first_date_col_label in self.df.columns:
     first_date_col = 0 if first_date_col is None else first_date_col + 1
     try:
       parse(first_date_col_label)
       break
     except ParserError:
       continue
   assert first_date_col is not None and first_date_col < self.df.shape[1], (
       'Could not find time-series column labels. Expected '
       'a consecutive list of date labels but instead saw this list of '
       'column labels: {col_labels}').format(col_labels=self.df.columns)
   for should_be_date_label in self.df.columns[first_date_col:]:
     try:
       parse(should_be_date_label)
     except ParserError as mesg:
       raise ParserError((
           'Expecting all column labels to be dates starting with {} in '
           '{}. {}').format(self.df[first_date_col], self.df.columns, mesg))
   # rename date columns to %m/%d/%yy
   column_rename_dict = {}
   for date in self.df.columns[first_date_col:].tolist():
     datecode = parse(date)
     column_rename_dict[date] = '{}/{}/{}'.format(
         datecode.month, datecode.day, datecode.year)
   self.df.rename(columns=column_rename_dict, inplace=True)
   return (self.df.columns[0:first_date_col].tolist(),
           self.df.columns[first_date_col:].tolist())
Example #4
0
def test_parsererror_repr():
    # GH 991 — the __repr__ was not properly indented and so was never defined.
    # This tests the current behavior of the ParserError __repr__, but the
    # precise format is not guaranteed to be stable and may change even in
    # minor versions. This test exists to avoid regressions.
    s = repr(ParserError("Problem with string: %s", "2019-01-01"))

    assert s == "ParserError('Problem with string: %s', '2019-01-01')"
Example #5
0
def parse_date_range(
    string: str,
    date_format: Optional[str] = None,
    fuzzy: Optional[Dict] = None,
    zero_time: bool = False,
) -> Tuple[datetime, datetime]:
    """Parse date from string using specified format (setting any time elements to 0 if zero_time is True).
    If no format is supplied, the function will guess. For unambiguous formats, this should be fine.
    Returns date range in dictionary keys startdate and enddate. If a dictionary is supplied in the fuzzy parameter,
    then dateutil's fuzzy parsing is used and the results returned in the dictionary in keys startdate, enddate,
    date (the string elements used to make the date) and nondate (the non date part of the string).

    Args:
        string (str): Dataset date string
        date_format (Optional[str]): Date format. If None is given, will attempt to guess. Defaults to None.
        fuzzy (Optional[Dict]): If dict supplied, fuzzy matching will be used and results returned in dict
        zero_time (bool): Zero time elements of datetime if True. Defaults to False.

    Returns:
        Tuple[datetime,datetime]: Tuple containing start date and end date
    """
    if date_format is None or fuzzy is not None:
        if fuzzy is not None:
            parsed_string1 = parse(string,
                                   fuzzy_with_tokens=True,
                                   default=default_date)
            parsed_string2 = parse(string,
                                   fuzzy_with_tokens=True,
                                   default=default_enddate)
            startdate = parsed_string1[0]
            enddate = parsed_string2[0]
            nondate = parsed_string1[1]
            if nondate:
                fuzzy["nondate"] = nondate
            else:
                fuzzy["nondate"] = None
            fuzzy["date"] = parsed_string1[2]
        else:
            startdate = parse(string, default=default_date)
            enddate = parse(string, default=default_enddate)
        if (startdate.year == default_sd_year
                and enddate.year == default_ed_year):
            raise ParserError("No year in date!")
    else:
        try:
            startdate = datetime.strptime(string, date_format)
        except ValueError as e:
            raise ParserError(str(e)) from e
        if (startdate.year == 1900 and "%Y"
                not in date_format):  # 1900 is default when no year supplied
            raise ParserError("No year in date!")
        enddate = startdate
        if not any(x in date_format for x in ["%d", "%j"]):
            startdate = startdate.replace(day=default_date.day)
            endday = default_enddate.day
            not_set = True
            while not_set:
                try:
                    enddate = enddate.replace(day=endday)
                    not_set = False
                except ValueError as e:
                    endday -= 1
                    if endday == 0:
                        raise ParserError(
                            f"No end day of month found for {str(enddate)}!"
                        ) from e
        if not any(str in date_format for str in ["%b", "%B", "%m", "%j"]):
            startdate = startdate.replace(month=default_date.month)
            enddate = enddate.replace(month=default_enddate.month)
    if zero_time:
        startdate = startdate.replace(hour=0,
                                      minute=0,
                                      second=0,
                                      microsecond=0)
        enddate = enddate.replace(hour=0, minute=0, second=0, microsecond=0)
    if fuzzy is not None:
        fuzzy["startdate"] = startdate
        fuzzy["enddate"] = enddate
    return startdate, enddate
Example #6
0
def parse(timestr,
          default=None,
          ignoretz=False,
          tzinfos=None,
          **kwargs):  # pragma: no cover
    """
    Parse the date/time string into a :class:`datetime.datetime` object.

    :param timestr:
        Any date/time string using the supported formats.

    :param default:
        The default datetime object, if this is a datetime object and not
        ``None``, elements specified in ``timestr`` replace elements in the
        default object.

    :param ignoretz:
        If set ``True``, time zones in parsed strings are ignored and a
        naive :class:`datetime.datetime` object is returned.

    :param tzinfos:
        Additional time zone names / aliases which may be present in the
        string. This argument maps time zone names (and optionally offsets
        from those time zones) to time zones. This parameter can be a
        dictionary with timezone aliases mapping time zone names to time
        zones or a function taking two parameters (``tzname`` and
        ``tzoffset``) and returning a time zone.

        The timezones to which the names are mapped can be an integer
        offset from UTC in seconds or a :class:`tzinfo` object.

        .. doctest::
           :options: +NORMALIZE_WHITESPACE

            >>> from dateutil.parser import parse
            >>> from dateutil.tz import gettz
            >>> tzinfos = {"BRST": -7200, "CST": gettz("America/Chicago")}
            >>> parse("2012-01-19 17:21:00 BRST", tzinfos=tzinfos)
            datetime.datetime(2012, 1, 19, 17, 21, tzinfo=tzoffset(u'BRST', -7200))
            >>> parse("2012-01-19 17:21:00 CST", tzinfos=tzinfos)
            datetime.datetime(2012, 1, 19, 17, 21,
                              tzinfo=tzfile('/usr/share/zoneinfo/America/Chicago'))

        This parameter is ignored if ``ignoretz`` is set.

    :param \\*\\*kwargs:
        Keyword arguments as passed to ``_parse()``.

    :return:
        Returns a :class:`datetime.datetime` object or, if the
        ``fuzzy_with_tokens`` option is ``True``, returns a tuple, the
        first element being a :class:`datetime.datetime` object, the second
        a tuple containing the fuzzy tokens.

    :raises ParserError:
        Raised for invalid or unknown string format, if the provided
        :class:`tzinfo` is not in a valid format, or if an invalid date
        would be created.

    :raises TypeError:
        Raised for non-string or character stream input.

    :raises OverflowError:
        Raised if the parsed date exceeds the largest valid C integer on
        your system.
    """

    if default is None:
        default = datetime.now().replace(hour=0,
                                         minute=0,
                                         second=0,
                                         microsecond=0)

    res, skipped_tokens, date_tokens = DEFAULTPARSER._parse(timestr, **kwargs)

    if res is None:
        raise ParserError("Unknown string format: %s", timestr)

    if len(res) == 0:
        raise ParserError("String does not contain a date: %s", timestr)

    try:
        ret = DEFAULTPARSER._build_naive(res, default)
    except ValueError as e:
        raise ParserError(str(e) + f": {timestr}") from e

    if not ignoretz:
        ret = DEFAULTPARSER._build_tzaware(ret, res, tzinfos)

    if kwargs.get("fuzzy_with_tokens", False):
        return ret, skipped_tokens, date_tokens
    else:
        return ret