// Parse "last minute", "next hour" private DateTimeResolutionResult ParseRelativeUnit(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); var match = Config.RelativeTimeUnitRegex.Match(text); if (!match.Success) { match = this.Config.RestOfDateTimeRegex.Match(text); } if (match.Success) { var srcUnit = match.Groups["unit"].Value.ToLower(); var unitStr = Config.UnitMap[srcUnit]; int swiftValue = 1; var prefixMatch = Config.PastRegex.Match(text); if (prefixMatch.Success) { swiftValue = -1; } DateObject beginTime; var endTime = beginTime = referenceTime; var ptTimex = string.Empty; if (Config.UnitMap.ContainsKey(srcUnit)) { switch (unitStr) { case "D": endTime = DateObject.MinValue.SafeCreateFromValue(beginTime.Year, beginTime.Month, beginTime.Day); endTime = endTime.AddDays(1).AddSeconds(-1); ptTimex = "PT" + (endTime - beginTime).TotalSeconds + "S"; break; case "H": beginTime = swiftValue > 0 ? beginTime : referenceTime.AddHours(swiftValue); endTime = swiftValue > 0 ? referenceTime.AddHours(swiftValue) : endTime; ptTimex = "PT1H"; break; case "M": beginTime = swiftValue > 0 ? beginTime : referenceTime.AddMinutes(swiftValue); endTime = swiftValue > 0 ? referenceTime.AddMinutes(swiftValue) : endTime; ptTimex = "PT1M"; break; case "S": beginTime = swiftValue > 0 ? beginTime : referenceTime.AddSeconds(swiftValue); endTime = swiftValue > 0 ? referenceTime.AddSeconds(swiftValue) : endTime; ptTimex = "PT1S"; break; default: return(ret); } ret.Timex = $"({DateTimeFormatUtil.LuisDate(beginTime)}T{DateTimeFormatUtil.LuisTime(beginTime)}," + $"{DateTimeFormatUtil.LuisDate(endTime)}T{DateTimeFormatUtil.LuisTime(endTime)},{ptTimex})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginTime, endTime); ret.Success = true; return(ret); } } return(ret); }
// TODO: this can be abstracted with the similar method in BaseDatePeriodParser // Parse "in 20 minutes" private DateTimeResolutionResult ParseDuration(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); // For the rest of datetime, it will be handled in next function if (Config.RestOfDateTimeRegex.IsMatch(text)) { return(ret); } var ers = Config.DurationExtractor.Extract(text, referenceTime); 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 numbersInSuffix = Config.CardinalExtractor.Extract(beforeStr); var numbersInDuration = Config.CardinalExtractor.Extract(ers[0].Text); // Handle cases like "2 upcoming days", "5 previous years" if (numbersInSuffix.Any() && !numbersInDuration.Any()) { var numberEr = numbersInSuffix.First(); var numberText = numberEr.Text; var durationText = ers[0].Text; var combinedText = $"{numberText} {durationText}"; var combinedDurationEr = Config.DurationExtractor.Extract(combinedText, referenceTime); if (combinedDurationEr.Any()) { pr = Config.DurationParser.Parse(combinedDurationEr.First()); var startIndex = numberEr.Start.Value + numberEr.Length.Value; beforeStr = beforeStr.Substring(startIndex).Trim(); } } if (pr.Value != null) { var swiftSeconds = 0; var mod = ""; var durationResult = (DateTimeResolutionResult)pr.Value; if (durationResult.PastValue is double && durationResult.FutureValue is double) { swiftSeconds = (int)((double)durationResult.FutureValue); } DateObject beginTime; var endTime = beginTime = referenceTime; if (Config.PastRegex.IsExactMatch(beforeStr, trim: true)) { mod = Constants.BEFORE_MOD; beginTime = referenceTime.AddSeconds(-swiftSeconds); } // Handle the "within (the) (next) xx seconds/minutes/hours" case // Should also handle the multiple duration case like P1DT8H // Set the beginTime equal to reference time for now if (Config.WithinNextPrefixRegex.IsExactMatch(beforeStr, trim: true)) { endTime = beginTime.AddSeconds(swiftSeconds); } if (Config.FutureRegex.IsExactMatch(beforeStr, trim: true)) { mod = Constants.AFTER_MOD; endTime = beginTime.AddSeconds(swiftSeconds); } if (Config.PastRegex.IsExactMatch(afterStr, trim: true)) { mod = Constants.BEFORE_MOD; beginTime = referenceTime.AddSeconds(-swiftSeconds); } if (Config.FutureRegex.IsExactMatch(afterStr, trim: true)) { mod = Constants.AFTER_MOD; endTime = beginTime.AddSeconds(swiftSeconds); } if (Config.FutureSuffixRegex.IsExactMatch(afterStr, trim: true)) { mod = Constants.AFTER_MOD; endTime = beginTime.AddSeconds(swiftSeconds); } ret.Timex = $"({DateTimeFormatUtil.LuisDate(beginTime)}T{DateTimeFormatUtil.LuisTime(beginTime)}," + $"{DateTimeFormatUtil.LuisDate(endTime)}T{DateTimeFormatUtil.LuisTime(endTime)}," + $"{durationResult.Timex})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginTime, endTime); ret.Success = true; if (!string.IsNullOrEmpty(mod)) { ((DateTimeResolutionResult)pr.Value).Mod = mod; } ret.SubDateTimeEntities = new List <object> { pr }; return(ret); } } return(ret); }
// parse "in 20 minutes" private DateTimeResolutionResult ParseNumberWithUnit(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); string unitStr; // if there are spaces between number and unit var ers = this.config.CardinalExtractor.Extract(text); if (ers.Count == 1) { var pr = this.config.CardinalParser.Parse(ers[0]); var srcUnit = text.Substring(ers[0].Start + ers[0].Length ?? 0).Trim(); if (srcUnit.StartsWith("个", StringComparison.Ordinal)) { srcUnit = srcUnit.Substring(1); } var beforeStr = text.Substring(0, ers[0].Start ?? 0); if (this.config.UnitMap.ContainsKey(srcUnit)) { var numStr = pr.ResolutionStr; unitStr = this.config.UnitMap[srcUnit]; var prefixMatch = this.config.PastRegex.MatchExact(beforeStr, trim: true); if (prefixMatch.Success) { DateObject beginDate, endDate; switch (unitStr) { case "H": beginDate = referenceTime.AddHours(-(double)pr.Value); endDate = referenceTime; break; case "M": beginDate = referenceTime.AddMinutes(-(double)pr.Value); endDate = referenceTime; break; case "S": beginDate = referenceTime.AddSeconds(-(double)pr.Value); endDate = referenceTime; break; default: return(ret); } ret.Timex = $"({DateTimeFormatUtil.LuisDate(beginDate)}T{DateTimeFormatUtil.LuisTime(beginDate)},{DateTimeFormatUtil.LuisDate(endDate)}T{DateTimeFormatUtil.LuisTime(endDate)},PT{numStr}{unitStr[0]})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate); ret.Success = true; return(ret); } prefixMatch = this.config.FutureRegex.MatchExact(beforeStr, trim: true); if (!prefixMatch.Success) { prefixMatch = this.config.TimePeriodLeftRegex.MatchEnd(beforeStr, trim: true); } if (prefixMatch.Success) { DateObject beginDate, endDate; switch (unitStr) { case "H": beginDate = referenceTime; endDate = referenceTime.AddHours((double)pr.Value); break; case "M": beginDate = referenceTime; endDate = referenceTime.AddMinutes((double)pr.Value); break; case "S": beginDate = referenceTime; endDate = referenceTime.AddSeconds((double)pr.Value); break; default: return(ret); } ret.Timex = $"({DateTimeFormatUtil.LuisDate(beginDate)}T{DateTimeFormatUtil.LuisTime(beginDate)},{DateTimeFormatUtil.LuisDate(endDate)}T{DateTimeFormatUtil.LuisTime(endDate)},PT{numStr}{unitStr[0]})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate); ret.Success = true; return(ret); } } } // handle "last hour" var match = this.config.UnitRegex.Match(text); if (match.Success) { var srcUnit = match.Groups[Constants.UnitGroupName].Value; var beforeStr = text.Substring(0, match.Index).Trim(); if (this.config.UnitMap.ContainsKey(srcUnit)) { unitStr = this.config.UnitMap[srcUnit]; if (this.config.PastRegex.IsExactMatch(beforeStr, trim: true)) { DateObject beginDate, endDate; switch (unitStr) { case "H": beginDate = referenceTime.AddHours(-1); endDate = referenceTime; break; case "M": beginDate = referenceTime.AddMinutes(-1); endDate = referenceTime; break; case "S": beginDate = referenceTime.AddSeconds(-1); endDate = referenceTime; break; default: return(ret); } ret.Timex = $"({DateTimeFormatUtil.LuisDate(beginDate)}T{DateTimeFormatUtil.LuisTime(beginDate)},{DateTimeFormatUtil.LuisDate(endDate)}T{DateTimeFormatUtil.LuisTime(endDate)},PT1{unitStr[0]})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate); ret.Success = true; return(ret); } if (this.config.FutureRegex.IsExactMatch(beforeStr, trim: true)) { DateObject beginDate, endDate; switch (unitStr) { case "H": beginDate = referenceTime; endDate = referenceTime.AddHours(1); break; case "M": beginDate = referenceTime; endDate = referenceTime.AddMinutes(1); break; case "S": beginDate = referenceTime; endDate = referenceTime.AddSeconds(1); break; default: return(ret); } ret.Timex = $"({DateTimeFormatUtil.LuisDate(beginDate)}T{DateTimeFormatUtil.LuisTime(beginDate)},{DateTimeFormatUtil.LuisDate(endDate)}T{DateTimeFormatUtil.LuisTime(endDate)},PT1{unitStr[0]})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate); ret.Success = true; return(ret); } } } return(ret); }