Пример #1
0
    def _parse_simple_cases(self, source: str, reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()
        year = reference.year
        month = reference.month
        no_year = False
        input_year = False

        match = regex.search(self.config.simple_cases_regex, source)

        if not match or match.start() != 0 or len(match.group()) != len(source):
            return result

        days = RegExpUtility.get_group_list(match, Constants.DAY_GROUP_NAME)
        begin_day = self.config.day_of_month[days[0]]
        end_day = self.config.day_of_month[days[1]]

        month_str = RegExpUtility.get_group(match, Constants.MONTH_GROUP_NAME)

        if month_str.strip() != '':
            month = self.config.month_of_year[month_str]
        else:
            month_str = RegExpUtility.get_group(match, Constants.REL_MONTH)
            month += self.config.get_swift_day_or_month(month_str)

            if month < 0:
                month = 0
                year -= 1
            elif month > 11:
                month = 11
                year += 1

        year_str = RegExpUtility.get_group(match, Constants.YEAR_GROUP_NAME)
        if year_str.strip() != '':
            year = int(year_str)
            input_year = True
        else:
            no_year = True

        begin_date_luis = DateTimeFormatUtil.luis_date(
            year if input_year or self.config.is_future(month_str) else -1, month, begin_day)
        end_date_luis = DateTimeFormatUtil.luis_date(
            year if input_year or self.config.is_future(month_str) else -1, month, end_day)

        future_past_begin_date = DateUtils.generate_dates(no_year, reference, year, month, begin_day)
        future_past_end_date = DateUtils.generate_dates(no_year, reference, year, month, end_day)

        result.timex = f'({begin_date_luis},{end_date_luis},P{end_day - begin_day}D)'

        result.future_value = [
            future_past_begin_date[0],
            future_past_end_date[0]
        ]
        result.past_value = [
            future_past_begin_date[1],
            future_past_end_date[1]
        ]
        result.success = True
        return result
Пример #2
0
    def _parse_quarter(self, source: str,
                       reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()

        match = regex.search(self.config.quarter_regex, source)

        if not match or len(match.group()) != len(source):
            return result

        year = reference.year
        year_num = RegExpUtility.get_group(match, Constants.YEAR_GROUP_NAME)
        year_chinese = RegExpUtility.get_group(match, Constants.YEAR_CHINESE)
        year_relative = RegExpUtility.get_group(match, Constants.YEAR_RELATIVE)
        has_year = False

        if year_num.strip() != '':
            has_year = True
            if self.config.is_year_only(year_num):
                year_num = year_num[:-1]
            year = self._convert_year(year_num, False)
        elif year_chinese.strip() != '':
            has_year = True
            if self.config.is_year_only(year_chinese):
                year_chinese = year_chinese[:-1]
            year = self._convert_year(year_chinese, True)
        elif year_relative.strip() != '':
            has_year = True
            year += self.config.get_swift_day_or_month(year_relative)

        if 100 > year >= 90:
            year += 1900
        elif year < 100 and year < 20:
            year += 2000

        cardinal_str = RegExpUtility.get_group(match, Constants.CARDINAL)
        quarter_num = self.config.cardinal_map.get(cardinal_str, None)

        begin_date = DateUtils.safe_create_from_min_value(
            year, quarter_num * 3 - 2, 1)
        end_date = DateUtils.safe_create_from_min_value(
            year, quarter_num * 3 + 1, 1)
        result.future_value = [begin_date, end_date]
        result.past_value = [begin_date, end_date]

        begin_luis = DateTimeFormatUtil.luis_date_from_datetime(begin_date)
        end_luis = DateTimeFormatUtil.luis_date_from_datetime(end_date)
        result.timex = f'({begin_luis},{end_luis},P3M)'

        result.success = True
        return result
    def match_to_date(self, match,
                      reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()
        year_str = RegExpUtility.get_group(match, 'year')
        year_chs = RegExpUtility.get_group(match, 'yearchs')
        month_str = RegExpUtility.get_group(match, 'month')
        day_str = RegExpUtility.get_group(match, 'day')
        month = 0
        day = 0
        year_tmp = self.convert_chinese_year_to_number(year_chs)
        year = 0 if year_tmp == -1 else year_tmp

        if month_str in self.config.month_of_year and day_str in self.config.day_of_month:
            month = self.get_month_of_year(month_str)
            day = self.get_day_of_month(day_str)

            if year_str.strip():
                year = int(year_str) if year_str.isnumeric() else 0

                if year < 100 and year >= Constants.MIN_TWO_DIGIT_YEAR_PAST_NUM:
                    year += 1900
                elif year < 100 and year < Constants.MAX_TWO_DIGIT_YEAR_FUTURE_NUM:
                    year += 2000

        no_year = False

        if year == 0:
            year = reference.year
            result.timex = DateTimeFormatUtil.luis_date(-1, month, day)
            no_year = True
        else:
            result.timex = DateTimeFormatUtil.luis_date(year, month, day)

        future_date = DateUtils.safe_create_from_min_value(year, month, day)
        past_date = DateUtils.safe_create_from_min_value(year, month, day)

        if no_year and future_date < reference:
            future_date = DateUtils.safe_create_from_min_value(
                year + 1, month, day)

        if no_year and past_date >= reference:
            past_date = DateUtils.safe_create_from_min_value(
                year - 1, month, day)

        result.future_value = future_date
        result.past_value = past_date
        result.success = True
        return result
Пример #4
0
    def _parse_year_and_month(self, source: str,
                              reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()

        match = regex.search(self.year_and_month_regex, source)

        if not match or len(match.group()) != len(source):
            match = regex.search(self.pure_number_year_and_month_regex, source)

        if not match or len(match.group()) != len(source):
            return result

        year = reference.year
        year_num = RegExpUtility.get_group(match, Constants.YEAR_GROUP_NAME)
        year_chinese = RegExpUtility.get_group(match, Constants.YEAR_CHINESE)
        year_relative = RegExpUtility.get_group(match, Constants.YEAR_RELATIVE)

        if year_num.strip() != '':
            if self.config.is_year_only(year_num):
                year_num = year_num[:-1]
            year = self._convert_year(year_num, False)
        elif year_chinese.strip() != '':
            if self.config.is_year_only(year_chinese):
                year_chinese = year_chinese[:-1]
            year = self._convert_year(year_chinese, True)
        elif year_relative.strip() != '':
            year += self.config.get_swift_day_or_month(year_relative)

        if 100 > year >= 90:
            year += 1900
        elif year < 100 and year < 20:
            year += 2000

        month_str = RegExpUtility.get_group(match, Constants.MONTH_GROUP_NAME)
        month = self.config.month_of_year.get(month_str, 0) % 12
        if month == 0:
            month = 12

        begin_date = DateUtils.safe_create_from_min_value(year, month, 1)
        end_date = DateUtils.safe_create_from_min_value(
            year, month, 1) + datedelta(months=1)
        result.future_value = [begin_date, end_date]
        result.past_value = [begin_date, end_date]

        result.timex = f'{year:04d}-{month:02d}'

        result.success = True
        return result
Пример #5
0
    def _parse_year_to_year(self, source: str,
                            reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()

        match = regex.search(self.year_to_year_regex, source)

        if not match:
            match = regex.search(self.year_to_year_suffix_required, source)
            if not match:
                return result

        year_matches = list(regex.finditer(self.config.year_regex, source))
        chinese_year_matches = list(
            regex.finditer(self.chinese_year_regex, source))

        begin_year = 0
        end_year = 0

        if len(year_matches) == 2:
            begin_year = self.__convert_chinese_to_number(
                RegExpUtility.get_group(year_matches[0], 'year'))
            end_year = self.__convert_chinese_to_number(
                RegExpUtility.get_group(year_matches[1], 'year'))
        elif len(chinese_year_matches) == 2:
            begin_year = self._convert_year(
                RegExpUtility.get_group(chinese_year_matches[0], 'yearchs'),
                True)
            end_year = self._convert_year(
                RegExpUtility.get_group(chinese_year_matches[1], 'yearchs'),
                True)
        elif len(year_matches) == 1 and len(chinese_year_matches) == 1:
            if year_matches[0].start() < chinese_year_matches[0].start():
                begin_year = self.__convert_chinese_to_number(
                    RegExpUtility.get_group(year_matches[0], 'year'))
                end_year = self.__convert_chinese_to_number(
                    RegExpUtility.get_group(chinese_year_matches[0],
                                            'yearchs'))
            else:
                begin_year = self.__convert_chinese_to_number(
                    RegExpUtility.get_group(chinese_year_matches[0],
                                            'yearchs'))
                end_year = self.__convert_chinese_to_number(
                    RegExpUtility.get_group(year_matches[0], 'year'))

        begin_year = self.__sanitize_year(begin_year)
        end_year = self.__sanitize_year(end_year)

        begin_date = DateUtils.safe_create_from_min_value(begin_year, 1, 1)
        end_date = DateUtils.safe_create_from_min_value(end_year, 1, 1)
        result.future_value = [begin_date, end_date]
        result.past_value = [begin_date, end_date]

        begin_timex = DateTimeFormatUtil.luis_date_from_datetime(begin_date)
        end_timex = DateTimeFormatUtil.luis_date_from_datetime(end_date)
        result.timex = f'({begin_timex},{end_timex},P{end_year - begin_year}Y)'

        result.success = True
        return result
Пример #6
0
    def _parse_duration(self, source: str,
                        reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()

        # for case "前两年" "后三年"
        duration_result = next(
            iter(self.config.duration_extractor.extract(source, reference)),
            None)
        if not duration_result:
            return result

        match = regex.search(self.unit_regex, duration_result.text)
        if not match:
            return result

        source_unit = RegExpUtility.get_group(match,
                                              Constants.UNIT).strip().lower()
        if source_unit not in self.config.unit_map:
            return result

        before_str = source[:duration_result.start].strip().lower()
        number_str = duration_result.text[:match.start()].strip().lower()
        number_val = self.__convert_chinese_to_number(number_str)
        num_str = str(number_val)

        return self.__parse_common_duration_with_unit(before_str, source_unit,
                                                      num_str, reference)
    def _parse_number_with_unit(
            self, source: str,
            reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()
        ers = self.cardinal_extractor.extract(source)

        if len(ers) == 1:
            er = ers[0]
            pr = self.cardinal_parser.parse(er)
            source_unit: str = source[er.start + er.length:].strip().lower()

            if source_unit.startswith('个'):
                source_unit = source_unit[1:]

            before_str = source[:er.start].strip().lower()

            return self.__parse_common_duration_with_unit(
                before_str, source_unit, pr.resolution_str, float(pr.value),
                reference)

        # handle "last hour"
        match = regex.search(self.unit_regex, source)

        if match:
            source_unit = RegExpUtility.get_group(match, 'unit')
            before_str = source[:match.start()].strip().lower()

            return self.__parse_common_duration_with_unit(
                before_str, source_unit, '1', 1, reference)

        return result
Пример #8
0
    def _parse_number_with_unit(self, source: str, reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()

        # if there are NO spaces between number and unit
        match = regex.search(self.number_combined_with_unit_regex, source)
        if not match:
            return result

        source_unit = RegExpUtility.get_group(match, Constants.UNIT).strip().lower()
        if source_unit not in self.config.unit_map:
            return result

        num_str = RegExpUtility.get_group(match, Constants.NUM)
        before_str = source[:match.start()].strip().lower()

        return self.__parse_common_duration_with_unit(before_str, source_unit, num_str, reference)
Пример #9
0
    def parser_duration_with_ago_and_later(
            self, source: str,
            reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()
        duration_res = self.duration_extractor.extract(source, reference).pop()

        if duration_res:
            match = self.config._unit_regex.search(source)
            if match:
                suffix = source[duration_res.start + duration_res.length:]
                src_unit = RegExpUtility.get_group(match, 'unit')

                number_str = source[duration_res.start:match.lastindex -
                                    duration_res.start + 1]
                number = self.parse_chinese_written_number_to_value(number_str)

                if src_unit in self.config.unit_map:
                    unit_str = self.config.unit_map.get(src_unit)

                    before_match = RegExpUtility.get_matches(
                        ChineseDateExtractor.before_regex, suffix)
                    if before_match and suffix.startswith(before_match[0]):
                        if unit_str == Constants.TIMEX_DAY:
                            date = reference + timedelta(days=-number)
                        elif unit_str == Constants.TIMEX_WEEK:
                            date = reference + timedelta(days=-7 * number)
                        elif unit_str == Constants.TIMEX_MONTH_FULL:
                            date = reference.replace(month=reference.month - 1)
                        elif unit_str == Constants.TIMEX_YEAR:
                            date = reference.replace(year=reference.year - 1)
                        else:
                            return result

                        result.timex = DateTimeFormatUtil.luis_date_from_datetime(
                            date)
                        result.future_value = result.past_value = date
                        result.success = True
                        return result

                    after_match = RegExpUtility.get_matches(
                        ChineseDateExtractor.after_regex, suffix)
                    if after_match and suffix.startswith(after_match[0]):
                        if unit_str == Constants.TIMEX_DAY:
                            date = reference + timedelta(days=number)
                        elif unit_str == Constants.TIMEX_WEEK:
                            date = reference + timedelta(days=7 * number)
                        elif unit_str == Constants.TIMEX_MONTH_FULL:
                            date = reference.replace(month=reference.month + 1)
                        elif unit_str == Constants.TIMEX_YEAR:
                            date = reference.replace(year=reference.year + 1)
                        else:
                            return result

                        result.timex = DateTimeFormatUtil.luis_date_from_datetime(
                            date)
                        result.future_value = result.past_value = date
                        result.success = True
                        return result

        return result
Пример #10
0
    def _parser_duration_with_ago_and_later(
            self, source: str,
            reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()
        duration_res = self.duration_extractor.extract(source, reference).pop()

        if duration_res:
            match = ChineseDateTimeExtractor.date_time_period_unit_regex.search(
                source)
            if match:
                suffix = source[duration_res.start + duration_res.length:]
                src_unit = RegExpUtility.get_group(match, 'unit')

                number_str = source[duration_res.start:match.lastindex -
                                    duration_res.start + 1]
                number = ChineseDateParser.parse_chinese_written_number_to_value(
                    ChineseDateParser(), number_str)

                if src_unit in self.config.unit_map:
                    unit_str = self.config.unit_map.get(src_unit)

                    before_match = RegExpUtility.get_matches(
                        ChineseDateExtractor.before_regex, suffix)
                    if before_match and suffix.startswith(before_match[0]):
                        if unit_str == Constants.TIMEX_HOUR:
                            date = reference + timedelta(hours=-number)
                        elif unit_str == Constants.TIMEX_MINUTE:
                            date = reference + timedelta(minutes=-number)
                        elif unit_str == Constants.TIMEX_SECOND:
                            date = reference + timedelta(seconds=-number)
                        else:
                            return result

                        result.timex = DateTimeFormatUtil.luis_date_from_datetime(
                            date)
                        result.future_value = result.past_value = date
                        result.success = True
                        return result

                    after_match = RegExpUtility.get_matches(
                        ChineseDateExtractor.after_regex, suffix)
                    if after_match and suffix.startswith(after_match[0]):
                        if unit_str == Constants.TIMEX_HOUR:
                            date = reference + timedelta(hours=number)
                        elif unit_str == Constants.TIMEX_MINUTE:
                            date = reference + timedelta(minutes=number)
                        elif unit_str == Constants.TIMEX_SECOND:
                            date = reference + timedelta(seconds=number)
                        else:
                            return result

                        result.timex = DateTimeFormatUtil.luis_date_from_datetime(
                            date)
                        result.future_value = result.past_value = date
                        result.success = True
                        return result

        return result
Пример #11
0
    def _parse_season(self, source: str,
                      reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()

        match = regex.search(self.season_with_year_regex, source)

        if not match or len(match.group()) != len(source):
            return result

        year = reference.year
        year_num = RegExpUtility.get_group(match, Constants.YEAR_GROUP_NAME)
        year_chinese = RegExpUtility.get_group(match, Constants.YEAR_CHINESE)
        year_relative = RegExpUtility.get_group(match, Constants.YEAR_RELATIVE)
        has_year = False

        if year_num.strip() != '':
            has_year = True
            if self.config.is_year_only(year_num):
                year_num = year_num[:-1]
            year = self._convert_year(year_num, False)
        elif year_chinese.strip() != '':
            has_year = True
            if self.config.is_year_only(year_chinese):
                year_chinese = year_chinese[:-1]
            year = self._convert_year(year_chinese, True)
        elif year_relative.strip() != '':
            has_year = True
            year += self.config.get_swift_day_or_month(year_relative)

        if 100 > year >= 90:
            year += 1900
        elif year < 100 and year < 20:
            year += 2000

        season_str = RegExpUtility.get_group(match, Constants.SEASON)
        season = self.config.season_map.get(season_str, None)

        if has_year:
            result.timex = f'{year:02d}-{season}'

        result.success = True
        return result
Пример #12
0
    def parse_implicit_date(self, source: str,
                            reference: datetime) -> DateTimeResolutionResult:
        trimmed_source = source.strip()
        result = DateTimeResolutionResult()

        # handle "十二日" "明年这个月三日" "本月十一日"
        match = regex.match(self.special_date_regex, trimmed_source)
        if match:
            year_str = RegExpUtility.get_group(match, 'thisyear')
            month_str = RegExpUtility.get_group(match, 'thismonth')
            day_str = RegExpUtility.get_group(match, 'day')

            month = reference.month
            day = 0
            day = self.config.day_of_month[day_str]
            year = reference.year

            has_year = False
            has_month = False

            if month_str:
                has_month = True
                if regex.search(self.token_next_regex, month_str):
                    month += 1
                    if month == Constants.MAX_MONTH + 1:
                        month = Constants.MIN_MONTH
                        year += 1
                elif regex.search(self.token_last_regex, month_str):
                    month -= 1
                    if month == Constants.MIN_MONTH - 1:
                        month = Constants.MAX_MONTH
                        year -= 1

                if year_str:
                    has_year = True
                    if regex.search(self.token_next_regex, year_str):
                        year += 1
                    elif regex.search(self.token_last_regex, year_str):
                        year -= 1

            result.timex = DateTimeFormatUtil.luis_date(
                year if has_year else -1, month if has_month else -1, day)

            if day > self.get_month_max_day(year, month):
                future_month = month + 1
                past_month = month - 1
                future_year = year
                past_year = year

                if future_month == Constants.MAX_MONTH + 1:
                    future_month = Constants.MIN_MONTH
                    future_year = year + 1

                if past_month == Constants.MIN_MONTH - 1:
                    past_month = Constants.MAX_MONTH
                    past_year = year - 1

                is_future_valid = DateUtils.is_valid_date(
                    future_year, future_month, day)
                is_past_valid = DateUtils.is_valid_date(
                    past_year, past_month, day)

                if is_future_valid and is_past_valid:
                    future_date = DateUtils.safe_create_from_min_value(
                        future_year, future_month, day)
                    past_date = DateUtils.safe_create_from_min_value(
                        past_year, past_month, day)
                elif is_future_valid and not is_past_valid:
                    future_date = past_date = DateUtils.safe_create_from_min_value(
                        future_year, future_month, day)
                elif not is_future_valid and not is_past_valid:
                    future_date = past_date = DateUtils.safe_create_from_min_value(
                        past_year, past_month, day)
                else:
                    future_date = past_date = DateUtils.safe_create_from_min_value(
                        year, month, day)
            else:
                future_date = DateUtils.safe_create_from_min_value(
                    year, month, day)
                past_date = DateUtils.safe_create_from_min_value(
                    year, month, day)

                if not has_month:
                    if future_date < reference:
                        if self.is_valid_date(year, month + 1, day):
                            future_date += datedelta(months=1)
                    if past_date >= reference:
                        if self.is_valid_date(year, month - 1, day):
                            past_date += datedelta(months=-1)
                        elif DateUtils.is_Feb_29th(year, month - 1, day):
                            past_date += datedelta(months=-2)
                elif not has_year:
                    if future_date < reference:
                        if self.is_valid_date(year + 1, month, day):
                            future_date += datedelta(years=1)
                    if past_date >= reference:
                        if self.is_valid_date(year - 1, month, day):
                            past_date += datedelta(years=-1)

            result.future_value = future_date
            result.past_value = past_date
            result.success = True

            return result

        # handle "today", "the day before yesterday"
        match = regex.match(self.config.special_day_regex, trimmed_source)
        if match and match.start() == 0 and len(
                match.group()) == len(trimmed_source):
            swift = self.config.get_swift_day(match.group())
            value = reference + timedelta(days=swift)

            result.timex = DateTimeFormatUtil.luis_date_from_datetime(value)
            result.future_value = result.past_value = DateUtils.safe_create_from_min_value(
                value.year, value.month, value.day)
            result.success = True
            return result

        # handle "this Friday"
        match = regex.match(self.config.this_regex, trimmed_source)
        if match and match.start() == 0 and len(
                match.group()) == len(trimmed_source):
            weekday_str = RegExpUtility.get_group(match, 'weekday')
            value = DateUtils.this(reference,
                                   self.config.day_of_week.get(weekday_str))

            result.timex = DateTimeFormatUtil.luis_date_from_datetime(value)
            result.future_value = value
            result.past_value = value
            result.success = True
            return result

        # handle "next Sunday"
        match = regex.match(self.config.next_regex, trimmed_source)
        if match and match.start() == 0 and len(
                match.group()) == len(trimmed_source):
            weekday_str = RegExpUtility.get_group(match, 'weekday')
            value = DateUtils.next(reference,
                                   self.config.day_of_week.get(weekday_str))

            result.timex = DateTimeFormatUtil.luis_date_from_datetime(value)
            result.future_value = value
            result.past_value = value
            result.success = True
            return result

        # handle "last Friday", "last mon"
        match = regex.match(self.config.last_regex, trimmed_source)
        if match and match.start() == 0 and len(
                match.group()) == len(trimmed_source):
            weekday_str = RegExpUtility.get_group(match, 'weekday')
            value = DateUtils.last(reference,
                                   self.config.day_of_week.get(weekday_str))

            result.timex = DateTimeFormatUtil.luis_date_from_datetime(value)
            result.future_value = value
            result.past_value = value
            result.success = True
            return result

        # handle "Friday"
        match = regex.match(self.config.week_day_regex, trimmed_source)
        if match and match.start() == 0 and len(
                match.group()) == len(trimmed_source):
            weekday_str = RegExpUtility.get_group(match, 'weekday')
            weekday = self.config.day_of_week.get(weekday_str)
            value = DateUtils.this(reference, weekday)

            if weekday == 0:
                weekday = 7

            if weekday < reference.isoweekday():
                value = DateUtils.next(reference, weekday)

            result.timex = 'XXXX-WXX-' + str(weekday)
            future_date = value
            past_date = value

            if future_date < reference:
                future_date += timedelta(weeks=1)

            if past_date >= reference:
                past_date -= timedelta(weeks=1)

            result.future_value = future_date
            result.past_value = past_date
            result.success = True
            return result

        return result
Пример #13
0
    def _parse_decade(self, source: str,
                      reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()

        century = int(reference.year / 100) + 1
        decade_last_year = 10
        input_century = False

        match = regex.search(self.decade_regex, source)

        if not match or len(match.group()) != len(source):
            return result

        decade_str = RegExpUtility.get_group(match, Constants.DECADE)
        decade = self.__convert_chinese_to_number(decade_str)
        century_str = RegExpUtility.get_group(match, Constants.CENTURY)
        if century_str != "":
            century = self.__convert_chinese_to_number(century_str)
            input_century = True
        else:
            century_str = RegExpUtility.get_group(match, Constants.REL_CENTURY)
            if century_str != "":
                century_str = century_str.strip().lower()

                this_match = regex.search(self.date_this_regex, century_str)
                next_match = regex.search(self.date_next_regex, century_str)
                last_match = regex.search(self.date_last_regex, century_str)

                if next_match:
                    century += 1
                elif last_match:
                    century -= 1

                input_century = True

        begin_year = ((century - 1) * 100) + decade
        end_year = begin_year + decade_last_year

        if input_century:
            begin_luis_str = DateTimeFormatUtil.luis_date(begin_year, 1, 1)
            end_luis_str = DateTimeFormatUtil.luis_date(end_year, 1, 1)
        else:
            begin_year_str = "XX{:02d}".format(decade)
            begin_luis_str = DateTimeFormatUtil.luis_date(-1, 1, 1)
            begin_luis_str = begin_luis_str.replace("XXXX", begin_year_str)

            end_year_str = "XX{:02d}".format(end_year % 100)
            end_luis_str = DateTimeFormatUtil.luis_date(-1, 1, 1)
            end_luis_str = end_luis_str.replace("XXXX", end_year_str)

        result.timex = f"({begin_luis_str},{end_luis_str},P10Y)"

        future_year, past_year = begin_year, begin_year
        start_date = DateUtils.safe_create_from_min_value(begin_year, 1, 1)
        if not input_century and start_date < reference:
            future_year += 100
        if not input_century and start_date >= reference:
            past_year -= 100

        result.future_value = [
            DateUtils.safe_create_from_min_value(future_year, 1, 1),
            DateUtils.safe_create_from_min_value(
                future_year + decade_last_year, 1, 1)
        ]
        result.past_value = [
            DateUtils.safe_create_from_min_value(past_year, 1, 1),
            DateUtils.safe_create_from_min_value(past_year + decade_last_year,
                                                 1, 1)
        ]
        result.success = True

        return result
Пример #14
0
    def _parse_simple_cases(self, source: str,
                            reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()
        year = reference.year
        month = reference.month
        no_year = False
        input_year = False

        match = regex.search(self.config.simple_cases_regex, source)

        if not match or match.start() != 0 or len(
                match.group()) != len(source):
            return result

        days = RegExpUtility.get_group_list(match, 'day')
        begin_day = self.config.day_of_month[days[0]]
        end_day = self.config.day_of_month[days[1]]

        month_str = RegExpUtility.get_group(match, 'month')

        if month_str.strip() != '':
            month = self.config.month_of_year[month_str]
        else:
            month_str = RegExpUtility.get_group(match, 'relmonth')
            month += self.config.get_swift_day_or_month(month_str)

            if month < 0:
                month = 0
                year -= 1
            elif month > 11:
                month = 11
                year += 1

        year_str = RegExpUtility.get_group(match, 'year')
        if year_str.strip() != '':
            year = int(year_str)
            input_year = True
        else:
            no_year = True

        begin_date_luis = DateTimeFormatUtil.luis_date(
            year if input_year or self.config.is_future(month_str) else -1,
            month, begin_day)
        end_date_luis = DateTimeFormatUtil.luis_date(
            year if input_year or self.config.is_future(month_str) else -1,
            month, end_day)

        future_year = year
        past_year = year

        start_date = DateUtils.safe_create_from_min_value(
            year, month, begin_day)

        if no_year and start_date < reference:
            future_year += 1

        if no_year and start_date >= reference:
            past_year -= 1

        result.timex = f'({begin_date_luis},{end_date_luis},P{end_day - begin_day}D)'

        result.future_value = [
            DateUtils.safe_create_from_min_value(future_year, month,
                                                 begin_day),
            DateUtils.safe_create_from_min_value(future_year, month, end_day)
        ]
        result.past_value = [
            DateUtils.safe_create_from_min_value(past_year, month, begin_day),
            DateUtils.safe_create_from_min_value(past_year, month, end_day)
        ]

        result.success = True
        return result
Пример #15
0
    def parse_implicit_date(self, source: str,
                            reference: datetime) -> DateTimeParseResult:
        trimmed_source = source.strip()
        result = DateTimeResolutionResult()

        # handle "on 12"
        match = regex.search(self.special_date_regex, trimmed_source)
        if match and len(match.group()) == len(trimmed_source):
            day = 0
            month = reference.month
            year = reference.year
            year_str = RegExpUtility.get_group(match, 'thisyear')
            month_str = RegExpUtility.get_group(match, 'thismonth')
            day_str = RegExpUtility.get_group(match, 'day')
            day = self.config.day_of_month.get(day_str, -1)

            has_year = year_str.strip() != ''
            has_month = month_str.strip() != ''

            if has_month:
                if regex.search(self.token_next_regex, month_str):
                    month += 1
                    if month == 12:
                        month = 0
                        year += 1
                elif regex.search(self.token_last_regex, month_str):
                    month -= 1
                    if month == -1:
                        month = 12
                        year -= 1

                if has_year:
                    if regex.search(self.token_next_regex, year_str):
                        year += 1
                    elif regex.search(self.token_last_regex, year_str):
                        year -= 1

            result.timex = FormatUtil.luis_date(year if has_year else -1,
                                                month if has_month else -1,
                                                day)

            future_date: datetime
            past_date: datetime

            if day > self.month_max_days[month]:
                future_date = DateUtils.safe_create_from_min_value(
                    year, month + 1, day)
                past_date = DateUtils.safe_create_from_min_value(
                    year, month - 1, day)
            else:
                future_date = DateUtils.safe_create_from_min_value(
                    year, month, day)
                past_date = DateUtils.safe_create_from_min_value(
                    year, month, day)

                if not has_month:
                    if future_date < reference:
                        future_date += datedelta(months=1)
                    if past_date >= reference:
                        past_date += datedelta(months=-1)
                elif has_month and not has_year:
                    if future_date < reference:
                        future_date += datedelta(years=1)
                    if past_date >= reference:
                        past_date += datedelta(years=-1)

            result.future_value = future_date
            result.past_value = past_date
            result.success = True
            return result

        # handle "today", "the day before yesterday"
        match = regex.match(self.config.special_day_regex, trimmed_source)
        if match and match.start() == 0 and len(
                match.group()) == len(trimmed_source):
            swift = self.config.get_swift_day(match.group())
            value = reference + timedelta(days=swift)

            result.timex = FormatUtil.luis_date_from_datetime(value)
            result.future_value = value
            result.past_value = value
            result.success = True
            return result

        # handle "this Friday"
        match = regex.match(self.config.this_regex, trimmed_source)
        if match and match.start() == 0 and len(
                match.group()) == len(trimmed_source):
            weekday_str = RegExpUtility.get_group(match, 'weekday')
            value = DateUtils.this(reference,
                                   self.config.day_of_week.get(weekday_str))

            result.timex = FormatUtil.luis_date_from_datetime(value)
            result.future_value = value
            result.past_value = value
            result.success = True
            return result

        # handle "next Sunday"
        match = regex.match(self.config.next_regex, trimmed_source)
        if match and match.start() == 0 and len(
                match.group()) == len(trimmed_source):
            weekday_str = RegExpUtility.get_group(match, 'weekday')
            value = DateUtils.next(reference,
                                   self.config.day_of_week.get(weekday_str))

            result.timex = FormatUtil.luis_date_from_datetime(value)
            result.future_value = value
            result.past_value = value
            result.success = True
            return result

        # handle "last Friday", "last mon"
        match = regex.match(self.config.last_regex, trimmed_source)
        if match and match.start() == 0 and len(
                match.group()) == len(trimmed_source):
            weekday_str = RegExpUtility.get_group(match, 'weekday')
            value = DateUtils.last(reference,
                                   self.config.day_of_week.get(weekday_str))

            result.timex = FormatUtil.luis_date_from_datetime(value)
            result.future_value = value
            result.past_value = value
            result.success = True
            return result

        # handle "Friday"
        match = regex.match(self.config.week_day_regex, trimmed_source)
        if match and match.start() == 0 and len(
                match.group()) == len(trimmed_source):
            weekday_str = RegExpUtility.get_group(match, 'weekday')
            weekday = self.config.day_of_week.get(weekday_str)
            value = DateUtils.this(reference, weekday)

            if weekday == 0:
                weekday = 7

            if weekday < reference.isoweekday():
                value = DateUtils.next(reference, weekday)

            result.timex = 'XXXX-WXX-' + str(weekday)
            future_date = value
            past_date = value

            if future_date < reference:
                future_date += timedelta(weeks=1)

            if past_date >= reference:
                past_date -= timedelta(weeks=1)

            result.future_value = future_date
            result.past_value = past_date
            result.success = True
            return result

        return result