private DateTimeResolutionResult ParseDuration(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); var ers = config.DurationExtractor.Extract(text, referenceTime); if (ers.Count == 1) { var pr = config.DurationParser.Parse(ers[0]); var afterStr = text.Substring((pr.Start ?? 0) + (pr.Length ?? 0)).Trim(); if (pr.Value != null) { var swiftSeconds = 0; var mod = string.Empty; 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; var match = config.FutureRegex.Match(afterStr); if (match.Groups[Constants.WithinGroupName].Success) { endTime = beginTime.AddSeconds(swiftSeconds); ret.Timex = TimexUtility.GenerateDateTimePeriodTimex(beginTime, 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); }
// Handle cases like "Monday 7-9", where "7-9" can't be extracted by the TimePeriodExtractor private DateTimeResolutionResult ParsePureNumberCases(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); var trimmedText = text.Trim().ToLower(); var match = this.Config.PureNumberFromToRegex.Match(trimmedText); if (!match.Success) { match = this.Config.PureNumberBetweenAndRegex.Match(trimmedText); } if (match.Success && (match.Index == 0 || match.Index + match.Length == trimmedText.Length)) { int beginHour, endHour; ret.Comment = ParseTimePeriod(match, out beginHour, out endHour); var dateStr = string.Empty; // Parse following date var dateExtractResult = this.Config.DateExtractor.Extract(trimmedText.Replace(match.Value, ""), referenceTime); DateObject futureDate, pastDate; if (dateExtractResult.Count > 0) { var pr = this.Config.DateParser.Parse(dateExtractResult[0], referenceTime); if (pr.Value != null) { futureDate = (DateObject)((DateTimeResolutionResult)pr.Value).FutureValue; pastDate = (DateObject)((DateTimeResolutionResult)pr.Value).PastValue; dateStr = pr.TimexStr; if (((DateTimeResolutionResult)pr.Value).TimeZoneResolution != null) { ret.TimeZoneResolution = ((DateTimeResolutionResult)pr.Value).TimeZoneResolution; } } else { return(ret); } } else { return(ret); } var pastHours = endHour - beginHour; var beginTimex = TimexUtility.CombineDateAndTimeTimex(dateStr, DateTimeFormatUtil.ShortTime(beginHour)); var endTimex = TimexUtility.CombineDateAndTimeTimex(dateStr, DateTimeFormatUtil.ShortTime(endHour)); var durationTimex = TimexUtility.GenerateDurationTimex(endHour - beginHour, Constants.TimexHour, isLessThanDay: true); ret.Timex = TimexUtility.GenerateDateTimePeriodTimex(beginTimex, endTimex, durationTimex); 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, 0, 0)); 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, 0, 0)); ret.Success = true; } return(ret); }
private DateTimeResolutionResult MergeDateWithSingleTimePeriod(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); var trimmedText = text.Trim().ToLower(); var ers = Config.TimePeriodExtractor.Extract(trimmedText, referenceTime); if (ers.Count == 0) { return(ParsePureNumberCases(text, referenceTime)); } else if (ers.Count == 1) { var timePeriodParseResult = Config.TimePeriodParser.Parse(ers[0]); var timePeriodResolutionResult = (DateTimeResolutionResult)timePeriodParseResult.Value; if (timePeriodResolutionResult == null) { return(ParsePureNumberCases(text, referenceTime)); } if (timePeriodResolutionResult.TimeZoneResolution != null) { ret.TimeZoneResolution = timePeriodResolutionResult.TimeZoneResolution; } var timePeriodTimex = timePeriodResolutionResult.Timex; // If it is a range type timex if (TimexUtility.IsRangeTimex(timePeriodTimex)) { var dateResult = this.Config.DateExtractor.Extract(trimmedText.Replace(ers[0].Text, ""), referenceTime); var dateText = trimmedText.Replace(ers[0].Text, "").Replace(Config.TokenBeforeDate, "").Trim(); // If only one Date is extracted and the Date text equals to the rest part of source text if (dateResult.Count == 1 && dateText.Equals(dateResult[0].Text)) { string dateTimex; DateObject futureTime; DateObject pastTime; var pr = this.Config.DateParser.Parse(dateResult[0], referenceTime); if (pr.Value != null) { futureTime = (DateObject)((DateTimeResolutionResult)pr.Value).FutureValue; pastTime = (DateObject)((DateTimeResolutionResult)pr.Value).PastValue; dateTimex = pr.TimexStr; } else { return(ParsePureNumberCases(text, referenceTime)); } var rangeTimexComponents = TimexUtility.GetRangeTimexComponents(timePeriodTimex); if (rangeTimexComponents.IsValid) { var beginTimex = TimexUtility.CombineDateAndTimeTimex(dateTimex, rangeTimexComponents.BeginTimex); var endTimex = TimexUtility.CombineDateAndTimeTimex(dateTimex, rangeTimexComponents.EndTimex); ret.Timex = TimexUtility.GenerateDateTimePeriodTimex(beginTimex, endTimex, rangeTimexComponents.DurationTimex); var timePeriodFutureValue = (Tuple <DateObject, DateObject>)timePeriodResolutionResult.FutureValue; var beginTime = timePeriodFutureValue.Item1; var endTime = timePeriodFutureValue.Item2; ret.FutureValue = new Tuple <DateObject, DateObject>( DateObject.MinValue.SafeCreateFromValue(futureTime.Year, futureTime.Month, futureTime.Day, beginTime.Hour, beginTime.Minute, beginTime.Second), DateObject.MinValue.SafeCreateFromValue(futureTime.Year, futureTime.Month, futureTime.Day, endTime.Hour, endTime.Minute, endTime.Second) ); ret.PastValue = new Tuple <DateObject, DateObject>( DateObject.MinValue.SafeCreateFromValue(pastTime.Year, pastTime.Month, pastTime.Day, beginTime.Hour, beginTime.Minute, beginTime.Second), DateObject.MinValue.SafeCreateFromValue(pastTime.Year, pastTime.Month, pastTime.Day, endTime.Hour, endTime.Minute, endTime.Second) ); if (!string.IsNullOrEmpty(timePeriodResolutionResult.Comment) && timePeriodResolutionResult.Comment.Equals(Constants.Comment_AmPm)) { // AmPm comment is used for later SetParserResult to judge whether this parse result should have two parsing results // Cases like "from 10:30 to 11 on 1/1/2015" should have AmPm comment, as it can be parsed to "10:30am to 11am" and also be parsed to "10:30pm to 11pm" // Cases like "from 10:30 to 3 on 1/1/2015" should not have AmPm comment if (beginTime.Hour < Constants.HalfDayHourCount && endTime.Hour < Constants.HalfDayHourCount) { ret.Comment = Constants.Comment_AmPm; } } ret.Success = true; ret.SubDateTimeEntities = new List <object> { pr, timePeriodParseResult }; return(ret); } } return(ParsePureNumberCases(text, referenceTime)); } } return(ret); }
// Parse cases like "this night" private DateTimeResolutionResult ParseSpecificNight(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); var trimmedText = text.Trim(); int beginHour, endHour, endMin = 0; string timeStr; // Handle 昨晚 (last night),今晨 (this morning) if (this.config.SpecificTimeOfDayRegex.IsExactMatch(trimmedText, trim: true)) { // handle the ambiguous case "ぎりぎり" [the latest possible time] var latest = this.config.SpecificTimeOfDayRegex.Match(text); if (latest.Groups[Constants.LatestGroupName].Success) { DateObject beginDate, endDate; beginDate = referenceTime.AddMinutes(-1); endDate = referenceTime; var diff = endDate - beginDate; ret.Timex = TimexUtility.GenerateDateTimePeriodTimex(beginDate, endDate); ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate); ret.Success = true; return(ret); } if (!this.config.GetMatchedTimeRangeAndSwift(trimmedText, out timeStr, out beginHour, out endHour, out endMin, out int swift)) { return(ret); } if (this.config.NextRegex.IsMatch(trimmedText)) { swift = 1; } else if (this.config.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 cases like morning, afternoon if (!this.config.GetMatchedTimeRange(trimmedText, out timeStr, out beginHour, out endHour, out endMin)) { return(ret); } if (this.config.SpecificTimeOfDayRegex.IsExactMatch(trimmedText, trim: true)) { var swift = 0; if (this.config.NextRegex.IsMatch(trimmedText)) { swift = 1; } else if (this.config.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 = this.config.TimeOfDayRegex.Match(trimmedText); if (match.Success) { var beforeStr = trimmedText.Substring(0, match.Index).Trim(); var ers = this.config.DateExtractor.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); }
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 = this.config.TimeExtractor.Extract(text, referenceTime); var er2 = this.config.DateTimeExtractor.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); var match = config.FutureRegex.Match(text); // cases including 'within' are processed in ParseDuration if (match.Groups[Constants.WithinGroupName].Success) { return(ParseDuration(text, referenceTime)); } 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; if (futureBegin > futureEnd) { futureBegin = pastBegin; } 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) { leftTime = DateObject.MinValue.SafeCreateFromValue(futureBegin.Year, futureBegin.Month, futureBegin.Day); } else if (endHasDate) { 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; // 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).AddMinutes(min).AddSeconds(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).AddMinutes(min).AddSeconds(second); // the right side time contains "ampm", while the left side doesn't if (rightResult.Comment is 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 = pr1.TimexStr; var rightTimex = pr2.TimexStr; if (beginHasDate) { rightTimex = DateTimeFormatUtil.LuisDateShortTime(rightTime, pr2.TimexStr); } else if (endHasDate) { leftTimex = DateTimeFormatUtil.LuisDateShortTime(leftTime, pr1.TimexStr); } ret.Timex = TimexUtility.GenerateDateTimePeriodTimex(leftTimex, rightTimex, rightTime - leftTime); ret.Success = true; return(ret); }