// 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 > 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); } 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); }
// 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); }