def parse_specific_time_of_day()

in Python/libraries/recognizers-date-time/recognizers_date_time/date_time/base_datetimeperiod.py [0:0]


    def parse_specific_time_of_day(self, source: str, reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()
        trimmed_source = source.strip()
        time_text = trimmed_source

        match = regex.search(self.config.period_time_of_day_with_date_regex, trimmed_source)
        # Extract early/late prefix from text if any
        has_early = False
        has_late = False
        if match:
            time_text = RegExpUtility.get_group(match, Constants.TIME_OF_DAY_GROUP_NAME)
            if RegExpUtility.get_group(match, Constants.COMMENT_EARLY):
                has_early = True
                result.comment = Constants.COMMENT_EARLY
                result.mod = TimeTypeConstants.EARLY_MOD
            if RegExpUtility.get_group(match, Constants.COMMENT_LATE):
                has_late = True
                result.comment = Constants.COMMENT_LATE
                result.mod = TimeTypeConstants.LATE_MOD
        else:
            match = self.config.am_desc_regex.match(trimmed_source)
            if not match:
                match = self.config.pm_desc_regex.match(trimmed_source)
            else:
                time_text = match.group()

        # handle time of day

        # Late/early only works with time of day
        # Only standard time of day (morning, afternoon, evening and night) will not directly return
        values = self.config.get_matched_time_range(time_text)
        if not values.success:
            return result

        # Modify time period if 'early' or 'late' exists
        # Since 'time of day' is defined as four hour periods
        # the first 2 hours represent early, the later 2 hours represent late
        if has_early:
            values.end_hour = values.begin_hour + 2
            if values.end_min == 59:
                values.end_min = 0
        elif has_late:
            values.begin_hour = values.begin_hour + 2

        if RegExpUtility.is_exact_match(self.config.specific_time_of_day_regex, trimmed_source, True):
            swift = self.config.get_swift_prefix(trimmed_source)
            date = (reference + timedelta(days=swift)).date()
            day = date.day
            month = date.month
            year = date.year

            result.timex = DateTimeFormatUtil.format_date(date) + values.time_str

            result.future_value = result.past_value = (DateUtils.safe_create_from_min_value(year, month, day,
                                                                                            values.begin_hour, 0, 0),
                                                       DateUtils.safe_create_from_min_value(year, month, day,
                                                                                            values.end_hour, values.end_min, values.end_min))

            result.success = True
            return result

        # Handle Date followed by morning, afternoon and morning, afternoon followed by Date
        match = self.config.period_time_of_day_with_date_regex.search(trimmed_source)

        if not match:
            match = self.config.am_desc_regex.sarch(trimmed_source)
            if not match:
                match = self.config.pm_desc_regex.search(trimmed_source)
        else:
            before_str = trimmed_source[0:match.start()].strip()
            _before_str = before_str
            trimmed_before_str = ''

            after_str = trimmed_source[match.end():].strip()
            _after_str = after_str
            trimmed_after_str = ''

            # Eliminate time period, if any
            time_period_extract_results = self.config.time_period_extractor.extract(before_str)
            if len(time_period_extract_results) > 0:
                start = time_period_extract_results[0].start
                length = time_period_extract_results[0].length
                for i in range(start, length):
                    trimmed_before_str = _before_str.replace(_before_str[start], '', 1)
                    _before_str = trimmed_before_str
                trimmed_before_str = trimmed_before_str.strip()
            else:
                time_period_extract_results = self.config.time_period_extractor.extract(after_str)
                if len(time_period_extract_results) > 0:
                    start = time_period_extract_results[0].start
                    length = time_period_extract_results[0].length
                    for i in range(start, length):
                        trimmed_after_str = _after_str.replace(_after_str[start], '', 1)
                        _before_str = trimmed_after_str
                    trimmed_after_str = trimmed_after_str.strip()

            extracted_results = self.config.date_extractor.extract((trimmed_before_str if trimmed_before_str is not '' else before_str) + ' ' + (trimmed_after_str if trimmed_after_str is not '' else after_str), reference)
            if len(extracted_results) == 0 or extracted_results[0].length < len(trimmed_before_str):
                valid = False
                if len(extracted_results) > 0 and extracted_results[0].start == 0:
                    mid_str = before_str[extracted_results[0].start + extracted_results[0].length:]
                    if mid_str.replace(',', ' '):
                        valid = True

                if not valid:
                    extracted_results = self.config.date_extractor.extract(after_str, reference)
                    if len(extracted_results) == 0 or extracted_results[0].length != len(after_str):
                        if len(extracted_results) > 0 and extracted_results[0].start + extracted_results[0].length ==\
                                len(after_str):
                            mid_str = after_str[0:extracted_results[0].start]
                            if not mid_str.replace(',', ' '):
                                valid = True
                    else:
                        valid = True
                if not valid:
                    return result

            has_specific_time_period = False
            if len(time_period_extract_results) > 0:
                time_parse_result = self.config.time_period_parser.parse(time_period_extract_results[0], reference)
                if time_parse_result:
                    period_future = (time_parse_result.value.future_value.start, time_parse_result.value.future_value.end)
                    period_past = (time_parse_result.value.past_value.start, time_parse_result.value.past_value.end)

                    if period_future == period_past:
                        values.begin_hour = period_future[0].hour
                        values.end_hour = period_future[1].hour
                    else:
                        if period_future[0].hour >= values.begin_hour or period_future[1].hour <= values.end_hour:
                            values.begin_hour = period_future[0].hour
                            values.end_hour = period_future[1].hour
                        else:
                            values.begin_hour = period_past[0].hour
                            values.end_hour = period_past[1].hour

                    has_specific_time_period = True

            parse_result = self.config.date_parser.parse(extracted_results[0], reference)
            future_date = parse_result.value.future_value
            past_date = parse_result.value.past_value

            if not has_specific_time_period:
                result.timex = parse_result.timex_str + values.time_str
            else:
                format_str = '({}T{},{}T{},PT{}H)'
                result.timex = format_str.format(parse_result.timex_str, values.begin_hour, parse_result.timex_str, values.end_hour,
                                                 values.end_hour - values.begin_hour)

            result.future_value = (DateUtils.safe_create_from_min_value(future_date.year, future_date.month,
                                                                        future_date.day, values.begin_hour, 0, 0),
                                   DateUtils.safe_create_from_min_value(future_date.year, future_date.month,
                                                                        future_date.day, values.end_hour, values.end_min, values.end_min))
            result.past_value = (DateUtils.safe_create_from_min_value(past_date.year, past_date.month,
                                                                      past_date.day, values.begin_hour, 0, 0),
                                 DateUtils.safe_create_from_min_value(past_date.year, past_date.month,
                                                                      past_date.day, values.end_hour, values.end_min, values.end_min))

            result.success = True
            return result

        return result