// 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" int beginHour; int beginMinute = Constants.InvalidMinute; int beginSecond = Constants.InvalidSecond; int endHour; int endMinute = Constants.InvalidMinute; int endSecond = Constants.InvalidSecond; // 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 = DateTimeFormatUtil.ShortTime(beginDateTime.Hour, beginMinute, beginSecond); var endStr = DateTimeFormatUtil.ShortTime(endDateTime.Hour, endMinute, endSecond); ret.Success = true; ret.Timex = $"({beginStr},{endStr},{DateTimeFormatUtil.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 != Constants.InvalidMinute || beginSecond != Constants.InvalidSecond) { 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 != Constants.InvalidMinute || endSecond != Constants.InvalidSecond) { 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); }
private DateTimeResolutionResult MergeTwoTimePoints(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); DateTimeParseResult pr1 = null, pr2 = null; bool bothHaveDates = false, beginHasDate = false, endHasDate = false; var timeExtractResults = this.Config.TimeExtractor.Extract(text, referenceTime); var dateTimeExtractResults = this.Config.DateTimeExtractor.Extract(text, referenceTime); if (dateTimeExtractResults.Count == 2) { pr1 = this.Config.DateTimeParser.Parse(dateTimeExtractResults[0], referenceTime); pr2 = this.Config.DateTimeParser.Parse(dateTimeExtractResults[1], referenceTime); bothHaveDates = true; } else if (dateTimeExtractResults.Count == 1 && timeExtractResults.Count == 2) { if (!dateTimeExtractResults[0].IsOverlap(timeExtractResults[0])) { pr1 = this.Config.TimeParser.Parse(timeExtractResults[0], referenceTime); pr2 = this.Config.DateTimeParser.Parse(dateTimeExtractResults[0], referenceTime); endHasDate = true; } else { pr1 = this.Config.DateTimeParser.Parse(dateTimeExtractResults[0], referenceTime); pr2 = this.Config.TimeParser.Parse(timeExtractResults[1], referenceTime); beginHasDate = true; } } else if (dateTimeExtractResults.Count == 1 && timeExtractResults.Count == 1) { if (timeExtractResults[0].Start < dateTimeExtractResults[0].Start) { pr1 = this.Config.TimeParser.Parse(timeExtractResults[0], referenceTime); pr2 = this.Config.DateTimeParser.Parse(dateTimeExtractResults[0], referenceTime); endHasDate = true; } else if (timeExtractResults[0].Start >= dateTimeExtractResults[0].Start + dateTimeExtractResults[0].Length) { pr1 = this.Config.DateTimeParser.Parse(dateTimeExtractResults[0], referenceTime); pr2 = this.Config.TimeParser.Parse(timeExtractResults[0], referenceTime); beginHasDate = true; } else { // If the only TimeExtractResult is part of DateTimeExtractResult, then it should not be handled in this method return(ret); } } else if (timeExtractResults.Count == 2) { // If both ends are Time. then this is a TimePeriod, not a DateTimePeriod return(ret); } else { return(ret); } if (pr1.Value == null || pr2.Value == null) { return(ret); } DateObject futureBegin = (DateObject)((DateTimeResolutionResult)pr1.Value).FutureValue, futureEnd = (DateObject)((DateTimeResolutionResult)pr2.Value).FutureValue; DateObject pastBegin = (DateObject)((DateTimeResolutionResult)pr1.Value).PastValue, pastEnd = (DateObject)((DateTimeResolutionResult)pr2.Value).PastValue; if (bothHaveDates) { if (futureBegin > futureEnd) { futureBegin = pastBegin; } if (pastEnd < pastBegin) { pastEnd = futureEnd; } } if (bothHaveDates) { ret.Timex = $"({pr1.TimexStr},{pr2.TimexStr},PT{Convert.ToInt32((futureEnd - futureBegin).TotalHours)}H)"; // Do nothing } else if (beginHasDate) { futureEnd = DateObject.MinValue.SafeCreateFromValue( futureBegin.Year, futureBegin.Month, futureBegin.Day, futureEnd.Hour, futureEnd.Minute, futureEnd.Second); pastEnd = DateObject.MinValue.SafeCreateFromValue( pastBegin.Year, pastBegin.Month, pastBegin.Day, pastEnd.Hour, pastEnd.Minute, pastEnd.Second); var dateStr = pr1.TimexStr.Split('T')[0]; var durationStr = DateTimeFormatUtil.LuisTimeSpan(futureEnd - futureBegin); ret.Timex = $"({pr1.TimexStr},{dateStr + pr2.TimexStr},{durationStr}"; } else if (endHasDate) { futureBegin = DateObject.MinValue.SafeCreateFromValue( futureEnd.Year, futureEnd.Month, futureEnd.Day, futureBegin.Hour, futureBegin.Minute, futureBegin.Second); pastBegin = DateObject.MinValue.SafeCreateFromValue( pastEnd.Year, pastEnd.Month, pastEnd.Day, pastBegin.Hour, pastBegin.Minute, pastBegin.Second); var dateStr = pr2.TimexStr.Split('T')[0]; var durationStr = DateTimeFormatUtil.LuisTimeSpan(pastEnd - pastBegin); ret.Timex = $"({dateStr + pr1.TimexStr},{pr2.TimexStr},{durationStr})"; } var ampmStr1 = ((DateTimeResolutionResult)pr1.Value).Comment; var ampmStr2 = ((DateTimeResolutionResult)pr2.Value).Comment; if (!string.IsNullOrEmpty(ampmStr1) && ampmStr1.EndsWith(Constants.Comment_AmPm) && !string.IsNullOrEmpty(ampmStr2) && ampmStr2.EndsWith(Constants.Comment_AmPm)) { ret.Comment = Constants.Comment_AmPm; } if ((this.Config.Options & DateTimeOptions.EnablePreview) != 0) { if (((DateTimeResolutionResult)pr1.Value).TimeZoneResolution != null) { ret.TimeZoneResolution = ((DateTimeResolutionResult)pr1.Value).TimeZoneResolution; } else if (((DateTimeResolutionResult)pr2.Value).TimeZoneResolution != null) { ret.TimeZoneResolution = ((DateTimeResolutionResult)pr2.Value).TimeZoneResolution; } } ret.FutureValue = new Tuple <DateObject, DateObject>(futureBegin, futureEnd); ret.PastValue = new Tuple <DateObject, DateObject>(pastBegin, pastEnd); ret.Success = true; ret.SubDateTimeEntities = new List <object> { pr1, pr2 }; return(ret); }
// Cases like "between 0730 to 0930", only this case is handled in this method private DateTimeResolutionResult ParsePureDigitNumCases(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); int year = referenceTime.Year, month = referenceTime.Month, day = referenceTime.Day; var trimmedText = text.Trim().ToLower(); var match = this.config.PureNumberBetweenAndRegex.MatchBegin(trimmedText, trim: true); if (match.Success) { // get hours var hourGroup = match.Groups[Constants.HourGroupName]; var minuteGroup = match.Groups[Constants.MinuteGroupName]; if (hourGroup.Captures.Count == 2 && minuteGroup.Captures.Count == 2) { var beginHourEndIndex = hourGroup.Captures[0].Index + hourGroup.Captures[0].Length; var beginMinuteStartIndex = minuteGroup.Captures[0].Index; var endHourEndIndex = hourGroup.Captures[1].Index + hourGroup.Captures[1].Length; var endMinuteStartIndex = minuteGroup.Captures[1].Index; // falls into the case "between 0730 to 0930" if (beginHourEndIndex == beginMinuteStartIndex && endHourEndIndex == endMinuteStartIndex) { var startHourStr = hourGroup.Captures[0].Value; var startMinuteStr = minuteGroup.Captures[0].Value; var endHourStr = hourGroup.Captures[1].Value; var endMinuteStr = minuteGroup.Captures[1].Value; if (!this.config.Numbers.TryGetValue(startHourStr, out int beginHour)) { beginHour = int.Parse(startHourStr); } if (!this.config.Numbers.TryGetValue(startMinuteStr, out int beginMinute)) { beginMinute = int.Parse(startMinuteStr); } if (!this.config.Numbers.TryGetValue(endHourStr, out int endHour)) { endHour = int.Parse(endHourStr); } if (!this.config.Numbers.TryGetValue(endMinuteStr, out int endMinute)) { endMinute = int.Parse(endMinuteStr); } var beginDateTime = DateObject.MinValue.SafeCreateFromValue(year, month, day, beginHour, beginMinute, 0); var endDateTime = DateObject.MinValue.SafeCreateFromValue(year, month, day, endHour, endMinute, 0); 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 = DateTimeFormatUtil.ShortTime(beginDateTime.Hour, beginMinute); var endStr = DateTimeFormatUtil.ShortTime(endDateTime.Hour, endMinute); ret.Timex = $"({beginStr},{endStr},{DateTimeFormatUtil.LuisTimeSpan(endDateTime - beginDateTime)})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>( beginDateTime, endDateTime); ret.Success = true; } } } return(ret); }
public static string GenerateDateTimePeriodTimex(string beginTimex, string endTimex, TimeSpan duration) { var durationTimex = DateTimeFormatUtil.LuisTimeSpan(duration); return(GenerateDateTimePeriodTimex(beginTimex, endTimex, durationTimex)); }