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
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
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
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
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
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)
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
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
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
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
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
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
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