// Cases like "from 3:30 to 5" or "between 3:30am to 6pm", at least one of the time point contains colon private DateTimeResolutionResult ParseSpecificTimeCases(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); int year = referenceTime.Year, month = referenceTime.Month, day = referenceTime.Day; var trimmedText = text.Trim().ToLower(); // Handle cases like "from 4:30 to 5" var match = config.SpecificTimeFromToRegex.Match(text); if (!match.Success) { // Handle cases like "between 5:10 and 7" match = config.SpecificTimeBetweenAndRegex.Match(text); } if (match.Success && match.Index == 0 && match.Index + match.Length == trimmedText.Length) { // Cases like "half past seven" are not handled here if (match.Groups[Constants.PrefixGroupName].Success) { return(ret); } // Cases like "4" is different with "4:00" as the Timex is different "T04H" vs "T04H00M" // Uses this invalidFlag to differentiate int beginHour; int invalidFlag = -1; int beginMinute = invalidFlag; int beginSecond = invalidFlag; int endHour; int endMinute = invalidFlag; int endSecond = invalidFlag; // Get time1 and time2 var hourGroup = match.Groups[Constants.HourGroupName]; var hourStr = hourGroup.Captures[0].Value; if (config.Numbers.ContainsKey(hourStr)) { beginHour = config.Numbers[hourStr]; } else { beginHour = int.Parse(hourStr); } hourStr = hourGroup.Captures[1].Value; if (config.Numbers.ContainsKey(hourStr)) { endHour = config.Numbers[hourStr]; } else { endHour = int.Parse(hourStr); } var time1StartIndex = match.Groups["time1"].Index; var time1EndIndex = time1StartIndex + match.Groups["time1"].Length; var time2StartIndex = match.Groups["time2"].Index; var time2EndIndex = time2StartIndex + match.Groups["time2"].Length; // Get beginMinute (if exists) and endMinute (if exists) for (int i = 0; i < match.Groups[Constants.MinuteGroupName].Captures.Count; i++) { var minuteCapture = match.Groups[Constants.MinuteGroupName].Captures[i]; if (minuteCapture.Index >= time1StartIndex && minuteCapture.Index + minuteCapture.Length <= time1EndIndex) { beginMinute = int.Parse(minuteCapture.Value); } else if (minuteCapture.Index >= time2StartIndex && minuteCapture.Index + minuteCapture.Length <= time2EndIndex) { endMinute = int.Parse(minuteCapture.Value); } } // Get beginSecond (if exists) and endSecond (if exists) for (int i = 0; i < match.Groups[Constants.SecondGroupName].Captures.Count; i++) { var secondCapture = match.Groups[Constants.SecondGroupName].Captures[i]; if (secondCapture.Index >= time1StartIndex && secondCapture.Index + secondCapture.Length <= time1EndIndex) { beginSecond = int.Parse(secondCapture.Value); } else if (secondCapture.Index >= time2StartIndex && secondCapture.Index + secondCapture.Length <= time2EndIndex) { endSecond = int.Parse(secondCapture.Value); } } // Desc here means descriptions like "am / pm / o'clock" // Get leftDesc (if exists) and rightDesc (if exists) var leftDesc = match.Groups["leftDesc"].Value; var rightDesc = match.Groups["rightDesc"].Value; for (int i = 0; i < match.Groups[Constants.DescGroupName].Captures.Count; i++) { var descCapture = match.Groups[Constants.DescGroupName].Captures[i]; if (descCapture.Index >= time1StartIndex && descCapture.Index + descCapture.Length <= time1EndIndex && string.IsNullOrEmpty(leftDesc)) { leftDesc = descCapture.Value; } else if (descCapture.Index >= time2StartIndex && descCapture.Index + descCapture.Length <= time2EndIndex && string.IsNullOrEmpty(rightDesc)) { rightDesc = descCapture.Value; } } var beginDateTime = DateObject.MinValue.SafeCreateFromValue(year, month, day, beginHour, beginMinute >= 0 ? beginMinute : 0, beginSecond >= 0 ? beginSecond : 0); var endDateTime = DateObject.MinValue.SafeCreateFromValue(year, month, day, endHour, endMinute >= 0 ? endMinute : 0, endSecond >= 0 ? endSecond : 0); var hasLeftAm = !string.IsNullOrEmpty(leftDesc) && leftDesc.ToLower().StartsWith("a"); var hasLeftPm = !string.IsNullOrEmpty(leftDesc) && leftDesc.ToLower().StartsWith("p"); var hasRightAm = !string.IsNullOrEmpty(rightDesc) && rightDesc.ToLower().StartsWith("a"); var hasRightPm = !string.IsNullOrEmpty(rightDesc) && rightDesc.ToLower().StartsWith("p"); var hasLeft = hasLeftAm || hasLeftPm; var hasRight = hasRightAm || hasRightPm; // Both time point has description like 'am' or 'pm' if (hasLeft && hasRight) { if (hasLeftAm) { if (beginHour >= Constants.HalfDayHourCount) { beginDateTime = beginDateTime.AddHours(-Constants.HalfDayHourCount); } } else { if (beginHour < Constants.HalfDayHourCount) { beginDateTime = beginDateTime.AddHours(Constants.HalfDayHourCount); } } if (hasRightAm) { if (endHour > Constants.HalfDayHourCount) { endDateTime = endDateTime.AddHours(-Constants.HalfDayHourCount); } } else { if (endHour < Constants.HalfDayHourCount) { endDateTime = endDateTime.AddHours(Constants.HalfDayHourCount); } } } else if (hasLeft || hasRight) { // one of the time point has description like 'am' or 'pm' if (hasLeftAm) { if (beginHour >= Constants.HalfDayHourCount) { beginDateTime = beginDateTime.AddHours(-Constants.HalfDayHourCount); } if (endHour < Constants.HalfDayHourCount) { if (endDateTime < beginDateTime) { endDateTime = endDateTime.AddHours(Constants.HalfDayHourCount); } } } else if (hasLeftPm) { if (beginHour < Constants.HalfDayHourCount) { beginDateTime = beginDateTime.AddHours(Constants.HalfDayHourCount); } if (endHour < Constants.HalfDayHourCount) { if (endDateTime < beginDateTime) { var span = beginDateTime - endDateTime; endDateTime = endDateTime.AddHours(span.TotalHours >= Constants.HalfDayHourCount ? 24 : Constants.HalfDayHourCount); } } } if (hasRightAm) { if (endHour >= Constants.HalfDayHourCount) { endDateTime = endDateTime.AddHours(-Constants.HalfDayHourCount); } if (beginHour < Constants.HalfDayHourCount) { if (endDateTime < beginDateTime) { beginDateTime = beginDateTime.AddHours(-Constants.HalfDayHourCount); } } } else if (hasRightPm) { if (endHour < Constants.HalfDayHourCount) { endDateTime = endDateTime.AddHours(Constants.HalfDayHourCount); } if (beginHour < Constants.HalfDayHourCount) { if (endDateTime < beginDateTime) { beginDateTime = beginDateTime.AddHours(-Constants.HalfDayHourCount); } else { var span = endDateTime - beginDateTime; if (span.TotalHours > Constants.HalfDayHourCount) { beginDateTime = beginDateTime.AddHours(Constants.HalfDayHourCount); } } } } } // No 'am' or 'pm' indicator else if (beginHour <= Constants.HalfDayHourCount && endHour <= Constants.HalfDayHourCount) { if (beginHour > endHour) { if (beginHour == Constants.HalfDayHourCount) { beginDateTime = beginDateTime.AddHours(-Constants.HalfDayHourCount); } else { endDateTime = endDateTime.AddHours(Constants.HalfDayHourCount); } } ret.Comment = Constants.Comment_AmPm; } if (endDateTime < beginDateTime) { endDateTime = endDateTime.AddHours(24); } var beginStr = FormatUtil.ShortTime(beginDateTime.Hour, beginMinute, beginSecond); var endStr = FormatUtil.ShortTime(endDateTime.Hour, endMinute, endSecond); ret.Success = true; ret.Timex = $"({beginStr},{endStr},{FormatUtil.LuisTimeSpan(endDateTime - beginDateTime)})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>( beginDateTime, endDateTime); ret.SubDateTimeEntities = new List <object>(); // In SplitDateAndTime mode, time points will be get from these SubDateTimeEntities // Cases like "from 4 to 5pm", "4" should not be treated as SubDateTimeEntity if (hasLeft || beginMinute != invalidFlag || beginSecond != invalidFlag) { var er = new ExtractResult() { Start = time1StartIndex, Length = time1EndIndex - time1StartIndex, Text = text.Substring(time1StartIndex, time1EndIndex - time1StartIndex), Type = $"{Constants.SYS_DATETIME_TIME}" }; var pr = this.config.TimeParser.Parse(er, referenceTime); ret.SubDateTimeEntities.Add(pr); } // Cases like "from 4am to 5", "5" should not be treated as SubDateTimeEntity if (hasRight || endMinute != invalidFlag || endSecond != invalidFlag) { var er = new ExtractResult { Start = time2StartIndex, Length = time2EndIndex - time2StartIndex, Text = text.Substring(time2StartIndex, time2EndIndex - time2StartIndex), Type = $"{Constants.SYS_DATETIME_TIME}" }; var pr = this.config.TimeParser.Parse(er, referenceTime); ret.SubDateTimeEntities.Add(pr); } ret.Success = true; } return(ret); }
// Handle cases like "Monday 7-9", where "7-9" can't be extracted by the TimePeriodExtractor private DateTimeResolutionResult ParsePureNumberCases(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); var trimmedText = text.Trim().ToLower(); var match = this.Config.PureNumberFromToRegex.Match(trimmedText); if (!match.Success) { match = this.Config.PureNumberBetweenAndRegex.Match(trimmedText); } if (match.Success && (match.Index == 0 || match.Index + match.Length == trimmedText.Length)) { int beginHour, endHour; ret.Comment = ParseTimePeriod(match, out beginHour, out endHour); var dateStr = string.Empty; // Parse following date var dateExtractResult = this.Config.DateExtractor.Extract(trimmedText.Replace(match.Value, ""), referenceTime); DateObject futureDate, pastDate; if (dateExtractResult.Count > 0) { var pr = this.Config.DateParser.Parse(dateExtractResult[0], referenceTime); if (pr.Value != null) { futureDate = (DateObject)((DateTimeResolutionResult)pr.Value).FutureValue; pastDate = (DateObject)((DateTimeResolutionResult)pr.Value).PastValue; dateStr = pr.TimexStr; if (((DateTimeResolutionResult)pr.Value).TimeZoneResolution != null) { ret.TimeZoneResolution = ((DateTimeResolutionResult)pr.Value).TimeZoneResolution; } } else { return(ret); } } else { return(ret); } var pastHours = endHour - beginHour; var beginTimex = TimexUtility.CombineDateAndTimeTimex(dateStr, FormatUtil.ShortTime(beginHour)); var endTimex = TimexUtility.CombineDateAndTimeTimex(dateStr, FormatUtil.ShortTime(endHour)); var durationTimex = TimexUtility.GenerateDurationTimex(endHour - beginHour, Constants.TimexHour, isLessThanDay: true); ret.Timex = TimexUtility.GenerateDateTimePeriodTimex(beginTimex, endTimex, durationTimex); ret.FutureValue = new Tuple <DateObject, DateObject>( DateObject.MinValue.SafeCreateFromValue(futureDate.Year, futureDate.Month, futureDate.Day, beginHour, 0, 0), DateObject.MinValue.SafeCreateFromValue(futureDate.Year, futureDate.Month, futureDate.Day, endHour, 0, 0)); ret.PastValue = new Tuple <DateObject, DateObject>( DateObject.MinValue.SafeCreateFromValue(pastDate.Year, pastDate.Month, pastDate.Day, beginHour, 0, 0), DateObject.MinValue.SafeCreateFromValue(pastDate.Year, pastDate.Month, pastDate.Day, endHour, 0, 0)); ret.Success = true; } return(ret); }