in Python/libraries/recognizers-date-time/recognizers_date_time/date_time/base_timeperiod.py [0:0]
def parse_specific_time(self, source: str, reference: datetime) -> DateTimeResolutionResult:
result = DateTimeResolutionResult()
year = reference.year
month = reference.month
day = reference.day
source = source.strip().lower()
match = regex.search(self.config.specific_time_from_to_regex, source)
if not match:
match = regex.search(
self.config.specific_time_between_and_regex, source)
if not match or match.start() != 0:
return result
# this "from .. to .." pattern is valid if followed by a Date OR "pm"
valid = False
time1 = RegExpUtility.get_group(match, "time1")
time2 = RegExpUtility.get_group(match, "time2")
# get hours
hour_group_list = RegExpUtility.get_group_list(match, Constants.HOUR_GROUP_NAME)
hour_str = hour_group_list[0]
begin_hour = self.config.numbers.get(hour_str, None)
if not begin_hour:
begin_hour = int(hour_str)
hour_str = hour_group_list[1]
end_hour = self.config.numbers.get(hour_str, None)
if not end_hour:
end_hour = int(hour_str)
# get minutes
minute_group_list = RegExpUtility.get_group_list(match, Constants.MINUTE_GROUP_NAME)
begin_minute = end_minute = -1
if len(minute_group_list) > 1:
minute_str = minute_group_list[0]
begin_minute = self.config.numbers.get(minute_str, None)
if not begin_minute:
begin_minute = int(minute_str)
minute_str = minute_group_list[1]
end_minute = self.config.numbers.get(minute_str, None)
if not end_minute:
end_minute = int(minute_str)
elif len(minute_group_list) == 1:
minute_str = minute_group_list[0]
if minute_str in time1:
begin_minute = self.config.numbers.get(minute_str, None)
if not begin_minute:
begin_minute = int(minute_str)
elif minute_str in time2:
end_minute = self.config.numbers.get(minute_str, None)
if not end_minute:
end_minute = int(minute_str)
# parse AM/PM
left_desc: str = RegExpUtility.get_group(match, Constants.LEFT_DESC_GROUP_NAME)
right_desc: str = RegExpUtility.get_group(match, Constants.RIGHT_DESC_GROUP_NAME)
desc_capture_list = RegExpUtility.get_group_list(match, Constants.DESC_GROUP_NAME)
for desc_capture in desc_capture_list:
if desc_capture in time1 and not left_desc:
left_desc: str = desc_capture
elif desc_capture in time2 and not right_desc:
right_desc: str = desc_capture
begin_date_time = datetime(year, month, day, hour=begin_hour, minute=begin_minute if begin_minute > 0 else 0)
end_date_time = datetime(year, month, day, hour=end_hour, minute=end_minute if end_minute > 0 else 0)
has_left_am = left_desc != '' and left_desc.startswith('a')
has_left_pm = left_desc != '' and left_desc.startswith('p')
has_right_am = right_desc != '' and right_desc.startswith('a')
has_right_pm = right_desc != '' and right_desc.startswith('p')
has_left = has_left_am or has_left_pm
has_right = has_right_am or has_right_pm
# both time point has description like 'am' or 'pm'
if has_left and has_right:
if has_left_am:
if begin_hour >= 12:
begin_date_time -= timedelta(hours=12)
else:
if begin_hour < 12:
begin_date_time += timedelta(hours=12)
if has_right_am:
if end_hour > 12:
end_date_time -= timedelta(hours=12)
else:
if end_hour < 12:
end_date_time += timedelta(hours=12)
# one of the time point has description like 'am' or 'pm'
elif has_left or has_right:
if has_left_am:
if begin_hour >= 12:
begin_date_time -= timedelta(hours=12)
if end_hour < 12:
if end_date_time < begin_date_time:
end_date_time += timedelta(hours=12)
elif has_left_pm:
if begin_hour < 12:
begin_date_time += timedelta(hours=12)
if end_hour < 12:
if end_date_time < begin_date_time:
span: datetime = begin_date_time - end_date_time
end_date_time += timedelta(hours=24) if span >= timedelta(hours=12) else timedelta(hours=12)
if has_right_am:
if end_hour >= 12:
end_date_time -= timedelta(hours=12)
if begin_hour < 12:
if end_date_time < begin_date_time:
begin_date_time -= timedelta(hours=12)
elif has_right_pm:
if end_hour < 12:
end_date_time += timedelta(hours=12)
if begin_hour < 12:
if end_date_time < begin_date_time:
begin_date_time -= timedelta(hours=12)
else:
span = end_date_time - begin_date_time
if span >= timedelta(hours=12):
begin_date_time += timedelta(hours=12)
# no 'am' or 'pm' indicator
elif begin_hour <= 12 and end_hour <= 12:
if begin_date_time > end_date_time:
if begin_hour == 12:
begin_date_time -= timedelta(hours=12)
else:
end_date_time += timedelta(hours=12)
result.comment = Constants.AM_PM_GROUP_NAME
if end_date_time < begin_date_time:
end_date_time += timedelta(hours=24)
if begin_minute >= 0:
begin = f'T{begin_date_time.hour:02d}:{begin_date_time.minute:02d}'
else:
begin = f'T{begin_date_time.hour:02d}'
if end_minute >= 0:
end = f'T{end_date_time.hour:02d}:{end_date_time.minute:02d}'
else:
end = f'T{end_date_time.hour:02d}'
difference = datetime(year, month, day) + (end_date_time - begin_date_time)
if difference.minute != 0 and difference.hour != 0:
result.timex = f'({begin},{end},PT{difference.hour}H{difference.minute}M)'
elif difference.minute != 0 and difference.hour == 0:
result.timex = f'({begin},{end},PT{difference.minute}M)'
else:
result.timex = f'({begin},{end},PT{difference.hour}H)'
result.future_value = ResolutionStartEnd()
result.past_value = ResolutionStartEnd()
result.future_value.start = begin_date_time
result.future_value.end = end_date_time
result.past_value.start = result.future_value.start
result.past_value.end = result.future_value.end
result.success = True
result.sub_date_time_entities = []
# in SplitDateAndTime mode, time points will be get from these sub_date_time_entities
# cases like "from 4 to 5pm", "4" should not be trated as sub_date_time_entities
if has_left or begin_minute >= 0:
er = ExtractResult()
er.start = match.start("time1")
er.length = match.end("time1") - match.start("time1")
er.text = time1
er.type = Constants.SYS_DATETIME_TIME
pr = self.config.time_parser.parse(er, reference)
result.sub_date_time_entities.append(pr)
# cases like "from 4am to 5" "5" should not treated as sub_date_time_entities
if has_right or end_minute >= 0:
er = ExtractResult()
er.start = match.start("time2")
er.length = match.end("time2") - match.start("time2")
er.text = time2
er.type = Constants.SYS_DATETIME_TIME
pr = self.config.time_parser.parse(er, reference)
result.sub_date_time_entities.append(pr)
return result