private DateTimeResolutionResult ParseMergedDuration(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); var durationExtractor = DurationExtractor; // DurationExtractor without parameter will not extract merged duration var ers = durationExtractor.Extract(text, referenceTime); // only handle merged duration cases like "1 month 21 days" if (ers.Count <= 1) { ret.Success = false; return(ret); } var start = ers[0].Start ?? 0; if (start != 0) { var beforeStr = text.Substring(0, start - 1); if (!string.IsNullOrWhiteSpace(beforeStr)) { return(ret); } } var end = ers[ers.Count - 1].Start + ers[ers.Count - 1].Length ?? 0; if (end != text.Length) { var afterStr = text.Substring(end); if (!string.IsNullOrWhiteSpace(afterStr)) { return(ret); } } var prs = new List <DateTimeParseResult>(); var timexDict = new Dictionary <string, string>(); // insert timex into a dictionary foreach (var er in ers) { var unitRegex = DurationUnitRegex; var unitMatch = unitRegex.Match(er.Text); if (unitMatch.Success) { var pr = (DateTimeParseResult)Parse(er); if (pr.Value != null) { timexDict.Add(UnitMap[unitMatch.Groups["unit"].Value], pr.TimexStr); prs.Add(pr); } } } // sort the timex using the granularity of the duration, "P1M23D" for "1 month 23 days" and "23 days 1 month" if (prs.Count == ers.Count) { ret.Timex = TimexUtility.GenerateCompoundDurationTimex(timexDict, UnitValueMap); double value = 0; foreach (var pr in prs) { value += double.Parse(((DateTimeResolutionResult)pr.Value).FutureValue.ToString(), CultureInfo.InvariantCulture); } ret.FutureValue = ret.PastValue = value; } ret.Success = true; return(ret); }
// match several other cases // including '今天', '后天', '十三日' protected DateTimeResolutionResult ParseImplicitDate(string text, DateObject referenceDate) { var trimedText = text.Trim(); var ret = new DateTimeResolutionResult(); // handle "十二日" "明年这个月三日" "本月十一日" var match = DateExtractorChs.SpecialDate.Match(trimedText); if (match.Success && match.Length == trimedText.Length) { var yearStr = match.Groups["thisyear"].Value.ToLower(); var monthStr = match.Groups["thismonth"].Value.ToLower(); var dayStr = match.Groups["day"].Value.ToLower(); 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 (DateExtractorChs.NextRe.Match(monthStr).Success) { month++; if (month == 13) { month = 1; year++; } } else if (DateExtractorChs.LastRe.Match(monthStr).Success) { month--; if (month == 0) { month = 12; year--; } } if (!string.IsNullOrEmpty(yearStr)) { hasYear = true; if (DateExtractorChs.NextRe.Match(yearStr).Success) { ++year; } else if (DateExtractorChs.LastRe.Match(yearStr).Success) { --year; } } } ret.Timex = FormatUtil.LuisDate(hasYear ? year : -1, hasMonth ? month : -1, day); DateObject futureDate, pastDate; if (day > MonthMaxDays[month - 1]) { futureDate = DateObject.MinValue.SafeCreateFromValue(year, month + 1, day); pastDate = DateObject.MinValue.SafeCreateFromValue(year, month - 1, day); } else { futureDate = DateObject.MinValue.SafeCreateFromValue(year, month, day); pastDate = DateObject.MinValue.SafeCreateFromValue(year, month, day); if (!hasMonth) { if (futureDate < referenceDate) { futureDate = futureDate.AddMonths(1); } if (pastDate >= referenceDate) { pastDate = pastDate.AddMonths(-1); } } else if (!hasYear) { if (futureDate < referenceDate) { futureDate = futureDate.AddYears(1); } if (pastDate >= referenceDate) { pastDate = pastDate.AddYears(-1); } } } ret.FutureValue = futureDate; ret.PastValue = pastDate; ret.Success = true; return(ret); } // handle cases like "昨日", "明日", "大后天" match = DateExtractorChs.SpecialDayRegex.Match(trimedText); if (match.Success && match.Index == 0 && match.Length == trimedText.Length) { var value = referenceDate.AddDays(config.GetSwiftDay(match.Value.ToLower())); ret.Timex = FormatUtil.LuisDate(value); ret.FutureValue = ret.PastValue = value; ret.Success = true; return(ret); } 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); }
// handle cases like "三天前" private DateTimeResolutionResult ParserDurationWithBeforeAndAfter(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); var durationRes = durationExtractor.Extract(text, referenceDate); var numStr = string.Empty; var unitStr = string.Empty; if (durationRes.Count > 0) { var match = DateExtractorChs.UnitRegex.Match(text); if (match.Success) { var afterStr = text.Substring((int)durationRes[0].Start + (int)durationRes[0].Length, 1) .Trim() .ToLowerInvariant(); var srcUnit = match.Groups["unit"].Value.ToLowerInvariant(); var numberStr = text.Substring((int)durationRes[0].Start, match.Index - (int)durationRes[0].Start) .Trim() .ToLowerInvariant(); var number = ConvertChineseToNum(numberStr); if (this.config.UnitMap.ContainsKey(srcUnit)) { unitStr = this.config.UnitMap[srcUnit]; numStr = number.ToString(); if (afterStr.Equals("前")) { DateObject date; switch (unitStr) { case "D": date = referenceDate.AddDays(-double.Parse(numStr)); break; case "W": date = referenceDate.AddDays(-7 * double.Parse(numStr)); break; case "MON": date = referenceDate.AddMonths(-Convert.ToInt32(double.Parse(numStr))); break; case "Y": date = referenceDate.AddYears(-Convert.ToInt32(double.Parse(numStr))); break; default: return(ret); } ret.Timex = $"{FormatUtil.LuisDate(date)}"; ret.FutureValue = ret.PastValue = date; ret.Success = true; return(ret); } if (afterStr.Equals("后")) { DateObject date; switch (unitStr) { case "D": date = referenceDate.AddDays(double.Parse(numStr)); break; case "W": date = referenceDate.AddDays(7 * double.Parse(numStr)); break; case "MON": date = referenceDate.AddMonths(Convert.ToInt32(double.Parse(numStr))); break; case "Y": date = referenceDate.AddYears(Convert.ToInt32(double.Parse(numStr))); break; default: return(ret); } ret.Timex = $"{FormatUtil.LuisDate(date)}"; ret.FutureValue = ret.PastValue = date; ret.Success = true; return(ret); } } } } 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 er1 = SingleTimeExtractor.Extract(text, referenceTime); var er2 = TimeWithDateExtractor.Extract(text, referenceTime); var rightTime = DateObject.MinValue.SafeCreateFromValue(referenceTime.Year, referenceTime.Month, referenceTime.Day); var leftTime = DateObject.MinValue.SafeCreateFromValue(referenceTime.Year, referenceTime.Month, referenceTime.Day); if (er2.Count == 2) { pr1 = this.config.DateTimeParser.Parse(er2[0], referenceTime); pr2 = this.config.DateTimeParser.Parse(er2[1], referenceTime); bothHaveDates = true; } else if (er2.Count == 1 && er1.Count == 2) { if (!er2[0].IsOverlap(er1[0])) { pr1 = this.config.TimeParser.Parse(er1[0], referenceTime); pr2 = this.config.DateTimeParser.Parse(er2[0], referenceTime); endHasDate = true; } else { pr1 = this.config.DateTimeParser.Parse(er2[0], referenceTime); pr2 = this.config.TimeParser.Parse(er1[1], referenceTime); beginHasDate = true; } } else if (er2.Count == 1 && er1.Count == 1) { if (er1[0].Start < er2[0].Start) { pr1 = this.config.TimeParser.Parse(er1[0], referenceTime); pr2 = this.config.DateTimeParser.Parse(er2[0], referenceTime); endHasDate = true; } else { pr1 = this.config.DateTimeParser.Parse(er2[0], referenceTime); pr2 = this.config.TimeParser.Parse(er1[0], referenceTime); beginHasDate = true; } } else if (er1.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 (futureBegin > futureEnd) { futureBegin = pastBegin; } if (pastEnd < pastBegin) { pastEnd = futureEnd; } if (bothHaveDates) { rightTime = DateObject.MinValue.SafeCreateFromValue(futureEnd.Year, futureEnd.Month, futureEnd.Day); leftTime = DateObject.MinValue.SafeCreateFromValue(futureBegin.Year, futureBegin.Month, futureBegin.Day); } else if (beginHasDate) { // TODO: Handle "明天下午两点到五点" 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); leftTime = DateObject.MinValue.SafeCreateFromValue(futureBegin.Year, futureBegin.Month, futureBegin.Day); } else if (endHasDate) { // TODO: Handle "明天下午两点到五点" 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); rightTime = DateObject.MinValue.SafeCreateFromValue(futureEnd.Year, futureEnd.Month, futureEnd.Day); } var leftResult = (DateTimeResolutionResult)pr1.Value; var rightResult = (DateTimeResolutionResult)pr2.Value; var leftResultTime = (DateObject)leftResult.FutureValue; var rightResultTime = (DateObject)rightResult.FutureValue; int day = referenceTime.Day, month = referenceTime.Month, year = referenceTime.Year; //check if the right time is smaller than the left time, if yes, add one day int hour = leftResultTime.Hour > 0 ? leftResultTime.Hour : 0, min = leftResultTime.Minute > 0 ? leftResultTime.Minute : 0, second = leftResultTime.Second > 0 ? leftResultTime.Second : 0; leftTime = leftTime.AddHours(hour); leftTime = leftTime.AddMinutes(min); leftTime = leftTime.AddSeconds(second); DateObject.MinValue.SafeCreateFromValue(year, month, day, hour, min, second); hour = rightResultTime.Hour > 0 ? rightResultTime.Hour : 0; min = rightResultTime.Minute > 0 ? rightResultTime.Minute : 0; second = rightResultTime.Second > 0 ? rightResultTime.Second : 0; rightTime = rightTime.AddHours(hour); rightTime = rightTime.AddMinutes(min); rightTime = rightTime.AddSeconds(second); //the right side time contains "ampm", while the left side doesn't if (rightResult.Comment != null && rightResult.Comment.Equals(Constants.Comment_AmPm) && leftResult.Comment == null && rightTime < leftTime) { rightTime = rightTime.AddHours(Constants.HalfDayHourCount); } if (rightTime < leftTime) { rightTime = rightTime.AddDays(1); } ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(leftTime, rightTime); var leftTimex = ""; var rightTimex = ""; //"X" is timex token for not determined time if (!pr1.TimexStr.Contains("X") && !pr2.TimexStr.Contains("X")) { leftTimex = DateTimeFormatUtil.LuisDateTime(leftTime); rightTimex = DateTimeFormatUtil.LuisDateTime(rightTime); } else { leftTimex = pr1.TimexStr; rightTimex = pr2.TimexStr; } ret.Timex = $"({leftTimex},{rightTimex},PT{Convert.ToInt32((rightTime - leftTime).TotalHours)}H)"; ret.Success = true; return(ret); }
// parse "in 20 minutes" private DateTimeResolutionResult ParseNumberWithUnit(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); string numStr, unitStr; // if there are spaces between nubmer and unit var ers = CardinalExtractor.Extract(text); if (ers.Count == 1) { var pr = CardinalParser.Parse(ers[0]); var srcUnit = text.Substring(ers[0].Start + ers[0].Length ?? 0).Trim().ToLower(); if (srcUnit.StartsWith("个")) { srcUnit = srcUnit.Substring(1); } var beforeStr = text.Substring(0, ers[0].Start ?? 0).ToLowerInvariant(); if (this.config.UnitMap.ContainsKey(srcUnit)) { numStr = pr.ResolutionStr; unitStr = this.config.UnitMap[srcUnit]; if (DateTimePeriodExtractor.PastRegex.IsExactMatch(beforeStr, trim: true)) { 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); } if (DateTimePeriodExtractor.FutureRegex.IsExactMatch(beforeStr, trim: true)) { 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 = DateTimePeriodExtractor.UnitRegex.Match(text); if (match.Success) { var srcUnit = match.Groups["unit"].Value.ToLower(); var beforeStr = text.Substring(0, match.Index).ToLowerInvariant(); if (this.config.UnitMap.ContainsKey(srcUnit)) { unitStr = this.config.UnitMap[srcUnit]; if (DateTimePeriodExtractor.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 (DateTimePeriodExtractor.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); }
// handle cases like "5分钟前", "1小时以后" private DateTimeResolutionResult ParserDurationWithAgoAndLater(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); var durationRes = durationExtractor.Extract(text, referenceDate); if (durationRes.Count > 0) { var match = ChineseDateTimeExtractorConfiguration.DateTimePeriodUnitRegex.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 number = ConvertChineseToNum(numberStr); if (this.config.UnitMap.ContainsKey(srcUnit)) { var unitStr = this.config.UnitMap[srcUnit]; var beforeMatch = ChineseDateTimeExtractorConfiguration.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 = ChineseDateTimeExtractorConfiguration.AfterRegex.Match(suffix); if (afterMatch.Success && suffix.StartsWith(afterMatch.Value)) { 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); }
// match several other cases // including '今天', '后天', '十三日' protected DateTimeResolutionResult ParseImplicitDate(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); // handle "十二日" "明年这个月三日" "本月十一日" var match = ChineseDateExtractorConfiguration.SpecialDate.MatchExact(text, trim: true); if (match.Success) { var yearStr = match.Groups["thisyear"].Value.ToLower(); var monthStr = match.Groups["thismonth"].Value.ToLower(); var dayStr = match.Groups["day"].Value.ToLower(); 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 (ChineseDateExtractorConfiguration.NextRe.Match(monthStr).Success) { month++; if (month == Constants.MaxMonth + 1) { month = Constants.MinMonth; year++; } } else if (ChineseDateExtractorConfiguration.LastRe.Match(monthStr).Success) { month--; if (month == Constants.MinMonth - 1) { month = Constants.MaxMonth; year--; } } if (!string.IsNullOrEmpty(yearStr)) { hasYear = true; if (ChineseDateExtractorConfiguration.NextRe.Match(yearStr).Success) { ++year; } else if (ChineseDateExtractorConfiguration.LastRe.Match(yearStr).Success) { --year; } } } ret.Timex = DateTimeFormatUtil.LuisDate(hasYear ? year : -1, hasMonth ? month : -1, day); DateObject futureDate, pastDate; if (day > 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 (IsNonleapYearFeb29th(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 = ChineseDateExtractorConfiguration.SpecialDayRegex.MatchExact(text, trim: true); if (match.Success) { var value = referenceDate.AddDays(ChineseDateTimeParserConfiguration.GetSwiftDay(match.Value.ToLower())); ret.Timex = DateTimeFormatUtil.LuisDate(value); ret.FutureValue = ret.PastValue = value; ret.Success = true; return(ret); } 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 ParseQuarter(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); var match = DatePeriodExtractorChs.QuarterRegex.Match(text); if (!(match.Success && match.Length == text.Length)) { return(ret); } // pare year var year = referenceDate.Year; var yearNum = match.Groups["year"].Value; var yearChs = match.Groups["yearchs"].Value; var yearRel = match.Groups["yearrel"].Value; if (!string.IsNullOrEmpty(yearNum)) { if (yearNum.EndsWith("年")) { yearNum = yearNum.Substring(0, yearNum.Length - 1); } year = int.Parse(yearNum); } else if (!string.IsNullOrEmpty(yearChs)) { if (yearChs.EndsWith("年")) { yearChs = yearChs.Substring(0, yearChs.Length - 1); } year = ConvertChineseToInteger(yearChs); } else if (!string.IsNullOrEmpty(yearRel)) { if (yearRel.EndsWith("去年")) { year--; } else if (yearRel.EndsWith("明年")) { year++; } } if (year < 100 && year >= 90) { year += 1900; } else if (year < 100 && year < 20) { year += 2000; } // parse quarterNum var cardinalStr = match.Groups["cardinal"].Value; var quarterNum = this.config.CardinalMap[cardinalStr]; var beginDate = DateObject.MinValue.SafeCreateFromValue(year, quarterNum * 3 - 2, 1); var endDate = DateObject.MinValue.SafeCreateFromValue(year, quarterNum * 3 + 1, 1); ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate); ret.Timex = $"({FormatUtil.LuisDate(beginDate)},{FormatUtil.LuisDate(endDate)},P3M)"; ret.Success = true; return(ret); }
private DateTimeResolutionResult ParseSimpleCases(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); int year = referenceDate.Year, month = referenceDate.Month; int beginDay, endDay; var noYear = false; var inputYear = false; var trimedText = text.Trim(); var match = DatePeriodExtractorChs.SimpleCasesRegex.Match(trimedText); string beginLuisStr, endLuisStr; if (match.Success && match.Index == 0 && match.Length == trimedText.Length) { var days = match.Groups["day"]; beginDay = this.config.DayOfMonth[days.Captures[0].Value.ToLower()]; endDay = this.config.DayOfMonth[days.Captures[1].Value.ToLower()]; var monthStr = match.Groups["month"].Value; var yearStr = match.Groups["year"].Value; if (!string.IsNullOrEmpty(yearStr)) { year = int.Parse(yearStr); inputYear = true; } else { noYear = true; } if (!string.IsNullOrEmpty(monthStr)) { month = this.config.MonthOfYear[monthStr.ToLower()]; } else { monthStr = match.Groups["relmonth"].Value.Trim().ToLower(); var thismatch = DatePeriodExtractorChs.ThisRegex.Match(monthStr); var nextmatch = DatePeriodExtractorChs.NextRegex.Match(monthStr); var lastmatch = DatePeriodExtractorChs.LastRegex.Match(monthStr); if (thismatch.Success) { // do nothing } else if (nextmatch.Success) { if (month != 12) { month += 1; } else { month = 1; year += 1; } } else { if (month != 1) { month -= 1; } else { month = 12; year -= 1; } } } if (inputYear || DatePeriodExtractorChs.ThisRegex.Match(monthStr).Success || DatePeriodExtractorChs.NextRegex.Match(monthStr).Success) { beginLuisStr = FormatUtil.LuisDate(year, month, beginDay); endLuisStr = FormatUtil.LuisDate(year, month, endDay); } else { beginLuisStr = FormatUtil.LuisDate(-1, month, beginDay); endLuisStr = FormatUtil.LuisDate(-1, month, endDay); } } else { return(ret); } int futureYear = year, pastYear = year; var startDate = DateObject.MinValue.SafeCreateFromValue(year, month, beginDay); if (noYear && startDate < referenceDate) { futureYear++; } if (noYear && startDate >= referenceDate) { pastYear--; } ret.Timex = $"({beginLuisStr},{endLuisStr},P{endDay - beginDay}D)"; ret.FutureValue = new Tuple <DateObject, DateObject>( DateObject.MinValue.SafeCreateFromValue(futureYear, month, beginDay), DateObject.MinValue.SafeCreateFromValue(futureYear, month, endDay)); ret.PastValue = new Tuple <DateObject, DateObject>( DateObject.MinValue.SafeCreateFromValue(pastYear, month, beginDay), DateObject.MinValue.SafeCreateFromValue(pastYear, month, endDay)); ret.Success = true; return(ret); }
public TestParserResultValue(DateTimeResolutionResult result) { this.Timex = result.Timex; this.FutureResolution = result.FutureResolution; this.PastResolution = result.PastResolution; }
// parse "今年夏天" private DateTimeResolutionResult ParseSeason(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); var match = DatePeriodExtractorChs.SeasonWithYear.Match(text); if (match.Success && match.Length == text.Length) { // parse year var year = referenceDate.Year; var hasYear = false; var yearNum = match.Groups["year"].Value; var yearChs = match.Groups["yearchs"].Value; var yearRel = match.Groups["yearrel"].Value; if (!string.IsNullOrEmpty(yearNum)) { hasYear = true; if (yearNum.EndsWith("年")) { yearNum = yearNum.Substring(0, yearNum.Length - 1); } year = int.Parse(yearNum); } else if (!string.IsNullOrEmpty(yearChs)) { hasYear = true; if (yearChs.EndsWith("年")) { yearChs = yearChs.Substring(0, yearChs.Length - 1); } year = ConvertChineseToInteger(yearChs); } else if (!string.IsNullOrEmpty(yearRel)) { hasYear = true; if (yearRel.EndsWith("去年")) { year--; } else if (yearRel.EndsWith("明年")) { year++; } } if (year < 100 && year >= 90) { year += 1900; } else if (year < 100 && year < 20) { year += 2000; } // parse season var seasonStr = match.Groups["season"].Value; ret.Timex = this.config.SeasonMap[seasonStr]; if (hasYear) { ret.Timex = year.ToString("D4") + "-" + ret.Timex; } ret.Success = true; return(ret); } return(ret); }
public DateTimeParseResult Parse(ExtractResult er, DateObject refDate) { var referenceTime = refDate; // handle cases like "三年半" var hasHalfSuffix = false; if (er.Text.EndsWith("半", StringComparison.Ordinal)) { er.Length -= 1; er.Text = er.Text.Substring(0, er.Text.Length - 1); hasHalfSuffix = true; } var parseResult = InternalParser.Parse(er); var unitResult = parseResult.Value as UnitValue; if (unitResult == null) { return(null); } var dateTimeParseResult = new DateTimeResolutionResult(); var unitStr = unitResult.Unit; var numStr = unitResult.Number; if (hasHalfSuffix) { numStr = (double.Parse(numStr) + 0.5).ToString(CultureInfo.InvariantCulture); } dateTimeParseResult.Timex = "P" + (BaseDurationParser.IsLessThanDay(unitStr) ? "T" : string.Empty) + numStr + unitStr[0]; dateTimeParseResult.FutureValue = dateTimeParseResult.PastValue = double.Parse(numStr) * 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() }, }; } 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); }
protected override DateTimeResolutionResult ParseSpecificTimeOfDay(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); var trimmedText = text.Trim(); // handle morning, afternoon.. if (!this.Config.GetMatchedTimeRange(trimmedText, out string timeStr, out int beginHour, out int endHour, out int endMin)) { return(ret); } var exactMatch = this.Config.SpecificTimeOfDayRegex.MatchExact(trimmedText, trim: true); if (!exactMatch.Success) { exactMatch = this.Config.PeriodTimeOfDayWithDateRegex.MatchExact(trimmedText, trim: true); } if (exactMatch.Success) { // Extract early/late prefix from text if any bool hasEarly = false; if (!string.IsNullOrEmpty(exactMatch.Groups["early"].Value)) { hasEarly = true; ret.Comment = Constants.Comment_Early; ret.Mod = Constants.EARLY_MOD; endHour = beginHour + 2; // Handling special case: night ends with 23:59 due to C# issues. if (endMin == 59) { endMin = 0; } } if (!hasEarly && !string.IsNullOrEmpty(exactMatch.Groups["late"].Value)) { ret.Comment = Constants.Comment_Late; ret.Mod = Constants.LATE_MOD; beginHour = beginHour + 2; } var swift = this.Config.GetSwiftPrefix(trimmedText); var date = referenceTime.AddDays(swift).Date; int day = date.Day, month = date.Month, year = date.Year; ret.Timex = DateTimeFormatUtil.FormatDate(date) + timeStr; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>( DateObject.MinValue.SafeCreateFromValue(year, month, day, beginHour, 0, 0), DateObject.MinValue.SafeCreateFromValue(year, month, day, endHour, endMin, endMin)); ret.Success = true; return(ret); } var startIndex = trimmedText.IndexOf(DateTimeDefinitions.Tomorrow, StringComparison.Ordinal) == 0 ? DateTimeDefinitions.Tomorrow.Length : 0; // handle Date preceded/followed by morning, afternoon // @TODO Add handling code to handle early/late morning, afternoon var match = this.Config.TimeOfDayRegex.Match(trimmedText.Substring(startIndex)); if (match.Success) { var subStr = match.Index > 0 ? trimmedText.Substring(0, match.Index + startIndex).Trim() : trimmedText.Substring(match.Index + match.Length).Trim(); var ers = this.Config.DateExtractor.Extract(subStr, referenceTime); if (ers.Count == 0) { return(ret); } // Check if Date and TimeOfDay are contiguous var middleStr = match.Index > 0 ? subStr.Substring((int)ers[0].Start + (int)ers[0].Length).Trim() : subStr.Substring(0, (int)ers[0].Start).Trim(); if (!(string.IsNullOrWhiteSpace(middleStr) || ConnectorRegex.IsMatch(middleStr))) { return(ret); } var pr = this.Config.DateParser.Parse(ers[0], referenceTime); var futureDate = (DateObject)((DateTimeResolutionResult)pr.Value).FutureValue; var pastDate = (DateObject)((DateTimeResolutionResult)pr.Value).PastValue; ret.Timex = pr.TimexStr + timeStr; 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, endMin, endMin)); 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, endMin, endMin)); ret.Success = true; return(ret); } return(ret); }
protected override DateTimeResolutionResult ParseSpecificTimeOfDay(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); var trimmedText = text.Trim().ToLowerInvariant(); // Handle morning, afternoon.. if (!this.Config.GetMatchedTimeRange(trimmedText, out string timeStr, out int beginHour, out int endHour, out int endMin)) { return(ret); } var match = this.Config.SpecificTimeOfDayRegex.Match(trimmedText); if (match.Success && match.Index == 0 && match.Length == trimmedText.Length) { var swift = this.Config.GetSwiftPrefix(trimmedText); var date = referenceTime.AddDays(swift).Date; int day = date.Day, month = date.Month, year = date.Year; ret.Timex = FormatUtil.FormatDate(date) + timeStr; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(DateObject.MinValue.SafeCreateFromValue(year, month, day, beginHour, 0, 0), DateObject.MinValue.SafeCreateFromValue(year, month, day, endHour, endMin, endMin)); ret.Success = true; return(ret); } var startIndex = trimmedText.IndexOf(DateTimeDefinitions.Tomorrow, StringComparison.Ordinal) == 0 ? DateTimeDefinitions.Tomorrow.Length : 0; // Handle Date followed by morning, afternoon, ... // Add handling code to handle morning, afternoon followed by Date // Add handling code to handle early/late morning, afternoon match = this.Config.TimeOfDayRegex.Match(trimmedText.Substring(startIndex)); if (match.Success) { var beforeStr = trimmedText.Substring(0, match.Index + startIndex).Trim(); var ers = this.Config.DateExtractor.Extract(beforeStr, referenceTime); if (ers.Count == 0) { return(ret); } var pr = this.Config.DateParser.Parse(ers[0], referenceTime); var futureDate = (DateObject)((DateTimeResolutionResult)pr.Value).FutureValue; var pastDate = (DateObject)((DateTimeResolutionResult)pr.Value).PastValue; ret.Timex = pr.TimexStr + timeStr; 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, endMin, endMin)); 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, endMin, endMin)); ret.Success = true; return(ret); } return(ret); }
// merge a Date entity and a Time entity private DateTimeResolutionResult MergeDateAndTime(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); var er1 = SingleDateExtractor.Extract(text, referenceTime); if (er1.Count == 0) { return(ret); } var er2 = SingleTimeExtractor.Extract(text, referenceTime); if (er2.Count == 0) { return(ret); } // TODO: Add reference time var pr1 = this.config.DateParser.Parse(er1[0], referenceTime.Date); var pr2 = this.config.TimeParser.Parse(er2[0], referenceTime); if (pr1.Value == null || pr2.Value == null) { return(ret); } var futureDate = (DateObject)((DateTimeResolutionResult)pr1.Value).FutureValue; var pastDate = (DateObject)((DateTimeResolutionResult)pr1.Value).PastValue; var time = (DateObject)((DateTimeResolutionResult)pr2.Value).FutureValue; var hour = time.Hour; var min = time.Minute; var sec = time.Second; // handle morning, afternoon if (SimplePmRegex.IsMatch(text) && hour < Constants.HalfDayHourCount) { hour += Constants.HalfDayHourCount; } else if (SimpleAmRegex.IsMatch(text) && hour >= Constants.HalfDayHourCount) { hour -= Constants.HalfDayHourCount; } var timeStr = pr2.TimexStr; if (timeStr.EndsWith(Constants.Comment_AmPm, StringComparison.Ordinal)) { timeStr = timeStr.Substring(0, timeStr.Length - 4); } timeStr = "T" + hour.ToString("D2") + timeStr.Substring(3); ret.Timex = pr1.TimexStr + timeStr; var val = (DateTimeResolutionResult)pr2.Value; if (hour <= Constants.HalfDayHourCount && !SimplePmRegex.IsMatch(text) && !SimpleAmRegex.IsMatch(text) && !string.IsNullOrEmpty(val.Comment)) { // ret.Timex += "ampm"; ret.Comment = Constants.Comment_AmPm; } ret.FutureValue = DateObject.MinValue.SafeCreateFromValue(futureDate.Year, futureDate.Month, futureDate.Day, hour, min, sec); ret.PastValue = DateObject.MinValue.SafeCreateFromValue(pastDate.Year, pastDate.Month, pastDate.Day, hour, min, sec); ret.Success = true; return(ret); }
// handle like "2016年到2017年" private static DateTimeResolutionResult ParseYearToYear(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); var match = DatePeriodExtractorChs.YearToYear.Match(text); if (match.Success) { var yearMatch = DatePeriodExtractorChs.YearRegex.Matches(text); var yearInChineseMatch = DatePeriodExtractorChs.YearInChineseRegex.Matches(text); var beginYear = 0; var endYear = 0; if (yearMatch.Count == 2) { var yearFrom = yearMatch[0].Groups["year"].Value; var yearTo = yearMatch[1].Groups["year"].Value; beginYear = int.Parse(yearFrom); endYear = int.Parse(yearTo); } else if (yearInChineseMatch.Count == 2) { var yearFrom = yearInChineseMatch[0].Groups["yearchs"].Value; var yearTo = yearInChineseMatch[1].Groups["yearchs"].Value; beginYear = ConvertChineseToInteger(yearFrom); endYear = ConvertChineseToInteger(yearTo); } else if (yearInChineseMatch.Count == 1 && yearMatch.Count == 1) { if (yearMatch[0].Index < yearInChineseMatch[0].Index) { var yearFrom = yearMatch[0].Groups["year"].Value; var yearTo = yearInChineseMatch[0].Groups["yearch"].Value; beginYear = int.Parse(yearFrom); endYear = ConvertChineseToInteger(yearTo); } else { var yearFrom = yearInChineseMatch[0].Groups["yearch"].Value; var yearTo = yearMatch[0].Groups["year"].Value; beginYear = ConvertChineseToInteger(yearFrom); endYear = int.Parse(yearTo); } } if (beginYear < 100 && beginYear >= 90) { beginYear += 1900; } else if (beginYear < 100 && beginYear < 20) { beginYear += 2000; } if (endYear < 100 && endYear >= 90) { endYear += 1900; } else if (endYear < 100 && endYear < 20) { endYear += 2000; } var beginDay = DateObject.MinValue.SafeCreateFromValue(beginYear, 1, 1); var endDay = DateObject.MinValue.SafeCreateFromValue(endYear, 12, 31); var beginTimex = beginYear.ToString("D4"); var endTimex = endYear.ToString("D4"); ret.Timex = $"({beginTimex},{endTimex},P{endYear - beginYear}Y)"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDay, endDay); ret.Success = true; return(ret); } return(ret); }
private DateTimeResolutionResult ParseTimeOfToday(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); var ers = SingleTimeExtractor.Extract(text, referenceTime); if (ers.Count != 1) { return(ret); } // TODO: Add reference time var pr = this.config.TimeParser.Parse(ers[0], referenceTime); if (pr.Value == null) { return(ret); } var time = (DateObject)((DateTimeResolutionResult)pr.Value).FutureValue; var hour = time.Hour; var min = time.Minute; var sec = time.Second; var match = ChineseDateTimeExtractorConfiguration.TimeOfTodayRegex.Match(text); if (match.Success) { var matchStr = match.Value; var swift = 0; switch (matchStr) { case "今晚": if (hour < Constants.HalfDayHourCount) { hour += Constants.HalfDayHourCount; } break; case "今早": case "今晨": if (hour >= Constants.HalfDayHourCount) { hour -= Constants.HalfDayHourCount; } break; case "明晚": swift = 1; if (hour < Constants.HalfDayHourCount) { hour += Constants.HalfDayHourCount; } break; case "明早": case "明晨": swift = 1; if (hour >= Constants.HalfDayHourCount) { hour -= Constants.HalfDayHourCount; } break; case "昨晚": swift = -1; if (hour < Constants.HalfDayHourCount) { hour += Constants.HalfDayHourCount; } break; default: break; } var date = referenceTime.AddDays(swift).Date; // in this situation, luisStr cannot end up with "ampm", because we always have a "morning" or "night" var timeStr = pr.TimexStr; if (timeStr.EndsWith(Constants.Comment_AmPm, StringComparison.Ordinal)) { timeStr = timeStr.Substring(0, timeStr.Length - 4); } timeStr = "T" + hour.ToString("D2") + timeStr.Substring(3); ret.Timex = DateTimeFormatUtil.FormatDate(date) + timeStr; ret.FutureValue = ret.PastValue = DateObject.MinValue.SafeCreateFromValue(date.Year, date.Month, date.Day, hour, min, sec); ret.Success = true; return(ret); } return(ret); }
// for case "2016年5月" private DateTimeResolutionResult ParseYearAndMonth(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); var match = DatePeriodExtractorChs.YearAndMonth.Match(text); if (!(match.Success && match.Length == text.Length)) { match = DatePeriodExtractorChs.PureNumYearAndMonth.Match(text); } if (!(match.Success && match.Length == text.Length)) { return(ret); } // parse year var year = referenceDate.Year; var yearNum = match.Groups["year"].Value; var yearChs = match.Groups["yearchs"].Value; var yearRel = match.Groups["yearrel"].Value; if (!string.IsNullOrEmpty(yearNum)) { if (yearNum.EndsWith("年")) { yearNum = yearNum.Substring(0, yearNum.Length - 1); } year = int.Parse(yearNum); } else if (!string.IsNullOrEmpty(yearChs)) { if (yearChs.EndsWith("年")) { yearChs = yearChs.Substring(0, yearChs.Length - 1); } year = ConvertChineseToInteger(yearChs); } else if (!string.IsNullOrEmpty(yearRel)) { if (yearRel.EndsWith("去年")) { year--; } else if (yearRel.EndsWith("明年")) { year++; } } if (year < 100 && year >= 90) { year += 1900; } else if (year < 20) { year += 2000; } var monthStr = match.Groups["month"].Value; var month = this.config.MonthOfYear[monthStr] > 12 ? this.config.MonthOfYear[monthStr] % 12 : this.config.MonthOfYear[monthStr]; var beginDay = DateObject.MinValue.SafeCreateFromValue(year, month, 1); DateObject endDay; if (month == 12) { endDay = DateObject.MinValue.SafeCreateFromValue(year + 1, 1, 1); } else { endDay = DateObject.MinValue.SafeCreateFromValue(year, month + 1, 1); } ret.Timex = year.ToString("D4") + "-" + month.ToString("D2"); ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDay, endDay); ret.Success = true; return(ret); }
// handle cases like "三天前" private DateTimeResolutionResult ParserDurationWithBeforeAndAfter(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); var durationRes = durationExtractor.Extract(text, referenceDate); var numStr = string.Empty; var unitStr = string.Empty; if (durationRes.Count > 0) { var match = DateExtractor.UnitRegex.Match(text); if (match.Success) { var suffix = text.Substring((int)durationRes[0].Start + (int)durationRes[0].Length) .Trim() .ToLowerInvariant(); var srcUnit = match.Groups["unit"].Value.ToLowerInvariant(); var numberStr = text.Substring((int)durationRes[0].Start, match.Index - (int)durationRes[0].Start) .Trim() .ToLowerInvariant(); var number = ConvertJapaneseToNum(numberStr); if (this.config.UnitMap.ContainsKey(srcUnit)) { unitStr = this.config.UnitMap[srcUnit]; numStr = number.ToString(); var beforeMatch = DateExtractor.BeforeRegex.Match(suffix); if (beforeMatch.Success && suffix.StartsWith(beforeMatch.Value)) { DateObject date; switch (unitStr) { case Constants.TimexDay: date = referenceDate.AddDays(-double.Parse(numStr)); break; case Constants.TimexWeek: date = referenceDate.AddDays(-7 * double.Parse(numStr)); break; case Constants.TimexMonthFull: date = referenceDate.AddMonths(-Convert.ToInt32(double.Parse(numStr))); break; case Constants.TimexYear: date = referenceDate.AddYears(-Convert.ToInt32(double.Parse(numStr))); break; default: return(ret); } ret.Timex = $"{DateTimeFormatUtil.LuisDate(date)}"; ret.FutureValue = ret.PastValue = date; ret.Success = true; return(ret); } var afterMatch = DateExtractor.AfterRegex.Match(suffix); if (afterMatch.Success && suffix.StartsWith(afterMatch.Value)) { DateObject date; switch (unitStr) { case Constants.TimexDay: date = referenceDate.AddDays(double.Parse(numStr)); break; case Constants.TimexWeek: date = referenceDate.AddDays(7 * double.Parse(numStr)); break; case Constants.TimexMonthFull: date = referenceDate.AddMonths(Convert.ToInt32(double.Parse(numStr))); break; case Constants.TimexYear: date = referenceDate.AddYears(Convert.ToInt32(double.Parse(numStr))); break; default: return(ret); } ret.Timex = $"{DateTimeFormatUtil.LuisDate(date)}"; ret.FutureValue = ret.PastValue = date; ret.Success = true; return(ret); } } } } return(ret); }
// case like "今年三月" "这个周末" "五月" private DateTimeResolutionResult ParseOneWordPeriod(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); int year = referenceDate.Year, month = referenceDate.Month; int futureYear = year, pastYear = year; var trimedText = text.Trim().ToLower(); var match = DatePeriodExtractorChs.OneWordPeriodRegex.Match(trimedText); if (match.Success && match.Index == 0 && match.Length == trimedText.Length) { var monthStr = match.Groups["month"].Value; if (trimedText.Equals("今年")) { ret.Timex = referenceDate.Year.ToString("D4"); ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(DateObject.MinValue.SafeCreateFromValue(referenceDate.Year, 1, 1), referenceDate); ret.Success = true; return(ret); } var thismatch = DatePeriodExtractorChs.ThisRegex.Match(trimedText); var nextmatch = DatePeriodExtractorChs.NextRegex.Match(trimedText); var lastmatch = DatePeriodExtractorChs.LastRegex.Match(trimedText); if (!string.IsNullOrEmpty(monthStr)) { var swift = -10; if (trimedText.StartsWith("明年")) { swift = 1; } else if (trimedText.StartsWith("去年")) { swift = -1; } else if (trimedText.StartsWith("今年")) { swift = 0; } month = this.config.MonthOfYear[monthStr.ToLower()]; if (swift >= -1) { ret.Timex = (referenceDate.Year + swift).ToString("D4") + "-" + month.ToString("D2"); year = year + swift; futureYear = pastYear = year; } else { ret.Timex = "XXXX-" + month.ToString("D2"); if (month < referenceDate.Month) { futureYear++; } if (month >= referenceDate.Month) { pastYear--; } } } else { var swift = 0; if (nextmatch.Success) { swift = 1; } else if (lastmatch.Success) { swift = -1; } if (trimedText.EndsWith("周") | trimedText.EndsWith("星期")) { var monday = referenceDate.This(DayOfWeek.Monday).AddDays(7 * swift); ret.Timex = monday.Year.ToString("D4") + "-W" + Cal.GetWeekOfYear(monday, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday) .ToString("D2"); ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>( referenceDate.This(DayOfWeek.Monday).AddDays(7 * swift), referenceDate.This(DayOfWeek.Sunday).AddDays(7 * swift).AddDays(1)); ret.Success = true; return(ret); } if (trimedText.EndsWith("周末")) { var beginDate = referenceDate.This(DayOfWeek.Saturday).AddDays(7 * swift); var endDate = referenceDate.This(DayOfWeek.Sunday).AddDays(7 * swift); ret.Timex = beginDate.Year.ToString("D4") + "-W" + Cal.GetWeekOfYear(beginDate, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday) .ToString("D2") + "-WE"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate.AddDays(1)); ret.Success = true; return(ret); } if (trimedText.EndsWith("月")) { month = referenceDate.AddMonths(swift).Month; year = referenceDate.AddMonths(swift).Year; ret.Timex = year.ToString("D4") + "-" + month.ToString("D2"); futureYear = pastYear = year; } else if (trimedText.EndsWith("年")) { year = referenceDate.AddYears(swift).Year; if (trimedText.EndsWith("去年")) { year--; } else if (trimedText.EndsWith("明年")) { year++; } else if (trimedText.EndsWith("前年")) { year -= 2; } else if (trimedText.EndsWith("后年")) { year += 2; } ret.Timex = year.ToString("D4"); ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(DateObject.MinValue.SafeCreateFromValue(year, 1, 1), DateObject.MinValue.SafeCreateFromValue(year, 12, 31).AddDays(1)); ret.Success = true; return(ret); } } } else { return(ret); } // only "month" will come to here ret.FutureValue = new Tuple <DateObject, DateObject>( DateObject.MinValue.SafeCreateFromValue(futureYear, month, 1), DateObject.MinValue.SafeCreateFromValue(futureYear, month, 1).AddMonths(1)); ret.PastValue = new Tuple <DateObject, DateObject>( DateObject.MinValue.SafeCreateFromValue(pastYear, month, 1), DateObject.MinValue.SafeCreateFromValue(pastYear, month, 1).AddMonths(1)); ret.Success = true; return(ret); }
private static DateTimeResolutionResult Match2Date(Match match, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); var holidayStr = match.Groups["holiday"].Value.ToLower(); var year = referenceDate.Year; var hasYear = false; var yearNum = match.Groups["year"].Value; var yearChs = match.Groups["yearchs"].Value; var yearRel = match.Groups["yearrel"].Value; if (!string.IsNullOrEmpty(yearNum)) { hasYear = true; if (yearNum.EndsWith("年")) { yearNum = yearNum.Substring(0, yearNum.Length - 1); } year = int.Parse(yearNum); } else if (!string.IsNullOrEmpty(yearChs)) { hasYear = true; if (yearChs.EndsWith("年")) { yearChs = yearChs.Substring(0, yearChs.Length - 1); } year = ConvertChineseToInteger(yearChs); } else if (!string.IsNullOrEmpty(yearRel)) { hasYear = true; if (yearRel.EndsWith("去年")) { year--; } else if (yearRel.EndsWith("明年")) { year++; } } if (year < 100 && year >= 90) { year += 1900; } else if (year < 20) { year += 2000; } if (!string.IsNullOrEmpty(holidayStr)) { DateObject value; string timexStr; if (FixedHolidaysDict.ContainsKey(holidayStr)) { value = FixedHolidaysDict[holidayStr](year); timexStr = $"-{value.Month:D2}-{value.Day:D2}"; } else { if (HolidayFuncDict.ContainsKey(holidayStr)) { value = HolidayFuncDict[holidayStr](year); timexStr = NoFixedTimex[holidayStr]; } else { return(ret); } } if (hasYear) { ret.Timex = year.ToString("D4") + timexStr; ret.FutureValue = ret.PastValue = DateObject.MinValue.SafeCreateFromValue(year, value.Month, value.Day); ret.Success = true; return(ret); } ret.Timex = "XXXX" + timexStr; ret.FutureValue = GetFutureValue(value, referenceDate, holidayStr); ret.PastValue = GetPastValue(value, referenceDate, holidayStr); ret.Success = true; return(ret); } return(ret); }
// only contains year like "2016年" private static DateTimeResolutionResult ParseYear(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); var match = DatePeriodExtractorChs.YearRegex.Match(text); if (match.Success && match.Length == text.Length) { var tmp = match.Value; if (tmp.EndsWith("年")) { tmp = tmp.Substring(0, tmp.Length - 1); } var num = 0; var year = 0; if (tmp.Length == 2) { num = int.Parse(tmp); if (num < 100 && num >= 20) { num += 1900; } else if (num < 20) { num += 2000; } year = num; } else { year = int.Parse(tmp); } var beginDay = DateObject.MinValue.SafeCreateFromValue(year, 1, 1); var endDay = DateObject.MinValue.SafeCreateFromValue(year + 1, 1, 1); ret.Timex = year.ToString("D4"); ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDay, endDay); ret.Success = true; return(ret); } match = DatePeriodExtractorChs.YearInChineseRegex.Match(text); if (match.Success && match.Length == text.Length) { var tmp = match.Value; if (tmp.EndsWith("年")) { tmp = tmp.Substring(0, tmp.Length - 1); } if (tmp.Length == 1) { return(ret); } var re = ConvertChineseToInteger(tmp); var year = re; if (year < 100 && year >= 90) { year += 1900; } else if (year < 100 && year < 20) { year += 2000; } var beginDay = DateObject.MinValue.SafeCreateFromValue(year, 1, 1); var endDay = DateObject.MinValue.SafeCreateFromValue(year + 1, 1, 1); ret.Timex = year.ToString("D4"); ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDay, endDay); ret.Success = true; return(ret); } return(ret); }
// parse "this night" private DateTimeResolutionResult ParseSpecificNight(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); var trimmedText = text.Trim().ToLowerInvariant(); int beginHour, endHour, endMin = 0; string timeStr; // handle 昨晚,今晨 var exactMatch = DateTimePeriodExtractor.SpecificTimeOfDayRegex.MatchExact(trimmedText, trim: true); if (exactMatch.Success) { var swift = 0; switch (trimmedText) { case "今晚": swift = 0; timeStr = "TEV"; beginHour = 16; endHour = 20; break; case "今早": case "今晨": swift = 0; timeStr = "TMO"; beginHour = 8; endHour = Constants.HalfDayHourCount; break; case "明晚": swift = 1; timeStr = "TEV"; beginHour = 16; endHour = 20; break; case "明早": case "明晨": swift = 1; timeStr = "TMO"; beginHour = 8; endHour = Constants.HalfDayHourCount; break; case "昨晚": swift = -1; timeStr = "TEV"; beginHour = 16; endHour = 20; break; default: return(ret); } var date = referenceTime.AddDays(swift).Date; int day = date.Day, month = date.Month, year = date.Year; ret.Timex = DateTimeFormatUtil.FormatDate(date) + timeStr; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(DateObject.MinValue.SafeCreateFromValue(year, month, day, beginHour, 0, 0), DateObject.MinValue.SafeCreateFromValue(year, month, day, endHour, endMin, endMin)); ret.Success = true; return(ret); } // handle morning, afternoon.. if (MORegex.IsMatch(trimmedText)) { timeStr = "TMO"; beginHour = 8; endHour = Constants.HalfDayHourCount; } else if (AFRegex.IsMatch(trimmedText)) { timeStr = "TAF"; beginHour = Constants.HalfDayHourCount; endHour = 16; } else if (EVRegex.IsMatch(trimmedText)) { timeStr = "TEV"; beginHour = 16; endHour = 20; } else if (NIRegex.IsMatch(trimmedText)) { timeStr = "TNI"; beginHour = 20; endHour = 23; endMin = 59; } else { return(ret); } exactMatch = DateTimePeriodExtractor.SpecificTimeOfDayRegex.MatchExact(trimmedText, trim: true); if (exactMatch.Success) { var swift = 0; if (DateTimePeriodExtractor.NextRegex.IsMatch(trimmedText)) { swift = 1; } else if (DateTimePeriodExtractor.LastRegex.IsMatch(trimmedText)) { swift = -1; } var date = referenceTime.AddDays(swift).Date; int day = date.Day, month = date.Month, year = date.Year; ret.Timex = DateTimeFormatUtil.FormatDate(date) + timeStr; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(DateObject.MinValue.SafeCreateFromValue(year, month, day, beginHour, 0, 0), DateObject.MinValue.SafeCreateFromValue(year, month, day, endHour, endMin, endMin)); ret.Success = true; return(ret); } // handle Date followed by morning, afternoon var match = DateTimePeriodExtractor.TimeOfDayRegex.Match(trimmedText); if (match.Success) { var beforeStr = trimmedText.Substring(0, match.Index).Trim(); var ers = SingleDateExtractor.Extract(beforeStr, referenceTime); if (ers.Count == 0 || ers[0].Length != beforeStr.Length) { return(ret); } var pr = this.config.DateParser.Parse(ers[0], referenceTime); var futureDate = (DateObject)((DateTimeResolutionResult)pr.Value).FutureValue; var pastDate = (DateObject)((DateTimeResolutionResult)pr.Value).PastValue; ret.Timex = pr.TimexStr + timeStr; 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, endMin, endMin)); 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, endMin, endMin)); ret.Success = true; return(ret); } return(ret); }
// handle like "前两年" "前三个月" private DateTimeResolutionResult ParseNumberWithUnit(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); string numStr, unitStr; // if there are NO spaces between number and unit var match = DatePeriodExtractorChs.NumberCombinedWithUnit.Match(text); if (match.Success) { var srcUnit = match.Groups["unit"].Value.ToLowerInvariant(); var beforeStr = text.Substring(0, match.Index).Trim().ToLowerInvariant(); if (this.config.UnitMap.ContainsKey(srcUnit)) { unitStr = this.config.UnitMap[srcUnit]; numStr = match.Groups["num"].Value; var prefixMatch = DatePeriodExtractorChs.PastRegex.Match(beforeStr); if (prefixMatch.Success && prefixMatch.Length == beforeStr.Length) { DateObject beginDate, endDate; switch (unitStr) { case "D": beginDate = referenceDate.AddDays(-double.Parse(numStr)); endDate = referenceDate; break; case "W": beginDate = referenceDate.AddDays(-7 * double.Parse(numStr)); endDate = referenceDate; break; case "MON": beginDate = referenceDate.AddMonths(-Convert.ToInt32(double.Parse(numStr))); endDate = referenceDate; break; case "Y": beginDate = referenceDate.AddYears(-Convert.ToInt32(double.Parse(numStr))); endDate = referenceDate; break; default: return(ret); } ret.Timex = $"({FormatUtil.LuisDate(beginDate)},{FormatUtil.LuisDate(endDate)},P{numStr}{unitStr[0]})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate); ret.Success = true; return(ret); } prefixMatch = DatePeriodExtractorChs.FutureRegex.Match(beforeStr); if (prefixMatch.Success && prefixMatch.Length == beforeStr.Length) { DateObject beginDate, endDate; switch (unitStr) { case "D": beginDate = referenceDate; endDate = referenceDate.AddDays(double.Parse(numStr)); break; case "W": beginDate = referenceDate; endDate = referenceDate.AddDays(7 * double.Parse(numStr)); break; case "MON": beginDate = referenceDate; endDate = referenceDate.AddMonths(Convert.ToInt32(double.Parse(numStr))); break; case "Y": beginDate = referenceDate; endDate = referenceDate.AddYears(Convert.ToInt32(double.Parse(numStr))); break; default: return(ret); } ret.Timex = $"({FormatUtil.LuisDate(beginDate.AddDays(1))},{FormatUtil.LuisDate(endDate.AddDays(1))},P{numStr}{unitStr[0]})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate.AddDays(1), endDate.AddDays(1)); ret.Success = true; return(ret); } } } // for case "前两年" "后三年" var durationRes = Durationextractor.Extract(text, referenceDate); if (durationRes.Count > 0) { var beforeStr = text.Substring(0, (int)durationRes[0].Start).Trim().ToLowerInvariant(); match = DatePeriodExtractorChs.UnitRegex.Match(durationRes[0].Text); if (match.Success) { var srcUnit = match.Groups["unit"].Value.ToLowerInvariant(); var numberStr = durationRes[0].Text.Substring(0, match.Index).Trim().ToLowerInvariant(); var number = ConvertChineseToNum(numberStr); if (this.config.UnitMap.ContainsKey(srcUnit)) { unitStr = this.config.UnitMap[srcUnit]; numStr = number.ToString(); var prefixMatch = DatePeriodExtractorChs.PastRegex.Match(beforeStr); if (prefixMatch.Success && prefixMatch.Length == beforeStr.Length) { DateObject beginDate, endDate; switch (unitStr) { case "D": beginDate = referenceDate.AddDays(-double.Parse(numStr)); endDate = referenceDate; break; case "W": beginDate = referenceDate.AddDays(-7 * double.Parse(numStr)); endDate = referenceDate; break; case "MON": beginDate = referenceDate.AddMonths(-Convert.ToInt32(double.Parse(numStr))); endDate = referenceDate; break; case "Y": beginDate = referenceDate.AddYears(-Convert.ToInt32(double.Parse(numStr))); endDate = referenceDate; break; default: return(ret); } ret.Timex = $"({FormatUtil.LuisDate(beginDate)},{FormatUtil.LuisDate(endDate)},P{numStr}{unitStr[0]})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate); ret.Success = true; return(ret); } prefixMatch = DatePeriodExtractorChs.FutureRegex.Match(beforeStr); if (prefixMatch.Success && prefixMatch.Length == beforeStr.Length) { DateObject beginDate, endDate; switch (unitStr) { case "D": beginDate = referenceDate; endDate = referenceDate.AddDays(double.Parse(numStr)); break; case "W": beginDate = referenceDate; endDate = referenceDate.AddDays(7 * double.Parse(numStr)); break; case "MON": beginDate = referenceDate; endDate = referenceDate.AddMonths(Convert.ToInt32(double.Parse(numStr))); break; case "Y": beginDate = referenceDate; endDate = referenceDate.AddYears(Convert.ToInt32(double.Parse(numStr))); break; default: return(ret); } ret.Timex = $"({FormatUtil.LuisDate(beginDate.AddDays(1))},{FormatUtil.LuisDate(endDate.AddDays(1))},P{numStr}{unitStr[0]})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate.AddDays(1), endDate.AddDays(1)); ret.Success = true; return(ret); } } } } return(ret); }
// match several other cases // including '今天', '后天', '十三日' protected DateTimeResolutionResult ParseImplicitDate(string text, DateObject referenceDate) { var trimedText = text.Trim(); var ret = new DateTimeResolutionResult(); int[] containsDay = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; // handle "十二日" "明年这个月三日" "本月十一日" var match = DateExtractorChs.SpecialDate.Match(trimedText); if (match.Success && match.Length == trimedText.Length) { int day = 0, month = referenceDate.Month, year = referenceDate.Year; var yearStr = match.Groups["thisyear"].Value.ToLower(); var monthStr = match.Groups["thismonth"].Value.ToLower(); var dayStr = match.Groups["day"].Value.ToLower(); day = this.config.DayOfMonth[dayStr]; bool hasYear = false, hasMonth = false; if (!string.IsNullOrEmpty(monthStr)) { hasMonth = true; if (DateExtractorChs.NextRe.Match(monthStr).Success) { month++; if (month == 13) { month = 1; year++; } } else if (DateExtractorChs.LastRe.Match(monthStr).Success) { month--; if (month == 0) { month = 12; year--; } } if (!string.IsNullOrEmpty(yearStr)) { hasYear = true; if (DateExtractorChs.NextRe.Match(yearStr).Success) { ++year; } else if (DateExtractorChs.LastRe.Match(yearStr).Success) { --year; } } } ret.Timex = FormatUtil.LuisDate(hasYear ? year : -1, hasMonth ? month : -1, day); var futureDate = DateObject.MinValue; var pastDate = DateObject.MinValue; if (day > containsDay[month - 1]) { futureDate = new DateObject(year, month + 1, day); pastDate = new DateObject(year, month - 1, day); } else { futureDate = new DateObject(year, month, day); pastDate = new DateObject(year, month, day); if (!hasMonth) { if (futureDate < referenceDate) { futureDate = futureDate.AddMonths(+1); } if (pastDate >= referenceDate) { pastDate = pastDate.AddMonths(-1); } } else if (hasMonth && !hasYear) { if (futureDate < referenceDate) { futureDate = futureDate.AddYears(+1); } if (pastDate >= referenceDate) { pastDate = pastDate.AddYears(-1); } } } ret.FutureValue = futureDate; ret.PastValue = pastDate; ret.Success = true; return(ret); } // handle "today", "the day before yesterday" match = DateExtractorChs.SpecialDayRegex.Match(trimedText); if (match.Success && match.Index == 0 && match.Length == trimedText.Length) { var value = referenceDate; if (match.Value.ToLower().Equals("今天") || match.Value.ToLower().Equals("今日") || match.Value.ToLower().Equals("最近")) { value = referenceDate; } else if (match.Value.ToLower().Equals("明天") || match.Value.ToLower().Equals("明日")) { value = referenceDate.AddDays(1); } else if (match.Value.ToLower().Equals("昨天")) { value = referenceDate.AddDays(-1); } else if (match.Value.ToLower().EndsWith("后天")) { value = referenceDate.AddDays(2); } else if (match.Value.ToLower().EndsWith("前天")) { value = referenceDate.AddDays(-2); } ret.Timex = FormatUtil.LuisDate(value); ret.FutureValue = ret.PastValue = value; ret.Success = true; return(ret); } if (!ret.Success) { ret = MatchThisWeekday(text, referenceDate); } if (!ret.Success) { ret = MatchLastWeekday(text, referenceDate); } if (!ret.Success) { ret = MatchWeekdayAlone(text, referenceDate); } return(ret); }
// case like "三月的第一周" private DateTimeResolutionResult ParseWeekOfMonth(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); var trimedText = text.Trim().ToLowerInvariant(); var match = DatePeriodExtractorChs.WeekOfMonthRegex.Match(text); if (!match.Success) { return(ret); } var cardinalStr = match.Groups["cardinal"].Value; var monthStr = match.Groups["month"].Value; var noYear = false; int year; int cardinal; if (cardinalStr.Equals("最后一")) { cardinal = 5; } else { cardinal = this.config.CardinalMap[cardinalStr]; } int month; if (string.IsNullOrEmpty(monthStr)) { var swift = 0; if (trimedText.StartsWith("下个")) { swift = 1; } else if (trimedText.StartsWith("上个")) { swift = -1; } month = referenceDate.AddMonths(swift).Month; year = referenceDate.AddMonths(swift).Year; ret.Timex = referenceDate.Year.ToString("D4") + "-" + month.ToString("D2"); } else { month = this.config.MonthOfYear[monthStr]; ret.Timex = "XXXX" + "-" + month.ToString("D2"); year = referenceDate.Year; noYear = true; } var value = ComputeDate(cardinal, 1, month, year); var futureDate = value; var pastDate = value; if (noYear && futureDate < referenceDate) { futureDate = ComputeDate(cardinal, 1, month, year + 1); if (futureDate.Month != month) { futureDate = futureDate.AddDays(-7); } } if (noYear && pastDate >= referenceDate) { pastDate = ComputeDate(cardinal, 1, month, year - 1); if (pastDate.Month != month) { pastDate = pastDate.AddDays(-7); } } ret.Timex += "-W" + cardinal.ToString("D2"); ret.FutureValue = new Tuple <DateObject, DateObject>(futureDate, futureDate.AddDays(7)); ret.PastValue = new Tuple <DateObject, DateObject>(pastDate, pastDate.AddDays(7)); ret.Success = true; return(ret); }
protected virtual DateTimeResolutionResult ParseWeekdayOfMonth(string text, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); var trimedText = text.Trim().ToLowerInvariant(); var match = this.config.WeekDayOfMonthRegex.Match(trimedText); if (!match.Success) { return(ret); } var cardinalStr = match.Groups["cardinal"].Value; var weekdayStr = match.Groups["weekday"].Value; var monthStr = match.Groups["month"].Value; var noYear = false; int year; int cardinal; if (cardinalStr.Equals(this.config.LastWeekDayToken)) { cardinal = 5; } else { cardinal = this.config.CardinalMap[cardinalStr]; } var weekday = this.config.DayOfWeek[weekdayStr]; int month; if (string.IsNullOrEmpty(monthStr)) { var swift = 0; if (trimedText.StartsWith(this.config.NextMonthToken)) { swift = 1; } else if (trimedText.StartsWith(this.config.LastMonthToken)) { swift = -1; } month = referenceDate.AddMonths(swift).Month; year = referenceDate.AddMonths(swift).Year; } else { month = this.config.MonthOfYear[monthStr]; year = referenceDate.Year; noYear = true; } var value = ComputeDate(cardinal, weekday, month, year); if (value.Month != month) { cardinal -= 1; value = value.AddDays(-7); } var futureDate = value; var pastDate = value; if (noYear && futureDate < referenceDate) { futureDate = ComputeDate(cardinal, weekday, month, year + 1); if (futureDate.Month != month) { futureDate = futureDate.AddDays(-7); } } if (noYear && pastDate >= referenceDate) { pastDate = ComputeDate(cardinal, weekday, month, year - 1); if (pastDate.Month != month) { pastDate = pastDate.AddDays(-7); } } // here is a very special case, timeX followe future date ret.Timex = $@"XXXX-{month:D2}-WXX-{weekday}-#{cardinal}"; ret.FutureValue = futureDate; ret.PastValue = pastDate; ret.Success = true; return(ret); }
private DateTimeResolutionResult Match2Date(Match match, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); var holidayStr = this.config.SanitizeHolidayToken(match.Groups["holiday"].Value); // get year (if exist) var yearStr = match.Groups["year"].Value; var orderStr = match.Groups["order"].Value; int year; var hasYear = false; if (!string.IsNullOrEmpty(yearStr)) { year = int.Parse(yearStr); hasYear = true; } else if (!string.IsNullOrEmpty(orderStr)) { var swift = this.config.GetSwiftYear(orderStr); if (swift < -1) { return(ret); } year = referenceDate.Year + swift; hasYear = true; } else { year = referenceDate.Year; } string holidayKey = string.Empty; foreach (var holidayPair in this.config.HolidayNames) { if (holidayPair.Value.Contains(holidayStr)) { holidayKey = holidayPair.Key; break; } } var timexStr = string.Empty; if (!string.IsNullOrEmpty(holidayKey)) { DateObject value; if (FixedHolidaysDict.ContainsKey(holidayKey)) { value = FixedHolidaysDict[holidayKey](year); timexStr = $"-{value.Month:D2}-{value.Day:D2}"; } else { if (HolidayFuncDict.ContainsKey(holidayKey)) { value = HolidayFuncDict[holidayKey](year); if (hasYear) { timexStr = $"-{value.Month:D2}-{value.Day:D2}"; } } else { return(ret); } } if (hasYear) { ret.Timex = year.ToString("D4") + timexStr; ret.FutureValue = ret.PastValue = DateObject.MinValue.SafeCreateFromValue(year, value.Month, value.Day); ret.Success = true; return(ret); } ret.Timex = "XXXX" + timexStr; ret.FutureValue = GetFutureValue(value, referenceDate, holidayKey); ret.PastValue = GetPastValue(value, referenceDate, holidayKey); ret.Success = true; return(ret); } return(ret); }
// parse a regex match which includes 'day', 'month' and 'year' (optional) group protected DateTimeResolutionResult Match2Date(Match match, DateObject referenceDate) { var ret = new DateTimeResolutionResult(); var monthStr = match.Groups["month"].Value.ToLower(); var dayStr = match.Groups["day"].Value.ToLower(); var yearStr = match.Groups["year"].Value.ToLower(); var yearChsStr = match.Groups["yearchs"].Value.ToLower(); int month = 0, day = 0, year = 0; var tmp = ConvertChineseYearToInteger(yearChsStr); year = tmp == -1 ? 0 : tmp; if (this.config.MonthOfYear.ContainsKey(monthStr) && this.config.DayOfMonth.ContainsKey(dayStr)) { month = this.config.MonthOfYear[monthStr] > 12 ? this.config.MonthOfYear[monthStr] % 12 : this.config.MonthOfYear[monthStr]; day = this.config.DayOfMonth[dayStr] > 31 ? this.config.DayOfMonth[dayStr] % 31 : this.config.DayOfMonth[dayStr]; if (!string.IsNullOrEmpty(yearStr)) { year = int.Parse(yearStr); if (year < 100 && year >= Constants.MinTwoDigitYearPastNum) { year += 1900; } else if (year >= 0 && year < Constants.MaxTwoDigitYearFutureNum) { year += 2000; } } } var noYear = false; if (year == 0) { year = referenceDate.Year; ret.Timex = FormatUtil.LuisDate(-1, month, day); noYear = true; } else { ret.Timex = FormatUtil.LuisDate(year, month, day); } var futureDate = DateObject.MinValue.SafeCreateFromValue(year, month, day); var pastDate = DateObject.MinValue.SafeCreateFromValue(year, month, day); if (noYear && futureDate < referenceDate) { futureDate = futureDate.AddYears(+1); } if (noYear && pastDate >= referenceDate) { pastDate = pastDate.AddYears(-1); } ret.FutureValue = futureDate; ret.PastValue = pastDate; ret.Success = true; return(ret); }
public static DateTimeResolutionResult Handle(IDateTimeParser timeParser, DateTimeExtra <PeriodType> extra, DateObject refTime) { //Left is a time var left = extra.NamedEntity["left"]; TimeResult leftResult, rightResult = null; // 下午四点十分到五点十分 if (extra.Type == PeriodType.FullTime) { var leftExtract = new ExtractResult { Start = left.Index, Length = left.Length, Text = left.Value, Type = Constants.SYS_DATETIME_TIME }; leftResult = timeParser.Parse(leftExtract, refTime).Data as TimeResult; } else { // 下午四到五点 leftResult = TimeFunctions.GetShortLeft(left.Value); } //Right is a time var right = extra.NamedEntity["right"]; var rightExtract = new ExtractResult { Start = right.Index, Length = right.Length, Text = right.Value, Type = Constants.SYS_DATETIME_TIME }; rightResult = timeParser.Parse(rightExtract, refTime).Data as TimeResult; var ret = new DateTimeResolutionResult() { Success = true }; //the right side doesn't contain desc while the left side does if (rightResult.LowBound == -1 && leftResult.LowBound != -1 && rightResult.Hour <= leftResult.LowBound) { rightResult.Hour += 12; } int day = refTime.Day, month = refTime.Month, year = refTime.Year; //determine if the right side time is smaller than the left side, if yes, add one day int hour = leftResult.Hour > 0 ? leftResult.Hour : 0, min = leftResult.Minute > 0 ? leftResult.Minute : 0, second = leftResult.Second > 0 ? leftResult.Second : 0; var leftTime = DateObject.MinValue.SafeCreateFromValue(year, month, day, hour, min, second); hour = rightResult.Hour > 0 ? rightResult.Hour : 0; min = rightResult.Minute > 0 ? rightResult.Minute : 0; second = rightResult.Second > 0 ? rightResult.Second : 0; var rightTime = DateObject.MinValue.SafeCreateFromValue(year, month, day, hour, min, second); if (rightTime.Hour < leftTime.Hour) { rightTime = rightTime.AddDays(1); } ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(leftTime, rightTime); var leftTimex = BuildTimex(leftResult); var rightTimex = BuildTimex(rightResult); ret.Timex = $"({leftTimex},{rightTimex},{BuildSpan(leftResult, rightResult)})"; return(ret); }