// simple cases made by a number followed an unit private DateTimeResolutionResult ParseNumberWithUnit(string text, DateObject referenceTime) { DateTimeResolutionResult ret; if ((ret = ParseNumberSpaceUnit(text)).Success) { return(ret); } if ((ret = ParseNumberCombinedUnit(text)).Success) { return(ret); } if ((ret = ParseAnUnit(text)).Success) { return(ret); } if ((ret = DurationParsingUtil.ParseInexactNumberUnit(text, this.config)).Success) { return(ret); } return(ret); }
private static DateTimeResolutionResult GetAgoLaterResult( DateTimeParseResult durationParseResult, string afterStr, string beforeStr, System.DateTime referenceTime, IDateTimeUtilityConfiguration utilityConfiguration, AgoLaterMode mode) { var ret = new DateTimeResolutionResult(); var resultDateTime = referenceTime; var timex = durationParseResult.TimexStr; if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.MORE_THAN_MOD) { ret.Mod = Constants.MORE_THAN_MOD; } else if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.LESS_THAN_MOD) { ret.Mod = Constants.LESS_THAN_MOD; } if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.AgoRegex)) { resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime, false); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.BEFORE_MOD; } else if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.LaterRegex) || MatchingUtil.ContainsTermIndex(beforeStr, utilityConfiguration.InConnectorRegex)) { resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime, true); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.AFTER_MOD; } if (resultDateTime != referenceTime) { if (mode.Equals(AgoLaterMode.Date)) { ret.Timex = $"{FormatUtil.LuisDate(resultDateTime)}"; } else if (mode.Equals(AgoLaterMode.DateTime)) { ret.Timex = $"{FormatUtil.LuisDateTime(resultDateTime)}"; } ret.FutureValue = ret.PastValue = resultDateTime; ret.SubDateTimeEntities = new List <object> { durationParseResult }; ret.Success = true; } return(ret); }
private static DateTimeResolutionResult GetAgoLaterResult( DateTimeParseResult durationParseResult, string afterStr, string beforeStr, DateObject referenceTime, IDateTimeUtilityConfiguration utilityConfiguration, AgoLaterMode mode, SwiftDayDelegate swiftDay) { var ret = new DateTimeResolutionResult(); var resultDateTime = referenceTime; var timex = durationParseResult.TimexStr; if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.MORE_THAN_MOD) { ret.Mod = Constants.MORE_THAN_MOD; } else if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.LESS_THAN_MOD) { ret.Mod = Constants.LESS_THAN_MOD; } if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.AgoRegex)) { var match = utilityConfiguration.AgoRegex.Match(afterStr); var swift = 0; // Handle cases like "3 days before yesterday" if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), false); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.BEFORE_MOD; } else if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.LaterRegex) || MatchingUtil.ContainsTermIndex(beforeStr, utilityConfiguration.InConnectorRegex)) { var match = utilityConfiguration.LaterRegex.Match(afterStr); var swift = 0; // Handle cases like "3 days after tomorrow" if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), true); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.AFTER_MOD; } if (resultDateTime != referenceTime) { if (mode.Equals(AgoLaterMode.Date)) { ret.Timex = $"{DateTimeFormatUtil.LuisDate(resultDateTime)}"; } else if (mode.Equals(AgoLaterMode.DateTime)) { ret.Timex = $"{DateTimeFormatUtil.LuisDateTime(resultDateTime)}"; } ret.FutureValue = ret.PastValue = resultDateTime; ret.SubDateTimeEntities = new List <object> { durationParseResult }; ret.Success = true; } return(ret); }
public DateTimeParseResult Parse(ExtractResult er, DateObject refDate) { var referenceTime = refDate; var dateTimeParseResult = ParseMergedDuration(er.Text, referenceTime); if (!dateTimeParseResult.Success) { dateTimeParseResult = DurationParsingUtil.ParseInexactNumberUnit(er.Text, this.config); } if (!dateTimeParseResult.Success) { var parseResult = this.config.InternalParser.Parse(er); var unitResult = parseResult.Value as UnitValue; if (unitResult == null) { return(null); } var unitStr = unitResult.Unit; var number = string.IsNullOrEmpty(unitResult.Number) ? 1 : double.Parse(unitResult.Number, CultureInfo.InvariantCulture); dateTimeParseResult.Timex = TimexUtility.GenerateDurationTimex(number, unitStr, DurationParsingUtil.IsLessThanDay(unitStr)); dateTimeParseResult.FutureValue = dateTimeParseResult.PastValue = number * this.config.UnitValueMap[unitStr]; dateTimeParseResult.Success = true; } if (dateTimeParseResult.Success) { dateTimeParseResult.FutureResolution = new Dictionary <string, string> { { TimeTypeConstants.DURATION, dateTimeParseResult.FutureValue.ToString() }, }; dateTimeParseResult.PastResolution = new Dictionary <string, string> { { TimeTypeConstants.DURATION, dateTimeParseResult.PastValue.ToString() }, }; } if (dateTimeParseResult.Success) { var moreOrLessMatch = config.MoreOrLessRegex.Match(er.Text); if (moreOrLessMatch.Success) { if (moreOrLessMatch.Groups["less"].Success) { dateTimeParseResult.Mod = Constants.LESS_THAN_MOD; } else if (moreOrLessMatch.Groups["more"].Success) { dateTimeParseResult.Mod = Constants.MORE_THAN_MOD; } } } var ret = new DateTimeParseResult { Text = er.Text, Start = er.Start, Length = er.Length, Type = er.Type, Data = er.Data, Value = dateTimeParseResult, TimexStr = dateTimeParseResult.Timex, ResolutionStr = string.Empty, }; return(ret); }
// Parse combined patterns Duration + Date, e.g. '3 days before Monday', '4 weeks after January 15th' private DateTimeResolutionResult ParseDurationWithDate(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); var durationRes = config.DurationExtractor.Extract(text, referenceDate); foreach (var duration in durationRes) { var matches = config.UnitRegex.Matches(duration.Text); if (matches.Count > 0) { var afterStr = text.Substring((int)duration.Start + (int)duration.Length); // Check if the Duration entity is followed by "before|from|after" var connector = config.BeforeAfterRegex.MatchBegin(afterStr, trim: true); if (connector.Success) { // Parse Duration var pr = config.DurationParser.Parse(duration, referenceDate); // Parse Date if (pr.Value != null) { var dateString = afterStr.Substring(connector.Index + connector.Length).Trim(); var innerResult = ParseBasicRegexMatch(dateString, referenceDate); if (!innerResult.Success) { innerResult = ParseImplicitDate(dateString, referenceDate); } if (!innerResult.Success) { innerResult = ParseWeekdayOfMonth(dateString, referenceDate); } if (!innerResult.Success) { innerResult = ParseNumberWithMonth(dateString, referenceDate); } if (!innerResult.Success) { innerResult = ParseSingleNumber(dateString, referenceDate); } if (!innerResult.Success) { var holidayEr = new ExtractResult { Start = 0, Length = dateString.Length, Text = dateString, Type = Constants.SYS_DATETIME_DATE, Data = null, Metadata = new Metadata { IsHoliday = true }, }; innerResult = (DateTimeResolutionResult)config.HolidayParser.Parse(holidayEr, referenceDate).Value; } // Combine parsed results Duration + Date if (innerResult.Success) { var isFuture = connector.Groups["after"].Success ? true : false; DateObject date = (DateObject)innerResult.FutureValue; var resultDateTime = DurationParsingUtil.ShiftDateTime(pr.TimexStr, date, future: isFuture); ret.Timex = $"{DateTimeFormatUtil.LuisDate(resultDateTime)}"; ret.FutureValue = ret.PastValue = resultDateTime; ret.SubDateTimeEntities = new List <object> { pr }; ret.Success = true; } } } } } return(ret); }
private static DateTimeResolutionResult GetAgoLaterResult( DateTimeParseResult durationParseResult, string afterStr, string beforeStr, DateObject referenceTime, IParser numberParser, IDateTimeUtilityConfiguration utilityConfiguration, AgoLaterMode mode, SwiftDayDelegate swiftDay) { var ret = new DateTimeResolutionResult(); var resultDateTime = referenceTime; var timex = durationParseResult.TimexStr; if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.MORE_THAN_MOD) { ret.Mod = Constants.MORE_THAN_MOD; } else if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.LESS_THAN_MOD) { ret.Mod = Constants.LESS_THAN_MOD; } int swift = 0; bool isMatch = false, isLater = false; string dayStr = null; var agoLaterRegexes = new List <(Regex, string)> { (utilityConfiguration.AgoRegex, "ago"), (utilityConfiguration.LaterRegex, "later"), }; // AgoRegex and LaterRegex cases foreach (var regex in agoLaterRegexes) { // Match in afterStr if (MatchingUtil.ContainsAgoLaterIndex(afterStr, regex.Item1, inSuffix: true)) { isMatch = true; isLater = regex.Item2 == "later" ? true : false; var match = regex.Item1.Match(afterStr); dayStr = match.Groups["day"].Value; } if (utilityConfiguration.CheckBothBeforeAfter) { // Match split between beforeStr and afterStr if (string.IsNullOrEmpty(dayStr) && isMatch) { var match = regex.Item1.Match(beforeStr + " " + afterStr); dayStr = match.Groups["day"].Value; } // Match in beforeStr if (string.IsNullOrEmpty(dayStr) && MatchingUtil.ContainsAgoLaterIndex(beforeStr, regex.Item1, inSuffix: false)) { isMatch = true; isLater = regex.Item2 == "later" ? true : false; var match = regex.Item1.Match(beforeStr); dayStr = match.Groups["day"].Value; } } if (isMatch) { break; } } // InConnectorRegex cases if (!isMatch) { if (MatchingUtil.ContainsTermIndex(beforeStr, utilityConfiguration.InConnectorRegex)) { // Match in afterStr isMatch = isLater = true; var match = utilityConfiguration.LaterRegex.Match(afterStr); dayStr = match.Groups["day"].Value; } else if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.InConnectorRegex, inSuffix: true)) { // Match in beforeStr isMatch = isLater = true; var match = utilityConfiguration.LaterRegex.Match(beforeStr); dayStr = match.Groups["day"].Value; } } if (isMatch) { // Handle cases like "3 days before yesterday", "3 days after tomorrow" if (!string.IsNullOrEmpty(dayStr)) { swift = swiftDay(dayStr); } if (isLater) { var yearMatch = utilityConfiguration.SinceYearSuffixRegex.Match(afterStr); if (yearMatch.Success) { var yearString = yearMatch.Groups[Constants.YearGroupName].Value; var yearEr = new ExtractResult { Text = yearString }; var year = Convert.ToInt32((double)(numberParser.Parse(yearEr).Value ?? 0)); referenceTime = DateObject.MinValue.SafeCreateFromValue(year, 1, 1); } } resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), isLater ? true : false); ((DateTimeResolutionResult)durationParseResult.Value).Mod = isLater ? Constants.AFTER_MOD : Constants.BEFORE_MOD; } if (resultDateTime != referenceTime) { if (mode.Equals(AgoLaterMode.Date)) { ret.Timex = $"{DateTimeFormatUtil.LuisDate(resultDateTime)}"; } else if (mode.Equals(AgoLaterMode.DateTime)) { ret.Timex = $"{DateTimeFormatUtil.LuisDateTime(resultDateTime)}"; } ret.FutureValue = ret.PastValue = resultDateTime; ret.SubDateTimeEntities = new List <object> { durationParseResult }; ret.Success = true; } return(ret); }
// Handle cases like "三天前" "Three days ago" private DateTimeResolutionResult ParserDurationWithAgoAndLater(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); var numStr = string.Empty; var unitStr = string.Empty; var durationRes = this.config.DurationExtractor.Extract(text, referenceDate); if (durationRes.Count > 0) { var match = this.config.UnitRegex.Match(text); if (match.Success) { var suffix = text.Substring((int)durationRes[0].Start + (int)durationRes[0].Length).Trim(); var srcUnit = match.Groups["unit"].Value; var numberStr = text.Substring((int)durationRes[0].Start, match.Index - (int)durationRes[0].Start).Trim(); var unitMatch = this.config.DurationRelativeDurationUnitRegex.Match(text); // set the inexact number "数" (few) to 3 for now var number = numberStr.Equals(unitMatch.Groups["few"].Value, StringComparison.Ordinal) ? 3 : ConvertCJKToNum(numberStr); if (!numberStr.Equals(unitMatch.Groups["few"].Value, StringComparison.Ordinal)) { if (suffix.Equals(unitMatch.Value, StringComparison.Ordinal)) { var pr = this.config.DurationParser.Parse(durationRes[0], referenceDate); var future = suffix.Equals(unitMatch.Groups["later"].Value, StringComparison.Ordinal); int swift = 0; if (pr != null) { var resultDateTime = DurationParsingUtil.ShiftDateTime(pr.TimexStr, referenceDate.AddDays(swift), future); ret.Timex = $"{DateTimeFormatUtil.LuisDate(resultDateTime)}"; ret.FutureValue = ret.PastValue = resultDateTime; ret.Success = true; return(ret); } } } if (this.config.UnitMap.ContainsKey(srcUnit)) { unitStr = this.config.UnitMap[srcUnit]; ret.Timex = TimexUtility.GenerateDurationTimex(number, unitStr, DurationParsingUtil.IsLessThanDay(unitStr)); DateObject date = Constants.InvalidDate; var beforeMatch = this.config.BeforeRegex.Match(suffix); if (beforeMatch.Success && suffix.StartsWith(beforeMatch.Value, StringComparison.Ordinal)) { date = DurationParsingUtil.ShiftDateTime(ret.Timex, referenceDate, future: false); } var afterMatch = this.config.AfterRegex.Match(suffix); if (afterMatch.Success && suffix.StartsWith(afterMatch.Value, StringComparison.Ordinal)) { date = DurationParsingUtil.ShiftDateTime(ret.Timex, referenceDate, future: true); } if (date != Constants.InvalidDate) { ret.Timex = $"{DateTimeFormatUtil.LuisDate(date)}"; ret.FutureValue = ret.PastValue = date; ret.Success = true; return(ret); } } } } return(ret); }
// handle cases like "5分钟前", "1小时以后" private DateTimeResolutionResult ParserDurationWithAgoAndLater(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); var durationRes = this.config.DurationExtractor.Extract(text, referenceDate); if (durationRes.Count > 0) { var matchAgoLater = this.config.AgoLaterRegex.Match(text); if (matchAgoLater.Success) { var pr = config.DurationParser.Parse(durationRes[0], referenceDate); var isFuture = matchAgoLater.Groups[Constants.LaterGroupName].Success; var timex = pr.TimexStr; var resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceDate, future: isFuture); ret.Timex = $"{DateTimeFormatUtil.LuisDateTime(resultDateTime)}"; ret.FutureValue = ret.PastValue = resultDateTime; ret.SubDateTimeEntities = new List <object> { pr }; ret.Success = true; return(ret); } var match = this.config.DateTimePeriodUnitRegex.Match(text); if (match.Success) { var suffix = text.Substring((int)durationRes[0].Start + (int)durationRes[0].Length).Trim(); var srcUnit = match.Groups[Constants.UnitGroupName].Value; var numberStr = text.Substring((int)durationRes[0].Start, match.Index - (int)durationRes[0].Start).Trim(); var number = ConvertCJKToNum(numberStr); if (this.config.UnitMap.ContainsKey(srcUnit)) { var unitStr = this.config.UnitMap[srcUnit]; var beforeMatch = this.config.BeforeRegex.Match(suffix); if (beforeMatch.Success && suffix.StartsWith(beforeMatch.Value, StringComparison.InvariantCulture)) { DateObject date; switch (unitStr) { case Constants.TimexHour: date = referenceDate.AddHours(-number); break; case Constants.TimexMinute: date = referenceDate.AddMinutes(-number); break; case Constants.TimexSecond: date = referenceDate.AddSeconds(-number); break; default: return(ret); } ret.Timex = $"{DateTimeFormatUtil.LuisDate(date)}"; ret.FutureValue = ret.PastValue = date; ret.Success = true; return(ret); } var afterMatch = this.config.AfterRegex.Match(suffix); if (afterMatch.Success && suffix.StartsWith(afterMatch.Value, StringComparison.Ordinal)) { DateObject date; switch (unitStr) { case Constants.TimexHour: date = referenceDate.AddHours(number); break; case Constants.TimexMinute: date = referenceDate.AddMinutes(number); break; case Constants.TimexSecond: date = referenceDate.AddSeconds(number); break; default: return(ret); } ret.Timex = $"{DateTimeFormatUtil.LuisDate(date)}"; ret.FutureValue = ret.PastValue = date; ret.Success = true; return(ret); } } } } return(ret); }
private List <ExtractResult> MergeMultipleDuration(string text, List <ExtractResult> extractorResults) { if (extractorResults.Count <= 1) { return(extractorResults); } var unitMap = this.config.UnitMap; var unitValueMap = this.config.UnitValueMap; var unitRegex = this.config.DurationUnitRegex; List <ExtractResult> results = new List <ExtractResult>(); List <List <ExtractResult> > separateResults = new List <List <ExtractResult> >(); var firstExtractionIndex = 0; var timeUnit = 0; var totalUnit = 0; while (firstExtractionIndex < extractorResults.Count) { string curUnit = null; var unitMatch = unitRegex.Match(extractorResults[firstExtractionIndex].Text); if (unitMatch.Success && unitMap.ContainsKey(unitMatch.Groups["unit"].ToString())) { curUnit = unitMatch.Groups["unit"].ToString(); totalUnit++; if (DurationParsingUtil.IsTimeDurationUnit(unitMap[curUnit])) { timeUnit++; } } if (string.IsNullOrEmpty(curUnit)) { firstExtractionIndex++; continue; } // Add extraction to list of separate results (needed in case the extractions should not be merged) List <ExtractResult> separateList = new List <ExtractResult>() { extractorResults[firstExtractionIndex] }; var secondExtractionIndex = firstExtractionIndex + 1; while (secondExtractionIndex < extractorResults.Count) { var valid = false; var midStrBegin = extractorResults[secondExtractionIndex - 1].Start + extractorResults[secondExtractionIndex - 1].Length ?? 0; var midStrEnd = extractorResults[secondExtractionIndex].Start ?? 0; var midStr = text.Substring(midStrBegin, midStrEnd - midStrBegin); var match = this.config.DurationConnectorRegex.Match(midStr); if (match.Success) { unitMatch = unitRegex.Match(extractorResults[secondExtractionIndex].Text); if (unitMatch.Success && unitMap.ContainsKey(unitMatch.Groups["unit"].ToString())) { var nextUnitStr = unitMatch.Groups["unit"].ToString(); if (unitValueMap[nextUnitStr] != unitValueMap[curUnit]) { valid = true; if (unitValueMap[nextUnitStr] < unitValueMap[curUnit]) { curUnit = nextUnitStr; } } totalUnit++; if (DurationParsingUtil.IsTimeDurationUnit(unitMap[nextUnitStr])) { timeUnit++; } } } if (!valid) { break; } // Add extraction to list of separate results (needed in case the extractions should not be merged) separateList.Add(extractorResults[secondExtractionIndex]); secondExtractionIndex++; } if (secondExtractionIndex - 1 > firstExtractionIndex) { var node = new ExtractResult(); node.Start = extractorResults[firstExtractionIndex].Start; node.Length = extractorResults[secondExtractionIndex - 1].Start + extractorResults[secondExtractionIndex - 1].Length - node.Start; node.Text = text.Substring(node.Start ?? 0, node.Length ?? 0); node.Type = extractorResults[firstExtractionIndex].Type; // Add multiple duration type to extract result string type = Constants.MultipleDuration_DateTime; // Default type if (timeUnit == totalUnit) { type = Constants.MultipleDuration_Time; } else if (timeUnit == 0) { type = Constants.MultipleDuration_Date; } node.Data = type; results.Add(node); timeUnit = 0; totalUnit = 0; } else { results.Add(extractorResults[firstExtractionIndex]); } // Add list of separate extractions to separateResults, so that there is a 1 to 1 correspondence // between results (list of merged extractions) and separateResults (list of unmerged extractions) separateResults.Add(separateList); firstExtractionIndex = secondExtractionIndex; } // If the first and last elements of a group of contiguous extractions are both preceded/followed by modifiers, // they should not be merged, e.g. "last 2 weeks and 3 days ago" for (int i = results.Count - 1; i >= 0; i--) { var start = (int)results[i].Start; var end = start + (int)results[i].Length; var beforeStr = text.Substring(0, start); var afterStr = text.Substring(end); var beforeMod = this.config.ModPrefixRegex.MatchEnd(beforeStr, trim: true); var afterMod = this.config.ModSuffixRegex.MatchBegin(afterStr, trim: true); if (beforeMod.Success && afterMod.Success) { results.RemoveAt(i); results.InsertRange(i, separateResults[i]); } } return(results); }
private bool TryGetResultFromRegex(Regex regex, string text, string numStr, out DateTimeResolutionResult ret) { ret = new DateTimeResolutionResult(); var match = regex.Match(text); if (match.Success) { var srcUnit = match.Groups["unit"].Value; if (this.config.UnitValueMap.ContainsKey(srcUnit)) { var unitStr = this.config.UnitMap[srcUnit]; var numVal = double.Parse(numStr, CultureInfo.InvariantCulture); ret.Timex = TimexUtility.GenerateDurationTimex(numVal, unitStr, DurationParsingUtil.IsLessThanDay(unitStr)); ret.FutureValue = ret.PastValue = numVal * this.config.UnitValueMap[srcUnit]; ret.Success = true; } } return(match.Success); }
// handle cases that don't contain numbers private DateTimeResolutionResult ParseImplicitDuration(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); // handle "all day" "all year" if (TryGetResultFromRegex(config.AllDateUnitRegex, text, "1", out var result)) { ret = result; } // handle "half day", "half year" if (TryGetResultFromRegex(config.HalfDateUnitRegex, text, "0.5", out result)) { ret = result; } // handle single duration unit, it is filtered in the extraction that there is a relative word in advance if (TryGetResultFromRegex(config.FollowedUnit, text, "1", out result)) { ret = result; } // handle "during/for the day/week/month/year" if ((config.Options & DateTimeOptions.CalendarMode) != 0 && TryGetResultFromRegex(config.DuringRegex, text, "1", out result)) { ret = result; } else { // handle cases like "the hour", which are special durations always not in CalendarMode if ((this.config.Options & DateTimeOptions.CalendarMode) == 0) { var regex = this.config.PrefixArticleRegex; if (regex != null) { var match = RegExpUtility.MatchBegin(regex, text, false); if (match.Success) { var srcUnit = text.Substring(match.Length); if (this.config.UnitValueMap.ContainsKey(srcUnit)) { var numStr = "1"; var unitStr = this.config.UnitMap[srcUnit]; var numVal = double.Parse(numStr, CultureInfo.InvariantCulture); ret.Timex = TimexUtility.GenerateDurationTimex(numVal, unitStr, DurationParsingUtil.IsLessThanDay(unitStr)); ret.FutureValue = ret.PastValue = numVal * this.config.UnitValueMap[srcUnit]; ret.Success = true; } } } } } return(ret); }
private DateTimeResolutionResult ParseAnUnit(string text) { var ret = new DateTimeResolutionResult(); var suffixStr = text; var match = this.config.AnUnitRegex.Match(text); if (!match.Success) { match = this.config.HalfDateUnitRegex.Match(text); } if (match.Success) { var numVal = match.Groups["half"].Success ? 0.5 : 1; numVal = match.Groups["quarter"].Success ? 0.25 : numVal; numVal = match.Groups["threequarter"].Success ? 0.75 : numVal; numVal += ParseNumberWithUnitAndSuffix(suffixStr); var srcUnit = match.Groups["unit"].Value; if (this.config.UnitMap.ContainsKey(srcUnit)) { var unitStr = this.config.UnitMap[srcUnit]; ret.Timex = TimexUtility.GenerateDurationTimex(numVal, unitStr, DurationParsingUtil.IsLessThanDay(unitStr)); ret.FutureValue = ret.PastValue = numVal * this.config.UnitValueMap[srcUnit]; ret.Success = true; } else if (match.Groups[Constants.BusinessDayGroupName].Success) { ret.Timex = TimexUtility.GenerateDurationTimex(numVal, Constants.TimexBusinessDay, false); // The line below was containing this.config.UnitValueMap[srcUnit.Split()[1]] // it was updated to accommodate single word "business day" expressions. ret.FutureValue = ret.PastValue = numVal * this.config.UnitValueMap[srcUnit.Split()[srcUnit.Split().Length - 1]]; ret.Success = true; } } return(ret); }
private DateTimeResolutionResult ParseNumberCombinedUnit(string text) { var ret = new DateTimeResolutionResult(); var suffixStr = text; // if there are NO spaces between number and unit var match = this.config.NumberCombinedWithUnit.Match(text); if (match.Success) { var numVal = double.Parse(match.Groups["num"].Value, CultureInfo.InvariantCulture) + ParseNumberWithUnitAndSuffix(suffixStr); var srcUnit = match.Groups["unit"].Value; if (this.config.UnitMap.ContainsKey(srcUnit)) { var unitStr = this.config.UnitMap[srcUnit]; if (numVal > 1000 && (unitStr.Equals(Constants.TimexYear, StringComparison.Ordinal) || unitStr.Equals(Constants.TimexMonthFull, StringComparison.Ordinal) || unitStr.Equals(Constants.TimexWeek, StringComparison.Ordinal))) { return(ret); } ret.Timex = TimexUtility.GenerateDurationTimex(numVal, unitStr, DurationParsingUtil.IsLessThanDay(unitStr)); ret.FutureValue = ret.PastValue = numVal * this.config.UnitValueMap[srcUnit]; ret.Success = true; return(ret); } } return(ret); }
private DateTimeResolutionResult ParseNumberSpaceUnit(string text) { var ret = new DateTimeResolutionResult(); var suffixStr = text; // if there are spaces between number and unit var ers = ExtractNumbersBeforeUnit(text); if (ers.Count == 1) { var pr = this.config.NumberParser.Parse(ers[0]); // followed unit: {num} (<followed unit>and a half hours) var srcUnit = string.Empty; var noNum = text.Substring(ers[0].Start + ers[0].Length ?? 0).Trim(); var match = this.config.FollowedUnit.Match(noNum); if (match.Success) { srcUnit = match.Groups["unit"].Value; suffixStr = match.Groups[Constants.SuffixGroupName].Value; // check also beforeStr for "and an half" if (this.config.CheckBothBeforeAfter && string.IsNullOrEmpty(suffixStr)) { noNum = text.Substring(0, (int)ers[0].Start).Trim(); var prefixMatch = this.config.SuffixAndRegex.Match(noNum); if (prefixMatch.Success) { suffixStr = prefixMatch.Groups[Constants.SuffixGroupName].Value; } } } if (match.Success && match.Groups[Constants.BusinessDayGroupName].Success) { var numVal = int.Parse(pr.Value.ToString(), CultureInfo.InvariantCulture); ret.Timex = TimexUtility.GenerateDurationTimex(numVal, Constants.TimexBusinessDay, false); // The line below was containing this.config.UnitValueMap[srcUnit.Split()[1]] // it was updated to accommodate single word "business day" expressions. ret.FutureValue = ret.PastValue = numVal * this.config.UnitValueMap[srcUnit.Split()[srcUnit.Split().Length - 1]]; ret.Success = true; return(ret); } if (this.config.UnitMap.TryGetValue(srcUnit, out var unitStr)) { // First try to parse combined expression 'num + suffix' double numVal; var combStr = pr.Text + " " + suffixStr; if (this.config.DoubleNumbers.ContainsKey(combStr)) { numVal = ParseNumberWithUnitAndSuffix(combStr); } else { numVal = double.Parse(pr.Value.ToString(), CultureInfo.InvariantCulture) + ParseNumberWithUnitAndSuffix(suffixStr); } ret.Timex = TimexUtility.GenerateDurationTimex(numVal, unitStr, DurationParsingUtil.IsLessThanDay(unitStr)); ret.FutureValue = ret.PastValue = numVal * this.config.UnitValueMap[srcUnit]; ret.Success = true; return(ret); } } return(ret); }
private List <ExtractResult> MergeMultipleDuration(string text, List <ExtractResult> extractorResults) { if (extractorResults.Count <= 1) { return(extractorResults); } var unitMap = this.config.UnitMap; var unitValueMap = this.config.UnitValueMap; var unitRegex = this.config.DurationUnitRegex; List <ExtractResult> ret = new List <ExtractResult>(); var firstExtractionIndex = 0; var timeUnit = 0; var totalUnit = 0; while (firstExtractionIndex < extractorResults.Count) { string curUnit = null; var unitMatch = unitRegex.Match(extractorResults[firstExtractionIndex].Text); if (unitMatch.Success && unitMap.ContainsKey(unitMatch.Groups["unit"].ToString())) { curUnit = unitMatch.Groups["unit"].ToString(); totalUnit++; if (DurationParsingUtil.IsTimeDurationUnit(unitMap[curUnit])) { timeUnit++; } } if (string.IsNullOrEmpty(curUnit)) { firstExtractionIndex++; continue; } var secondExtractionIndex = firstExtractionIndex + 1; while (secondExtractionIndex < extractorResults.Count) { var valid = false; var midStrBegin = extractorResults[secondExtractionIndex - 1].Start + extractorResults[secondExtractionIndex - 1].Length ?? 0; var midStrEnd = extractorResults[secondExtractionIndex].Start ?? 0; if (midStrBegin > midStrEnd) { return(extractorResults); } var midStr = text.Substring(midStrBegin, midStrEnd - midStrBegin); var match = this.config.DurationConnectorRegex.Match(midStr); if (match.Success) { unitMatch = unitRegex.Match(extractorResults[secondExtractionIndex].Text); if (unitMatch.Success && unitMap.ContainsKey(unitMatch.Groups["unit"].ToString())) { var nextUnitStr = unitMatch.Groups["unit"].ToString(); if (unitValueMap[unitMap[nextUnitStr]] != unitValueMap[unitMap[curUnit]]) { valid = true; if (unitValueMap[unitMap[nextUnitStr]] < unitValueMap[unitMap[curUnit]]) { curUnit = nextUnitStr; } } totalUnit++; if (DurationParsingUtil.IsTimeDurationUnit(unitMap[nextUnitStr])) { timeUnit++; } } } if (!valid) { break; } secondExtractionIndex++; } if (secondExtractionIndex - 1 > firstExtractionIndex) { var node = new ExtractResult(); node.Start = extractorResults[firstExtractionIndex].Start; node.Length = extractorResults[secondExtractionIndex - 1].Start + extractorResults[secondExtractionIndex - 1].Length - node.Start; node.Text = text.Substring(node.Start ?? 0, node.Length ?? 0); node.Type = extractorResults[firstExtractionIndex].Type; // Add multiple duration type to extract result string type = Constants.MultipleDuration_DateTime; // Default type if (timeUnit == totalUnit) { type = Constants.MultipleDuration_Time; } else if (timeUnit == 0) { type = Constants.MultipleDuration_Date; } node.Data = type; ret.Add(node); timeUnit = 0; totalUnit = 0; } else { ret.Add(extractorResults[firstExtractionIndex]); } firstExtractionIndex = secondExtractionIndex; } return(ret); }
// match several other cases // including '今天', '后天', '十三日' protected DateTimeResolutionResult ParseImplicitDate(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); // handle "十二日" "明年这个月三日" "本月十一日" var match = this.config.SpecialDate.MatchExact(text, trim: true); if (match.Success) { var yearStr = match.Groups["thisyear"].Value; var monthStr = match.Groups["thismonth"].Value; var dayStr = match.Groups["day"].Value; int month = referenceDate.Month, year = referenceDate.Year; var day = this.config.DayOfMonth[dayStr]; bool hasYear = false, hasMonth = false; if (!string.IsNullOrEmpty(monthStr)) { hasMonth = true; if (this.config.NextRe.Match(monthStr).Success) { month++; if (month == Constants.MaxMonth + 1) { month = Constants.MinMonth; year++; } } else if (this.config.LastRe.Match(monthStr).Success) { month--; if (month == Constants.MinMonth - 1) { month = Constants.MaxMonth; year--; } } if (!string.IsNullOrEmpty(yearStr)) { hasYear = true; if (this.config.NextRe.Match(yearStr).Success) { ++year; } else if (this.config.LastRe.Match(yearStr).Success) { --year; } } } ret.Timex = DateTimeFormatUtil.LuisDate(hasYear ? year : -1, hasMonth ? month : -1, day); DateObject futureDate, pastDate; if (day > DateObjectExtension.GetMonthMaxDay(year, month)) { var futureMonth = month + 1; var pastMonth = month - 1; var futureYear = year; var pastYear = year; if (futureMonth == Constants.MaxMonth + 1) { futureMonth = Constants.MinMonth; futureYear = year++; } if (pastMonth == Constants.MinMonth - 1) { pastMonth = Constants.MaxMonth; pastYear = year--; } var isFutureValid = DateObjectExtension.IsValidDate(futureYear, futureMonth, day); var isPastValid = DateObjectExtension.IsValidDate(pastYear, pastMonth, day); if (isFutureValid && isPastValid) { futureDate = DateObject.MinValue.SafeCreateFromValue(futureYear, futureMonth, day); pastDate = DateObject.MinValue.SafeCreateFromValue(pastYear, pastMonth, day); } else if (isFutureValid && !isPastValid) { futureDate = pastDate = DateObject.MinValue.SafeCreateFromValue(futureYear, futureMonth, day); } else if (!isFutureValid && !isPastValid) { futureDate = pastDate = DateObject.MinValue.SafeCreateFromValue(pastYear, pastMonth, day); } else { // Fall back to normal cases, might lead to resolution failure // TODO: Ideally, this failure should be filtered out in extract phase futureDate = pastDate = DateObject.MinValue.SafeCreateFromValue(year, month, day); } } else { futureDate = DateObject.MinValue.SafeCreateFromValue(year, month, day); pastDate = DateObject.MinValue.SafeCreateFromValue(year, month, day); if (!hasMonth) { if (futureDate < referenceDate) { if (IsValidDate(year, month + 1, day)) { futureDate = futureDate.AddMonths(1); } } if (pastDate >= referenceDate) { if (IsValidDate(year, month - 1, day)) { pastDate = pastDate.AddMonths(-1); } else if (DateContext.IsFeb29th(year, month - 1, day)) { pastDate = pastDate.AddMonths(-2); } } } else if (!hasYear) { if (futureDate < referenceDate) { if (IsValidDate(year + 1, month, day)) { futureDate = futureDate.AddYears(1); } } if (pastDate >= referenceDate) { if (IsValidDate(year - 1, month, day)) { pastDate = pastDate.AddYears(-1); } } } } ret.FutureValue = futureDate; ret.PastValue = pastDate; ret.Success = true; return(ret); } // handle cases like "昨日", "明日", "大后天" match = this.config.SpecialDayRegex.MatchExact(text, trim: true); if (match.Success) { var value = referenceDate.AddDays(this.config.GetSwiftDay(match.Value)); ret.Timex = DateTimeFormatUtil.LuisDate(value); ret.FutureValue = ret.PastValue = DateObject.MinValue.SafeCreateFromValue(value.Year, value.Month, value.Day); ret.Success = true; return(ret); } // Handle "今から2日曜日" (2 Sundays from now) var exactMatch = this.config.SpecialDayWithNumRegex.MatchExact(text, trim: true); if (exactMatch.Success) { var numErs = this.config.IntegerExtractor.Extract(text); var weekdayStr = exactMatch.Groups["weekday"].Value; if (!string.IsNullOrEmpty(weekdayStr) && numErs.Count > 0) { var num = Convert.ToInt32((double)(this.config.NumberParser.Parse(numErs[0]).Value ?? 0)); var value = referenceDate; // Check whether the determined day of this week has passed. if (value.DayOfWeek > (DayOfWeek)this.config.DayOfWeek[weekdayStr]) { num--; } while (num-- > 0) { value = value.Next((DayOfWeek)this.config.DayOfWeek[weekdayStr]); } ret.Timex = DateTimeFormatUtil.LuisDate(value); ret.FutureValue = ret.PastValue = DateObject.MinValue.SafeCreateFromValue(value.Year, value.Month, value.Day); ret.Success = true; return(ret); } } // handle "明日から3週間" (3 weeks from tomorrow) var durationResult = this.config.DurationExtractor.Extract(text, referenceDate); var unitMatch = this.config.DurationRelativeDurationUnitRegex.Match(text); var isWithin = this.config.DurationRelativeDurationUnitRegex.MatchEnd(text, trim: true).Groups[Constants.WithinGroupName].Success; if ((exactMatch.Success || isWithin) && unitMatch.Success && (durationResult.Count > 0) && string.IsNullOrEmpty(unitMatch.Groups["few"].Value)) { var pr = this.config.DurationParser.Parse(durationResult[0], referenceDate); var dayStr = unitMatch.Groups["later"].Value; var future = true; int swift = 0; if (pr != null) { if (!string.IsNullOrEmpty(dayStr)) { swift = this.config.GetSwiftDay(dayStr); } var resultDateTime = DurationParsingUtil.ShiftDateTime(pr.TimexStr, referenceDate.AddDays(swift), future); ret.Timex = $"{DateTimeFormatUtil.LuisDate(resultDateTime)}"; ret.FutureValue = ret.PastValue = resultDateTime; ret.Success = true; return(ret); } } if (!ret.Success) { ret = MatchWeekdayAndDay(text, referenceDate); } if (!ret.Success) { ret = MatchThisWeekday(text, referenceDate); } if (!ret.Success) { ret = MatchNextWeekday(text, referenceDate); } if (!ret.Success) { ret = MatchLastWeekday(text, referenceDate); } if (!ret.Success) { ret = MatchWeekdayAlone(text, referenceDate); } return(ret); }
private DateTimeResolutionResult ParseDuration(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); DateObject beginDate; var endDate = beginDate = referenceDate; string timex = string.Empty; bool restNowSunday = false; var ers = config.DurationExtractor.Extract(text, referenceDate); if (ers.Count == 1) { var pr = config.DurationParser.Parse(ers[0]); var beforeStr = text.Substring(0, pr.Start ?? 0).Trim().ToLowerInvariant(); var afterStr = text.Substring((pr.Start ?? 0) + (pr.Length ?? 0)).Trim().ToLowerInvariant(); var mod = ""; if (pr.Value != null) { var durationResult = (DateTimeResolutionResult)pr.Value; if (string.IsNullOrEmpty(durationResult.Timex)) { return(ret); } var prefixMatch = config.PastRegex.Match(beforeStr); if (prefixMatch.Success) { mod = TimeTypeConstants.beforeMod; beginDate = DurationParsingUtil.ShiftDateTime(durationResult.Timex, endDate, false); } else { var suffixMatch = config.PastRegex.Match(afterStr); if (suffixMatch.Success) { mod = TimeTypeConstants.beforeMod; beginDate = DurationParsingUtil.ShiftDateTime(durationResult.Timex, endDate, false); } } prefixMatch = config.FutureRegex.Match(beforeStr); if (prefixMatch.Success && prefixMatch.Length == beforeStr.Length) { mod = TimeTypeConstants.afterMod; // For future the beginDate should add 1 first beginDate = referenceDate.AddDays(1); endDate = DurationParsingUtil.ShiftDateTime(durationResult.Timex, beginDate, true); } // Handle the "in two weeks" case which means the second week prefixMatch = config.InConnectorRegex.Match(beforeStr); if (prefixMatch.Success && prefixMatch.Length == beforeStr.Length && !DurationParsingUtil.IsMultipleDuration(durationResult.Timex)) { mod = TimeTypeConstants.afterMod; beginDate = referenceDate.AddDays(1); endDate = DurationParsingUtil.ShiftDateTime(durationResult.Timex, beginDate, true); // Change the duration value and the beginDate var unit = durationResult.Timex.Substring(durationResult.Timex.Length - 1); durationResult.Timex = "P1" + unit; beginDate = DurationParsingUtil.ShiftDateTime(durationResult.Timex, endDate, false); } if (!string.IsNullOrEmpty(mod)) { ((DateTimeResolutionResult)pr.Value).Mod = mod; } timex = durationResult.Timex; ret.SubDateTimeEntities = new List <object> { pr }; } } // Parse "rest of" var match = this.config.RestOfDateRegex.Match(text); if (match.Success) { var durationStr = match.Groups["duration"].Value; var durationUnit = this.config.UnitMap[durationStr]; switch (durationUnit) { case "W": var diff = 7 - (((int)beginDate.DayOfWeek) == 0? 7: (int)beginDate.DayOfWeek); endDate = beginDate.AddDays(diff); timex = "P" + diff + "D"; if (diff == 0) { restNowSunday = true; } break; case "MON": endDate = DateObject.MinValue.SafeCreateFromValue(beginDate.Year, beginDate.Month, 1); endDate = endDate.AddMonths(1).AddDays(-1); diff = endDate.Day - beginDate.Day + 1; timex = "P" + diff + "D"; break; case "Y": endDate = DateObject.MinValue.SafeCreateFromValue(beginDate.Year, 12, 1); endDate = endDate.AddMonths(1).AddDays(-1); diff = endDate.DayOfYear - beginDate.DayOfYear + 1; timex = "P" + diff + "D"; break; } } if (!beginDate.Equals(endDate) || restNowSunday) { endDate = InclusiveEndPeriod ? endDate.AddDays(-1) : endDate; ret.Timex = $"({FormatUtil.LuisDate(beginDate)},{FormatUtil.LuisDate(endDate)},{timex})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate); ret.Success = true; return(ret); } return(ret); }
private static DateTimeResolutionResult GetAgoLaterResult( DateTimeParseResult durationParseResult, string afterStr, string beforeStr, DateObject referenceTime, IParser numberParser, IDateTimeUtilityConfiguration utilityConfiguration, AgoLaterMode mode, SwiftDayDelegate swiftDay) { var ret = new DateTimeResolutionResult(); var resultDateTime = referenceTime; var timex = durationParseResult.TimexStr; if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.MORE_THAN_MOD) { ret.Mod = Constants.MORE_THAN_MOD; } else if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.LESS_THAN_MOD) { ret.Mod = Constants.LESS_THAN_MOD; } if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.AgoRegex)) { var match = utilityConfiguration.AgoRegex.Match(afterStr); var swift = 0; // Handle cases like "3 days before yesterday" if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } else if (utilityConfiguration.CheckBothBeforeAfter && match.Success && !MatchingUtil.ContainsAgoLaterIndexInBeforeString(beforeStr, utilityConfiguration.AgoRegex)) { match = utilityConfiguration.AgoRegex.Match(beforeStr + " " + afterStr); if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } } resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), false); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.BEFORE_MOD; } else if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.ContainsAgoLaterIndexInBeforeString(beforeStr, utilityConfiguration.AgoRegex)) { var match = utilityConfiguration.AgoRegex.Match(beforeStr); var swift = 0; // Handle cases like "3 days before yesterday" if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), false); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.BEFORE_MOD; } else if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.LaterRegex) || MatchingUtil.ContainsTermIndex(beforeStr, utilityConfiguration.InConnectorRegex) || (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.ContainsAgoLaterIndexInBeforeString(beforeStr, utilityConfiguration.LaterRegex))) { var match = utilityConfiguration.LaterRegex.Match(afterStr); var swift = 0; if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.ContainsAgoLaterIndexInBeforeString(beforeStr, utilityConfiguration.LaterRegex) && string.IsNullOrEmpty(match.Groups["day"].Value)) { match = utilityConfiguration.LaterRegex.Match(beforeStr); } // Handle cases like "3 days after tomorrow" if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } var yearMatch = utilityConfiguration.SinceYearSuffixRegex.Match(afterStr); if (yearMatch.Success) { var yearString = yearMatch.Groups[Constants.YearGroupName].Value; var yearEr = new ExtractResult { Text = yearString }; var year = Convert.ToInt32((double)(numberParser.Parse(yearEr).Value ?? 0)); referenceTime = DateObject.MinValue.SafeCreateFromValue(year, 1, 1); } resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), true); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.AFTER_MOD; } else if (utilityConfiguration.CheckBothBeforeAfter && (MatchingUtil.ContainsAgoLaterIndexInBeforeString(beforeStr, utilityConfiguration.LaterRegex) || MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.InConnectorRegex) || MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.LaterRegex))) { // Check also beforeStr var match = utilityConfiguration.LaterRegex.Match(beforeStr); var swift = 0; if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.LaterRegex) && string.IsNullOrEmpty(match.Groups["day"].Value)) { match = utilityConfiguration.LaterRegex.Match(beforeStr); } // Handle cases like "3 days after tomorrow" if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } var yearMatch = utilityConfiguration.SinceYearSuffixRegex.Match(beforeStr); if (yearMatch.Success) { var yearString = yearMatch.Groups[Constants.YearGroupName].Value; var yearEr = new ExtractResult { Text = yearString }; var year = Convert.ToInt32((double)(numberParser.Parse(yearEr).Value ?? 0)); referenceTime = DateObject.MinValue.SafeCreateFromValue(year, 1, 1); } resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), true); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.AFTER_MOD; } if (resultDateTime != referenceTime) { if (mode.Equals(AgoLaterMode.Date)) { ret.Timex = $"{DateTimeFormatUtil.LuisDate(resultDateTime)}"; } else if (mode.Equals(AgoLaterMode.DateTime)) { ret.Timex = $"{DateTimeFormatUtil.LuisDateTime(resultDateTime)}"; } ret.FutureValue = ret.PastValue = resultDateTime; ret.SubDateTimeEntities = new List <object> { durationParseResult }; ret.Success = true; } return(ret); }