public DateTimeParseResult Parse(ExtractResult er, DateObject refTime) { var referenceTime = refTime; DateTimeParseResult pr = null; // push, save teh MOD string bool hasBefore = false, hasAfter = false; var modStr = string.Empty; if (this.Config.BeforeRegex.IsMatch(er.Text)) { hasBefore = true; var match = this.Config.BeforeRegex.Match(er.Text); er.Start += match.Length; er.Length -= match.Length; er.Text = er.Text.Substring(match.Length); modStr = match.Value; } else if (this.Config.AfterRegex.IsMatch(er.Text)) { hasAfter = true; var match = this.Config.AfterRegex.Match(er.Text); er.Start += match.Length; er.Length -= match.Length; er.Text = er.Text.Substring(match.Length); modStr = match.Value; } if (er.Type.Equals(Constants.SYS_DATETIME_DATE)) { pr = this.Config.DateParser.Parse(er, referenceTime); if (pr.Value == null) { pr = Config.HolidayParser.Parse(er, referenceTime); } } else if (er.Type.Equals(Constants.SYS_DATETIME_TIME)) { pr = this.Config.TimeParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DATETIME)) { pr = this.Config.DateTimeParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DATEPERIOD)) { pr = this.Config.DatePeriodParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_TIMEPERIOD)) { pr = this.Config.TimePeriodParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DATETIMEPERIOD)) { pr = this.Config.DateTimePeriodParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DURATION)) { pr = this.Config.DurationParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_SET)) { pr = this.Config.GetParser.Parse(er, referenceTime); } else { return(null); } // pop, restore the MOD string if (hasBefore) { pr.Length += modStr.Length; pr.Start -= modStr.Length; pr.Text = modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; val.Mod = TimeTypeConstants.beforeMod; pr.Value = val; } if (hasAfter) { pr.Length += modStr.Length; pr.Start -= modStr.Length; pr.Text = modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; val.Mod = TimeTypeConstants.afterMod; pr.Value = val; } pr.Value = DateTimeResolution(pr, hasBefore, hasAfter); //change the type at last for the after or before mode pr.Type = $"{ParserTypeName}.{DetermineDateTimeType(er.Type, hasBefore, hasAfter)}"; return(pr); }
public DateTimeParseResult Parse(ExtractResult er, DateObject refTime) { var referenceTime = refTime; object value = null; if (er.Type.Equals(ParserName, StringComparison.Ordinal)) { DateTimeResolutionResult innerResult; if (TimeZoneUtility.ShouldResolveTimeZone(er, config.Options)) { var metadata = er.Data as Dictionary <string, object>; var timezoneEr = metadata[Constants.SYS_DATETIME_TIMEZONE] as ExtractResult; var timezonePr = config.TimeZoneParser.Parse(timezoneEr); innerResult = InternalParse( er.Text.Substring(0, (int)(er.Length - timezoneEr.Length)), referenceTime); if (timezonePr != null && timezonePr.Value != null) { innerResult.TimeZoneResolution = ((DateTimeResolutionResult)timezonePr.Value).TimeZoneResolution; } } else { innerResult = InternalParse(er.Text, referenceTime); } if (innerResult.Success) { innerResult.FutureResolution = new Dictionary <string, string> { { TimeTypeConstants.START_TIME, DateTimeFormatUtil.FormatTime(((Tuple <DateObject, DateObject>)innerResult.FutureValue).Item1) }, { TimeTypeConstants.END_TIME, DateTimeFormatUtil.FormatTime(((Tuple <DateObject, DateObject>)innerResult.FutureValue).Item2) }, }; innerResult.PastResolution = new Dictionary <string, string> { { TimeTypeConstants.START_TIME, DateTimeFormatUtil.FormatTime(((Tuple <DateObject, DateObject>)innerResult.PastValue).Item1) }, { TimeTypeConstants.END_TIME, DateTimeFormatUtil.FormatTime(((Tuple <DateObject, DateObject>)innerResult.PastValue).Item2) }, }; value = innerResult; } } var ret = new DateTimeParseResult { Text = er.Text, Start = er.Start, Length = er.Length, Type = er.Type, Data = er.Data, Value = value, TimexStr = value == null ? string.Empty : ((DateTimeResolutionResult)value).Timex, ResolutionStr = string.Empty, }; return(ret); }
public DateTimeParseResult Parse(ExtractResult er, DateObject refTime) { var referenceTime = refTime; object value = null; if (er.Type.Equals(ParserName)) { var innerResult = ParseSimpleCases(er.Text, referenceTime); if (!innerResult.Success) { innerResult = MergeTwoTimePoints(er.Text, referenceTime); } if (!innerResult.Success) { innerResult = ParseTimeOfDay(er.Text, referenceTime); } if (innerResult.Success) { innerResult.FutureResolution = new Dictionary <string, string> { { TimeTypeConstants.START_TIME, FormatUtil.FormatTime(((Tuple <DateObject, DateObject>)innerResult.FutureValue).Item1) }, { TimeTypeConstants.END_TIME, FormatUtil.FormatTime(((Tuple <DateObject, DateObject>)innerResult.FutureValue).Item2) } }; innerResult.PastResolution = new Dictionary <string, string> { { TimeTypeConstants.START_TIME, FormatUtil.FormatTime(((Tuple <DateObject, DateObject>)innerResult.PastValue).Item1) }, { TimeTypeConstants.END_TIME, FormatUtil.FormatTime(((Tuple <DateObject, DateObject>)innerResult.PastValue).Item2) } }; value = innerResult; } } var ret = new DateTimeParseResult { Text = er.Text, Start = er.Start, Length = er.Length, Type = er.Type, Data = er.Data, Value = value, TimexStr = value == null ? "" : ((DateTimeResolutionResult)value).Timex, ResolutionStr = "" }; return(ret); }
public SortedDictionary <string, object> DateTimeResolution(DateTimeParseResult slot) { if (slot == null) { return(null); } var resolutions = new List <Dictionary <string, string> >(); var res = new Dictionary <string, object>(); var type = slot.Type; var timex = slot.TimexStr; var val = (DateTimeResolutionResult)slot.Value; if (val == null) { return(null); } var isLunar = val.IsLunar; var mod = val.Mod; string list = null; // Resolve dates list for date periods if (slot.Type.Equals(Constants.SYS_DATETIME_DATEPERIOD, StringComparison.Ordinal) && val.List != null) { list = string.Join(",", val.List.Select(o => DateTimeFormatUtil.LuisDate((DateObject)o)).ToArray()); } // With modifier, output Type might not be the same with type in resolution result // For example, if the resolution type is "date", with modifier the output type should be "daterange" var typeOutput = DetermineDateTimeType(slot.Type, hasMod: !string.IsNullOrEmpty(mod)); var sourceEntity = DetermineSourceEntityType(slot.Type, typeOutput, val.HasRangeChangingMod); var comment = val.Comment; // The following should be added to res first, since ResolveAmPm requires these fields. AddResolutionFields(res, DateTimeResolutionKey.Timex, timex); AddResolutionFields(res, Constants.Comment, comment); AddResolutionFields(res, DateTimeResolutionKey.Mod, mod); AddResolutionFields(res, ResolutionKey.Type, typeOutput); AddResolutionFields(res, DateTimeResolutionKey.IsLunar, isLunar ? isLunar.ToString() : string.Empty); var hasTimeZone = false; // For standalone timezone entity recognition, we generate TimeZoneResolution for each entity we extracted. // We also merge time entity with timezone entity and add the information in TimeZoneResolution to every DateTime resolutions. if (val.TimeZoneResolution != null) { if (slot.Type.Equals(Constants.SYS_DATETIME_TIMEZONE, StringComparison.Ordinal)) { // single timezone AddResolutionFields(res, Constants.ResolveTimeZone, new Dictionary <string, string> { { ResolutionKey.Value, val.TimeZoneResolution.Value }, { Constants.UtcOffsetMinsKey, val.TimeZoneResolution.UtcOffsetMins.ToString() }, }); } else { // timezone as clarification of datetime hasTimeZone = true; AddResolutionFields(res, Constants.TimeZone, val.TimeZoneResolution.Value); AddResolutionFields(res, Constants.TimeZoneText, val.TimeZoneResolution.TimeZoneText); AddResolutionFields(res, Constants.UtcOffsetMinsKey, val.TimeZoneResolution.UtcOffsetMins.ToString()); } } var pastResolutionStr = ((DateTimeResolutionResult)slot.Value).PastResolution; var futureResolutionStr = ((DateTimeResolutionResult)slot.Value).FutureResolution; if (typeOutput == Constants.SYS_DATETIME_DATETIMEALT && pastResolutionStr.Count > 0) { typeOutput = DetermineResolutionDateTimeType(pastResolutionStr); } var resolutionPast = GenerateResolution(type, pastResolutionStr, mod); var resolutionFuture = GenerateResolution(type, futureResolutionStr, mod); // If past and future are same, keep only one if (resolutionFuture.OrderBy(t => t.Key).Select(t => t.Value) .SequenceEqual(resolutionPast.OrderBy(t => t.Key).Select(t => t.Value))) { if (resolutionPast.Count > 0) { AddResolutionFields(res, Constants.Resolve, resolutionPast); } } else { if (resolutionPast.Count > 0) { AddResolutionFields(res, Constants.ResolveToPast, resolutionPast); } if (resolutionFuture.Count > 0) { AddResolutionFields(res, Constants.ResolveToFuture, resolutionFuture); } } // If 'ampm', double our resolution accordingly if (!string.IsNullOrEmpty(comment) && comment.Equals(Constants.Comment_AmPm, StringComparison.Ordinal)) { if (res.ContainsKey(Constants.Resolve)) { ResolveAmpm(res, Constants.Resolve); } else { ResolveAmpm(res, Constants.ResolveToPast); ResolveAmpm(res, Constants.ResolveToFuture); } } // If WeekOf and in CalendarMode, modify the past part of our resolution if ((Config.Options & DateTimeOptions.CalendarMode) != 0 && !string.IsNullOrEmpty(comment) && comment.Equals(Constants.Comment_WeekOf, StringComparison.Ordinal)) { ResolveWeekOf(res, Constants.ResolveToPast); } foreach (var p in res) { if (p.Value is Dictionary <string, string> dictionary) { var value = new Dictionary <string, string>(); AddResolutionFields(value, DateTimeResolutionKey.Timex, timex); AddResolutionFields(value, DateTimeResolutionKey.Mod, mod); AddResolutionFields(value, ResolutionKey.Type, typeOutput); AddResolutionFields(value, DateTimeResolutionKey.IsLunar, isLunar ? isLunar.ToString() : string.Empty); AddResolutionFields(value, DateTimeResolutionKey.List, list); AddResolutionFields(value, DateTimeResolutionKey.SourceEntity, sourceEntity); if (hasTimeZone) { AddResolutionFields(value, Constants.TimeZone, val.TimeZoneResolution.Value); AddResolutionFields(value, Constants.TimeZoneText, val.TimeZoneResolution.TimeZoneText); AddResolutionFields(value, Constants.UtcOffsetMinsKey, val.TimeZoneResolution.UtcOffsetMins.ToString()); } foreach (var q in dictionary) { if (value.ContainsKey(q.Key)) { value[q.Key] = q.Value; } else { value.Add(q.Key, q.Value); } } resolutions.Add(value); } } if (resolutionPast.Count == 0 && resolutionFuture.Count == 0 && val.TimeZoneResolution == null) { var notResolved = new Dictionary <string, string> { { DateTimeResolutionKey.Timex, timex }, { ResolutionKey.Type, typeOutput }, { ResolutionKey.Value, "not resolved" }, }; resolutions.Add(notResolved); } return(new SortedDictionary <string, object> { { ResolutionKey.ValueSet, resolutions } }); }
public DateTimeParseResult Parse(ExtractResult er, DateObject referenceTime) { DateTimeParseResult pr = null; // push, save teh MOD string bool hasBefore = false, hasAfter = false, hasUntil = false, hasSince = false; string modStr = string.Empty, modStrPrefix = string.Empty, modStrSuffix = string.Empty; var beforeMatch = config.BeforeRegex.MatchEnd(er.Text, trim: true); var afterMatch = config.AfterRegex.MatchEnd(er.Text, trim: true); var untilMatch = config.UntilRegex.MatchBegin(er.Text, trim: true); var sinceMatchPrefix = config.SincePrefixRegex.MatchBegin(er.Text, trim: true); var sinceMatchSuffix = config.SinceSuffixRegex.MatchEnd(er.Text, trim: true); if (beforeMatch.Success && !IsDurationWithBeforeAndAfter(er)) { hasBefore = true; er.Length -= beforeMatch.Length; er.Text = er.Text.Substring(0, er.Length ?? 0); modStr = beforeMatch.Value; } else if (afterMatch.Success && !IsDurationWithBeforeAndAfter(er)) { hasAfter = true; er.Length -= afterMatch.Length; er.Text = er.Text.Substring(0, er.Length ?? 0); modStr = afterMatch.Value; } else if (untilMatch.Success) { hasUntil = true; er.Start += untilMatch.Length; er.Length -= untilMatch.Length; er.Text = er.Text.Substring(untilMatch.Length); modStr = untilMatch.Value; } else { if (sinceMatchPrefix.Success) { hasSince = true; er.Start += sinceMatchPrefix.Length; er.Length -= sinceMatchPrefix.Length; er.Text = er.Text.Substring(sinceMatchPrefix.Length); modStrPrefix = sinceMatchPrefix.Value; } if (sinceMatchSuffix.Success) { hasSince = true; er.Length -= sinceMatchSuffix.Length; er.Text = er.Text.Substring(0, er.Length ?? 0); modStrSuffix = sinceMatchSuffix.Value; } } if (er.Type.Equals(Constants.SYS_DATETIME_DATE)) { pr = config.DateParser.Parse(er, referenceTime); if (pr.Value == null) { pr = config.HolidayParser.Parse(er, referenceTime); } } else if (er.Type.Equals(Constants.SYS_DATETIME_TIME)) { pr = config.TimeParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DATETIME)) { pr = config.DateTimeParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DATEPERIOD)) { pr = config.DatePeriodParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_TIMEPERIOD)) { pr = config.TimePeriodParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DATETIMEPERIOD)) { pr = config.DateTimePeriodParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DURATION)) { pr = config.DurationParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_SET)) { pr = config.GetParser.Parse(er, referenceTime); } else { return(null); } // pop, restore the MOD string if (hasBefore) { pr.Length += modStr.Length; pr.Text = pr.Text + modStr; var val = (DateTimeResolutionResult)pr.Value; val.Mod = Constants.BEFORE_MOD; pr.Value = val; } if (hasAfter) { pr.Length += modStr.Length; pr.Text = pr.Text + modStr; var val = (DateTimeResolutionResult)pr.Value; val.Mod = Constants.AFTER_MOD; pr.Value = val; } if (hasUntil) { pr.Length += modStr.Length; pr.Start -= modStr.Length; pr.Text = modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; val.Mod = Constants.BEFORE_MOD; pr.Value = val; hasBefore = true; } if (hasSince) { pr.Length += modStrPrefix.Length + modStrSuffix.Length; pr.Start -= modStrPrefix.Length; pr.Text = modStrPrefix + pr.Text + modStrSuffix; var val = (DateTimeResolutionResult)pr.Value; val.Mod = Constants.SINCE_MOD; pr.Value = val; } pr.Value = DateTimeResolution(pr, hasBefore, hasAfter, hasSince); // change the type at last for the after or before mode pr.Type = $"{ParserTypeName}.{DetermineDateTimeType(er.Type, hasBefore, hasAfter, hasSince)}"; return(pr); }
public DateTimeParseResult Parse(ExtractResult er, DateObject refDate) { var referenceTime = refDate; var extra = er.Data as DateTimeExtra <PeriodType>; if (extra == null) { var result = this.config.TimeExtractor.Extract(er.Text, refDate); extra = result[0]?.Data as DateTimeExtra <PeriodType>; } if (extra != null) { // Handle special case like '上午' (morning), '下午' (afternoon) var parseResult = ParseTimeOfDay(er.Text, referenceTime); if (!parseResult.Success) { parseResult = TimePeriodFunctions.Handle(this.config.TimeParser, extra, referenceTime, this.config.TimeFunc); } if (parseResult.Success) { parseResult.FutureResolution = new Dictionary <string, string> { { TimeTypeConstants.START_TIME, DateTimeFormatUtil.FormatTime(((Tuple <DateObject, DateObject>)parseResult.FutureValue).Item1) }, { TimeTypeConstants.END_TIME, DateTimeFormatUtil.FormatTime(((Tuple <DateObject, DateObject>)parseResult.FutureValue).Item2) }, }; parseResult.PastResolution = new Dictionary <string, string> { { TimeTypeConstants.START_TIME, DateTimeFormatUtil.FormatTime(((Tuple <DateObject, DateObject>)parseResult.PastValue).Item1) }, { TimeTypeConstants.END_TIME, DateTimeFormatUtil.FormatTime(((Tuple <DateObject, DateObject>)parseResult.PastValue).Item2) }, }; } var ret = new DateTimeParseResult { Start = er.Start, Text = er.Text, Type = er.Type, Length = er.Length, Value = parseResult, ResolutionStr = string.Empty, TimexStr = parseResult.Timex, }; return(ret); } return(null); }
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); 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 (bothHaveDates) { if (futureBegin > futureEnd) { futureBegin = pastBegin; } if (pastEnd < pastBegin) { pastEnd = futureEnd; } } if (bothHaveDates) { ret.Timex = $"({pr1.TimexStr},{pr2.TimexStr},PT{Convert.ToInt32((futureEnd - futureBegin).TotalHours)}H)"; // Do nothing } else if (beginHasDate) { 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); var dateStr = pr1.TimexStr.Split('T')[0]; ret.Timex = $"({pr1.TimexStr},{dateStr + pr2.TimexStr},PT{Convert.ToInt32((futureEnd - futureBegin).TotalHours)}H)"; } else if (endHasDate) { 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); var dateStr = pr2.TimexStr.Split('T')[0]; ret.Timex = $"({dateStr + pr1.TimexStr},{pr2.TimexStr},PT{Convert.ToInt32((futureEnd - futureBegin).TotalHours)}H)"; } var ampmStr1 = ((DateTimeResolutionResult)pr1.Value).Comment; var ampmStr2 = ((DateTimeResolutionResult)pr2.Value).Comment; if (!string.IsNullOrEmpty(ampmStr1) && ampmStr1.EndsWith(Constants.Comment_AmPm) && !string.IsNullOrEmpty(ampmStr2) && ampmStr2.EndsWith(Constants.Comment_AmPm)) { ret.Comment = Constants.Comment_AmPm; } ret.FutureValue = new Tuple <DateObject, DateObject>(futureBegin, futureEnd); ret.PastValue = new Tuple <DateObject, DateObject>(pastBegin, pastEnd); ret.Success = true; ret.SubDateTimeEntities = new List <object> { pr1, pr2 }; return(ret); }
// This will parse to a date ranging between the holiday and the closest weekend // cases: "Thanksgiving weekend", "weekend of Halloween" private DateTimeParseResult ParseHolidayWeekend(ExtractResult er, DateObject referenceDate) { var dateTimeRes = new DateTimeResolutionResult(); if (!string.IsNullOrEmpty(er.Metadata?.HolidayName)) { var holidayName = er.Metadata.HolidayName; // resolve holiday var holidayEr = new ExtractResult { Start = 0, Length = holidayName.Length, Text = holidayName, Type = Constants.SYS_DATETIME_DATE, Data = null, Metadata = new Metadata { IsHoliday = true }, }; var result = (DateTimeResolutionResult)this.Parse(holidayEr, referenceDate).Value; if (!result.Success) { dateTimeRes.FutureResolution = dateTimeRes.PastResolution = new Dictionary <string, string>(); } else { // get closest weekend to the holiday(s) var futureWeekend = GetClosestHolidayWeekend((DateObject)result.FutureValue); var pastWeekend = futureWeekend; if (result.FutureValue == result.PastValue) { dateTimeRes.Timex = TimexUtility.GenerateWeekendTimex(futureWeekend.Item1); } else { dateTimeRes.Timex = result.Timex; pastWeekend = GetClosestHolidayWeekend((DateObject)result.PastValue); } dateTimeRes.Success = true; dateTimeRes.FutureValue = futureWeekend; dateTimeRes.PastValue = pastWeekend; dateTimeRes.FutureResolution = new Dictionary <string, string> { { TimeTypeConstants.START_DATE, DateTimeFormatUtil.FormatDate(((Tuple <DateObject, DateObject>)dateTimeRes.FutureValue).Item1) }, { TimeTypeConstants.END_DATE, DateTimeFormatUtil.FormatDate(((Tuple <DateObject, DateObject>)dateTimeRes.FutureValue).Item2) }, { DateTimeResolutionKey.Timex, TimexUtility.GenerateWeekendTimex(futureWeekend.Item1) }, }; dateTimeRes.PastResolution = new Dictionary <string, string> { { TimeTypeConstants.START_DATE, DateTimeFormatUtil.FormatDate(((Tuple <DateObject, DateObject>)dateTimeRes.PastValue).Item1) }, { TimeTypeConstants.END_DATE, DateTimeFormatUtil.FormatDate(((Tuple <DateObject, DateObject>)dateTimeRes.PastValue).Item2) }, { DateTimeResolutionKey.Timex, TimexUtility.GenerateWeekendTimex(pastWeekend.Item1) }, }; } } else { dateTimeRes.FutureResolution = dateTimeRes.PastResolution = new Dictionary <string, string>(); } var ret = new DateTimeParseResult { Text = er.Text, Start = er.Start, Length = er.Length, Type = er.Type, Data = er.Data, Metadata = er.Metadata, Value = dateTimeRes, TimexStr = dateTimeRes == null ? string.Empty : ((DateTimeResolutionResult)dateTimeRes).Timex, ResolutionStr = string.Empty, }; return(ret); }
public DateTimeParseResult Parse(ExtractResult er, DateObject refTime) { var referenceTime = refTime; DateTimeParseResult pr = null; var originText = er.Text; if ((this.Config.Options & DateTimeOptions.EnablePreview) != 0) { er.Text = MatchingUtil.PreProcessTextRemoveSuperfluousWords(er.Text, Config.SuperfluousWordMatcher, out var _); er.Length += er.Text.Length - originText.Length; } // Push, save the MOD string bool hasBefore = false, hasAfter = false, hasSince = false, hasYearAfter = false; // "InclusieModifier" means MOD should include the start/end time // For example, cases like "on or later than", "earlier than or in" have inclusive modifier bool hasInclusiveModifier = false; var modStr = string.Empty; var beforeMatch = Config.BeforeRegex.Match(er.Text); var afterMatch = Config.AfterRegex.Match(er.Text); var sinceMatch = Config.SinceRegex.Match(er.Text); if (beforeMatch.Success && beforeMatch.Index == 0) { hasBefore = true; er.Start += beforeMatch.Length; er.Length -= beforeMatch.Length; er.Text = er.Text.Substring(beforeMatch.Length); modStr = beforeMatch.Value; if (!string.IsNullOrEmpty(beforeMatch.Groups["include"].Value)) { hasInclusiveModifier = true; } } else if (afterMatch.Success && afterMatch.Index == 0) { hasAfter = true; er.Start += afterMatch.Length; er.Length -= afterMatch.Length; er.Text = er.Text.Substring(afterMatch.Length); modStr = afterMatch.Value; if (!string.IsNullOrEmpty(afterMatch.Groups["include"].Value)) { hasInclusiveModifier = true; } } else if (sinceMatch.Success && sinceMatch.Index == 0) { hasSince = true; er.Start += sinceMatch.Length; er.Length -= sinceMatch.Length; er.Text = er.Text.Substring(sinceMatch.Length); modStr = sinceMatch.Value; } else if (er.Type.Equals(Constants.SYS_DATETIME_DATEPERIOD) && Config.YearRegex.Match(er.Text).Success) { // This has to be put at the end of the if, or cases like "before 2012" and "after 2012" would fall into this // 2012 or after/above var match = Config.YearAfterRegex.Match(er.Text); if (match.Success && er.Text.EndsWith(match.Value)) { hasYearAfter = true; er.Length -= match.Length; er.Text = er.Text.Substring(0, er.Length ?? 0); modStr = match.Value; } } if (er.Type.Equals(Constants.SYS_DATETIME_DATE)) { pr = this.Config.DateParser.Parse(er, referenceTime); if (pr.Value == null) { pr = Config.HolidayParser.Parse(er, referenceTime); } } else if (er.Type.Equals(Constants.SYS_DATETIME_TIME)) { pr = this.Config.TimeParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DATETIME)) { pr = this.Config.DateTimeParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DATEPERIOD)) { pr = this.Config.DatePeriodParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_TIMEPERIOD)) { pr = this.Config.TimePeriodParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DATETIMEPERIOD)) { pr = this.Config.DateTimePeriodParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DURATION)) { pr = this.Config.DurationParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_SET)) { pr = this.Config.SetParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DATETIMEALT)) { pr = this.Config.DateTimeAltParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_TIMEZONE)) { if ((Config.Options & DateTimeOptions.EnablePreview) != 0) { pr = this.Config.TimeZoneParser.Parse(er, referenceTime); } } else { return(null); } // Pop, restore the MOD string if (hasBefore && pr.Value != null) { pr.Length += modStr.Length; pr.Start -= modStr.Length; pr.Text = modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; if (!hasInclusiveModifier) { val.Mod = Constants.BEFORE_MOD; } else { val.Mod = Constants.UNTIL_MOD; } pr.Value = val; } if (hasAfter && pr.Value != null) { pr.Length += modStr.Length; pr.Start -= modStr.Length; pr.Text = modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; if (!hasInclusiveModifier) { val.Mod = Constants.AFTER_MOD; } else { val.Mod = Constants.SINCE_MOD; } pr.Value = val; } if (hasSince && pr.Value != null) { pr.Length += modStr.Length; pr.Start -= modStr.Length; pr.Text = modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; val.Mod = Constants.SINCE_MOD; pr.Value = val; } if (hasYearAfter && pr.Value != null) { pr.Length += modStr.Length; pr.Text = pr.Text + modStr; var val = (DateTimeResolutionResult)pr.Value; val.Mod = Constants.SINCE_MOD; pr.Value = val; hasSince = true; } if ((Config.Options & DateTimeOptions.SplitDateAndTime) != 0 && ((DateTimeResolutionResult)pr.Value)?.SubDateTimeEntities != null) { pr.Value = DateTimeResolutionForSplit(pr); } else { var hasModifier = hasBefore || hasAfter || hasSince; pr = SetParseResult(pr, hasModifier); } // In this version, ExperimentalMode only cope with the "IncludePeriodEnd" case if ((this.Config.Options & DateTimeOptions.ExperimentalMode) != 0) { if (pr.Metadata != null && pr.Metadata.PossiblyIncludePeriodEnd) { pr = SetInclusivePeriodEnd(pr); } } if ((this.Config.Options & DateTimeOptions.EnablePreview) != 0) { pr.Length += originText.Length - pr.Text.Length; pr.Text = originText; } return(pr); }
public DateTimeParseResult Parse(ExtractResult er, DateObject refTime) { var referenceTime = refTime; object value = null; if (er.Type.Equals(ParserName)) { var innerResult = InternalParse(er.Text, referenceTime); // Handling timeZone if (innerResult.Success && TimeZoneUtility.ShouldResolveTimeZone(er, this.Config.Options)) { var metadata = er.Data as Dictionary <string, object>; var timezoneEr = metadata[Constants.SYS_DATETIME_TIMEZONE] as ExtractResult; var timezonePr = this.Config.TimeZoneParser.Parse(timezoneEr); if (timezonePr != null && timezonePr.Value != null) { innerResult.TimeZoneResolution = ((DateTimeResolutionResult)timezonePr.Value).TimeZoneResolution; } } if (innerResult.Success) { if (!IsBeforeOrAfterMod(innerResult.Mod)) { innerResult.FutureResolution = new Dictionary <string, string> { { TimeTypeConstants.START_DATETIME, DateTimeFormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)innerResult.FutureValue).Item1) }, { TimeTypeConstants.END_DATETIME, DateTimeFormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)innerResult.FutureValue).Item2) }, }; innerResult.PastResolution = new Dictionary <string, string> { { TimeTypeConstants.START_DATETIME, DateTimeFormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)innerResult.PastValue).Item1) }, { TimeTypeConstants.END_DATETIME, DateTimeFormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)innerResult.PastValue).Item2) }, }; } else { if (innerResult.Mod == Constants.AFTER_MOD) { // Cases like "1/1/2015 after 2:00" there is no EndTime innerResult.FutureResolution = new Dictionary <string, string> { { TimeTypeConstants.START_DATETIME, DateTimeFormatUtil.FormatDateTime((DateObject)innerResult.FutureValue) }, }; innerResult.PastResolution = new Dictionary <string, string> { { TimeTypeConstants.START_DATETIME, DateTimeFormatUtil.FormatDateTime((DateObject)innerResult.PastValue) }, }; } else { // Cases like "1/1/2015 before 5:00 in the afternoon" there is no StartTime innerResult.FutureResolution = new Dictionary <string, string> { { TimeTypeConstants.END_DATETIME, DateTimeFormatUtil.FormatDateTime((DateObject)innerResult.FutureValue) }, }; innerResult.PastResolution = new Dictionary <string, string> { { TimeTypeConstants.END_DATETIME, DateTimeFormatUtil.FormatDateTime((DateObject)innerResult.PastValue) }, }; } } value = innerResult; } } var ret = new DateTimeParseResult { Text = er.Text, Start = er.Start, Length = er.Length, Type = er.Type, Data = er.Data, Value = value, TimexStr = value == null ? string.Empty : ((DateTimeResolutionResult)value).Timex, ResolutionStr = string.Empty, }; 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 timeExtractResults = this.Config.TimeExtractor.Extract(text, referenceTime); var dateTimeExtractResults = this.Config.DateTimeExtractor.Extract(text, referenceTime); if (dateTimeExtractResults.Count == 2) { pr1 = this.Config.DateTimeParser.Parse(dateTimeExtractResults[0], referenceTime); pr2 = this.Config.DateTimeParser.Parse(dateTimeExtractResults[1], referenceTime); bothHaveDates = true; } else if (dateTimeExtractResults.Count == 1 && timeExtractResults.Count == 2) { if (!dateTimeExtractResults[0].IsOverlap(timeExtractResults[0])) { pr1 = this.Config.TimeParser.Parse(timeExtractResults[0], referenceTime); pr2 = this.Config.DateTimeParser.Parse(dateTimeExtractResults[0], referenceTime); endHasDate = true; } else { pr1 = this.Config.DateTimeParser.Parse(dateTimeExtractResults[0], referenceTime); pr2 = this.Config.TimeParser.Parse(timeExtractResults[1], referenceTime); beginHasDate = true; } } else if (dateTimeExtractResults.Count == 1 && timeExtractResults.Count == 1) { if (timeExtractResults[0].Start < dateTimeExtractResults[0].Start) { pr1 = this.Config.TimeParser.Parse(timeExtractResults[0], referenceTime); pr2 = this.Config.DateTimeParser.Parse(dateTimeExtractResults[0], referenceTime); endHasDate = true; } else if (timeExtractResults[0].Start >= dateTimeExtractResults[0].Start + dateTimeExtractResults[0].Length) { pr1 = this.Config.DateTimeParser.Parse(dateTimeExtractResults[0], referenceTime); pr2 = this.Config.TimeParser.Parse(timeExtractResults[0], referenceTime); beginHasDate = true; } else { // If the only TimeExtractResult is part of DateTimeExtractResult, then it should not be handled in this method return(ret); } } else if (timeExtractResults.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 (bothHaveDates) { if (futureBegin > futureEnd) { futureBegin = pastBegin; } if (pastEnd < pastBegin) { pastEnd = futureEnd; } } if (bothHaveDates) { ret.Timex = $"({pr1.TimexStr},{pr2.TimexStr},PT{Convert.ToInt32((futureEnd - futureBegin).TotalHours)}H)"; // Do nothing } else if (beginHasDate) { 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); var dateStr = pr1.TimexStr.Split('T')[0]; var durationStr = DateTimeFormatUtil.LuisTimeSpan(futureEnd - futureBegin); ret.Timex = $"({pr1.TimexStr},{dateStr + pr2.TimexStr},{durationStr}"; } else if (endHasDate) { 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); var dateStr = pr2.TimexStr.Split('T')[0]; var durationStr = DateTimeFormatUtil.LuisTimeSpan(pastEnd - pastBegin); ret.Timex = $"({dateStr + pr1.TimexStr},{pr2.TimexStr},PT{Convert.ToInt32((pastEnd - pastBegin).TotalHours)}H)"; } var ampmStr1 = ((DateTimeResolutionResult)pr1.Value).Comment; var ampmStr2 = ((DateTimeResolutionResult)pr2.Value).Comment; if (!string.IsNullOrEmpty(ampmStr1) && ampmStr1.EndsWith(Constants.Comment_AmPm) && !string.IsNullOrEmpty(ampmStr2) && ampmStr2.EndsWith(Constants.Comment_AmPm)) { ret.Comment = Constants.Comment_AmPm; } if ((this.Config.Options & DateTimeOptions.EnablePreview) != 0) { if (((DateTimeResolutionResult)pr1.Value).TimeZoneResolution != null) { ret.TimeZoneResolution = ((DateTimeResolutionResult)pr1.Value).TimeZoneResolution; } else if (((DateTimeResolutionResult)pr2.Value).TimeZoneResolution != null) { ret.TimeZoneResolution = ((DateTimeResolutionResult)pr2.Value).TimeZoneResolution; } } ret.FutureValue = new Tuple <DateObject, DateObject>(futureBegin, futureEnd); ret.PastValue = new Tuple <DateObject, DateObject>(pastBegin, pastEnd); ret.Success = true; ret.SubDateTimeEntities = new List <object> { pr1, pr2 }; return(ret); }
public DateTimeParseResult Parse(ExtractResult er, DateObject refTime) { var referenceTime = refTime; DateTimeParseResult pr = null; // Push, save the MOD string bool hasBefore = false, hasAfter = false, hasSince = false, hasYearAfter = false; var modStr = string.Empty; var beforeMatch = Config.BeforeRegex.Match(er.Text); var afterMatch = Config.AfterRegex.Match(er.Text); var sinceMatch = Config.SinceRegex.Match(er.Text); if (beforeMatch.Success && beforeMatch.Index == 0) { hasBefore = true; er.Start += beforeMatch.Length; er.Length -= beforeMatch.Length; er.Text = er.Text.Substring(beforeMatch.Length); modStr = beforeMatch.Value; } else if (afterMatch.Success && afterMatch.Index == 0) { hasAfter = true; er.Start += afterMatch.Length; er.Length -= afterMatch.Length; er.Text = er.Text.Substring(afterMatch.Length); modStr = afterMatch.Value; } else if (sinceMatch.Success && sinceMatch.Index == 0) { hasSince = true; er.Start += sinceMatch.Length; er.Length -= sinceMatch.Length; er.Text = er.Text.Substring(sinceMatch.Length); modStr = sinceMatch.Value; } else if (er.Type.Equals(Constants.SYS_DATETIME_DATEPERIOD) && Config.YearRegex.Match(er.Text).Success) { // This has to be put at the end of the if, or cases like "before 2012" and "after 2012" would fall into this // 2012 or after/above var match = Config.YearAfterRegex.Match(er.Text); if (match.Success && er.Text.EndsWith(match.Value)) { hasYearAfter = true; er.Length -= match.Length; er.Text = er.Text.Substring(0, er.Length ?? 0); modStr = match.Value; } } if (er.Type.Equals(Constants.SYS_DATETIME_DATE)) { pr = this.Config.DateParser.Parse(er, referenceTime); if (pr.Value == null) { pr = Config.HolidayParser.Parse(er, referenceTime); } } else if (er.Type.Equals(Constants.SYS_DATETIME_TIME)) { pr = this.Config.TimeParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DATETIME)) { pr = this.Config.DateTimeParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DATEPERIOD)) { pr = this.Config.DatePeriodParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_TIMEPERIOD)) { pr = this.Config.TimePeriodParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DATETIMEPERIOD)) { pr = this.Config.DateTimePeriodParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DURATION)) { pr = this.Config.DurationParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_SET)) { pr = this.Config.GetParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DATETIMEALT)) { pr = this.Config.DateTimeAltParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_TIMEZONE)) { if ((Config.Options & DateTimeOptions.EnablePreview) != 0) { pr = this.Config.TimeZoneParser.Parse(er, referenceTime); } } else { return(null); } // Pop, restore the MOD string if (hasBefore && pr.Value != null) { pr.Length += modStr.Length; pr.Start -= modStr.Length; pr.Text = modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; val.Mod = Constants.BEFORE_MOD; pr.Value = val; } if (hasAfter && pr.Value != null) { pr.Length += modStr.Length; pr.Start -= modStr.Length; pr.Text = modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; val.Mod = Constants.AFTER_MOD; pr.Value = val; } if (hasSince && pr.Value != null) { pr.Length += modStr.Length; pr.Start -= modStr.Length; pr.Text = modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; val.Mod = Constants.SINCE_MOD; pr.Value = val; } if (hasYearAfter && pr.Value != null) { pr.Length += modStr.Length; pr.Text = pr.Text + modStr; var val = (DateTimeResolutionResult)pr.Value; val.Mod = Constants.SINCE_MOD; pr.Value = val; hasSince = true; } if ((Config.Options & DateTimeOptions.SplitDateAndTime) != 0 && ((DateTimeResolutionResult)pr.Value)?.SubDateTimeEntities != null) { pr.Value = DateTimeResolutionForSplit(pr); } else { pr = SetParseResult(pr, hasBefore, hasAfter, hasSince); } return(pr); }
public SortedDictionary <string, object> DateTimeResolution(DateTimeParseResult slot, bool hasBefore, bool hasAfter, bool hasSince) { if (slot == null) { return(null); } var resolutions = new List <Dictionary <string, string> >(); var res = new Dictionary <string, object>(); var type = slot.Type; var typeOutput = DetermineDateTimeType(slot.Type, hasBefore, hasAfter, hasSince); var timex = slot.TimexStr; var val = (DateTimeResolutionResult)slot.Value; if (val == null) { return(null); } var islunar = val.IsLunar; var mod = val.Mod; var comment = val.Comment; // The following should be added to res first, since ResolveAmPm requires these fields. AddResolutionFields(res, DateTimeResolutionKey.Timex, timex); AddResolutionFields(res, Constants.Comment, comment); AddResolutionFields(res, DateTimeResolutionKey.Mod, mod); AddResolutionFields(res, ResolutionKey.Type, typeOutput); AddResolutionFields(res, DateTimeResolutionKey.IsLunar, islunar? islunar.ToString():string.Empty); var pastResolutionStr = ((DateTimeResolutionResult)slot.Value).PastResolution; var futureResolutionStr = ((DateTimeResolutionResult)slot.Value).FutureResolution; if (typeOutput == Constants.SYS_DATETIME_DATETIMEALT && pastResolutionStr.Count > 0) { typeOutput = DetermineResolutionDateTimeType(pastResolutionStr); } var resolutionPast = GenerateResolution(type, pastResolutionStr, mod); var resolutionFuture = GenerateResolution(type, futureResolutionStr, mod); // If past and future are same, keep only one if (resolutionFuture.OrderBy(t => t.Key).Select(t => t.Value) .SequenceEqual(resolutionPast.OrderBy(t => t.Key).Select(t => t.Value))) { if (resolutionPast.Count > 0) { AddResolutionFields(res, Constants.Resolve, resolutionPast); } } else { if (resolutionPast.Count > 0) { AddResolutionFields(res, Constants.ResolveToPast, resolutionPast); } if (resolutionFuture.Count > 0) { AddResolutionFields(res, Constants.ResolveToFuture, resolutionFuture); } } // If 'ampm', double our resolution accordingly if (!string.IsNullOrEmpty(comment) && comment.Equals(Constants.Comment_AmPm)) { if (res.ContainsKey(Constants.Resolve)) { ResolveAmpm(res, Constants.Resolve); } else { ResolveAmpm(res, Constants.ResolveToPast); ResolveAmpm(res, Constants.ResolveToFuture); } } // If WeekOf and in CalendarMode, modify the past part of our resolution if ((Config.Options & DateTimeOptions.CalendarMode) != 0 && !string.IsNullOrEmpty(comment) && comment.Equals(Constants.Comment_WeekOf)) { ResolveWeekOf(res, Constants.ResolveToPast); } if (val.TimeZoneResolution != null) { var timeZoneResolution = new Dictionary <string, string>(); timeZoneResolution.Add(ResolutionKey.Value, val.TimeZoneResolution.Value); timeZoneResolution.Add(Constants.UtcOffsetMinsKey, val.TimeZoneResolution.UtcOffsetMins.ToString()); AddResolutionFields(res, Constants.ResolveTimeZone, timeZoneResolution); } foreach (var p in res) { if (p.Value is Dictionary <string, string> ) { var value = new Dictionary <string, string>(); AddResolutionFields(value, DateTimeResolutionKey.Timex, timex); AddResolutionFields(value, DateTimeResolutionKey.Mod, mod); AddResolutionFields(value, ResolutionKey.Type, typeOutput); AddResolutionFields(value, DateTimeResolutionKey.IsLunar, islunar ? islunar.ToString() : string.Empty); foreach (var q in (Dictionary <string, string>)p.Value) { if (value.ContainsKey(q.Key)) { value[q.Key] = q.Value; } else { value.Add(q.Key, q.Value); } } resolutions.Add(value); } } if (resolutionPast.Count == 0 && resolutionFuture.Count == 0 && val.TimeZoneResolution == null) { var notResolved = new Dictionary <string, string> { { DateTimeResolutionKey.Timex, timex }, { ResolutionKey.Type, typeOutput }, { ResolutionKey.Value, "not resolved" } }; resolutions.Add(notResolved); } return(new SortedDictionary <string, object> { { ResolutionKey.ValueSet, resolutions } }); }
// Cases like "from 3:30 to 5" or "between 3:30am to 6pm", at least one of the time point contains colon private DateTimeResolutionResult ParseSpecificTimeCases(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); int year = referenceTime.Year, month = referenceTime.Month, day = referenceTime.Day; var trimedText = text.Trim().ToLower(); // Handle cases like "from 4:30 to 5" var match = config.SpecificTimeFromToRegex.Match(text); if (!match.Success) { // Handle cases like "between 5:10 and 7" match = config.SpecificTimeBetweenAndRegex.Match(text); } if (match.Success && match.Index == 0 && match.Index + match.Length == trimedText.Length) { // Cases like "half past seven" are not handled here if (match.Groups[Constants.PrefixGroupName].Success) { return(ret); } // Cases like "4" is different with "4:00" as the Timex is different "T04H" vs "T04H00M" // Uses this invalidFlag to differentiate int beginHour; int invalidFlag = -1; int beginMinute = invalidFlag; int beginSecond = invalidFlag; int endHour; int endMinute = invalidFlag; int endSecond = invalidFlag; // Get time1 and time2 var hourGroup = match.Groups[Constants.HourGroupName]; var hourStr = hourGroup.Captures[0].Value; if (config.Numbers.ContainsKey(hourStr)) { beginHour = config.Numbers[hourStr]; } else { beginHour = int.Parse(hourStr); } hourStr = hourGroup.Captures[1].Value; if (config.Numbers.ContainsKey(hourStr)) { endHour = config.Numbers[hourStr]; } else { endHour = int.Parse(hourStr); } var time1StartIndex = match.Groups["time1"].Index; var time1EndIndex = time1StartIndex + match.Groups["time1"].Length; var time2StartIndex = match.Groups["time2"].Index; var time2EndIndex = time2StartIndex + match.Groups["time2"].Length; // Get beginMinute (if exists) and endMinute (if exists) for (int i = 0; i < match.Groups[Constants.MinuteGroupName].Captures.Count; i++) { var minuteCapture = match.Groups[Constants.MinuteGroupName].Captures[i]; if (minuteCapture.Index >= time1StartIndex && minuteCapture.Index + minuteCapture.Length <= time1EndIndex) { beginMinute = int.Parse(minuteCapture.Value); } else if (minuteCapture.Index >= time2StartIndex && minuteCapture.Index + minuteCapture.Length <= time2EndIndex) { endMinute = int.Parse(minuteCapture.Value); } } // Get beginSecond (if exists) and endSecond (if exists) for (int i = 0; i < match.Groups[Constants.SecondGroupName].Captures.Count; i++) { var secondCapture = match.Groups[Constants.SecondGroupName].Captures[i]; if (secondCapture.Index >= time1StartIndex && secondCapture.Index + secondCapture.Length <= time1EndIndex) { beginSecond = int.Parse(secondCapture.Value); } else if (secondCapture.Index >= time2StartIndex && secondCapture.Index + secondCapture.Length <= time2EndIndex) { endSecond = int.Parse(secondCapture.Value); } } // Desc here means descriptions like "am / pm / o'clock" // Get leftDesc (if exists) and rightDesc (if exists) var leftDesc = match.Groups["leftDesc"].Value; var rightDesc = match.Groups["rightDesc"].Value; for (int i = 0; i < match.Groups[Constants.DescGroupName].Captures.Count; i++) { var descCapture = match.Groups[Constants.DescGroupName].Captures[i]; if (descCapture.Index >= time1StartIndex && descCapture.Index + descCapture.Length <= time1EndIndex && string.IsNullOrEmpty(leftDesc)) { leftDesc = descCapture.Value; } else if (descCapture.Index >= time2StartIndex && descCapture.Index + descCapture.Length <= time2EndIndex && string.IsNullOrEmpty(rightDesc)) { rightDesc = descCapture.Value; } } var beginDateTime = DateObject.MinValue.SafeCreateFromValue(year, month, day, beginHour, beginMinute >= 0 ? beginMinute : 0, beginSecond >= 0 ? beginSecond : 0); var endDateTime = DateObject.MinValue.SafeCreateFromValue(year, month, day, endHour, endMinute >= 0 ? endMinute : 0, endSecond >= 0 ? endSecond : 0); var hasLeftAm = !string.IsNullOrEmpty(leftDesc) && leftDesc.ToLower().StartsWith("a"); var hasLeftPm = !string.IsNullOrEmpty(leftDesc) && leftDesc.ToLower().StartsWith("p"); var hasRightAm = !string.IsNullOrEmpty(rightDesc) && rightDesc.ToLower().StartsWith("a"); var hasRightPm = !string.IsNullOrEmpty(rightDesc) && rightDesc.ToLower().StartsWith("p"); var hasLeft = hasLeftAm || hasLeftPm; var hasRight = hasRightAm || hasRightPm; // Both timepoint has description like 'am' or 'pm' if (hasLeft && hasRight) { if (hasLeftAm) { if (beginHour >= Constants.HalfDayHourCount) { beginDateTime = beginDateTime.AddHours(-Constants.HalfDayHourCount); } } else if (hasLeftPm) { if (beginHour < Constants.HalfDayHourCount) { beginDateTime = beginDateTime.AddHours(Constants.HalfDayHourCount); } } if (hasRightAm) { if (endHour >= Constants.HalfDayHourCount) { endDateTime = endDateTime.AddHours(-Constants.HalfDayHourCount); } } else if (hasRightPm) { if (endHour < Constants.HalfDayHourCount) { endDateTime = endDateTime.AddHours(Constants.HalfDayHourCount); } } } // one of the timepoint has description like 'am' or 'pm' else if (hasLeft || hasRight) { if (hasLeftAm) { if (beginHour >= Constants.HalfDayHourCount) { beginDateTime = beginDateTime.AddHours(-Constants.HalfDayHourCount); } if (endHour < Constants.HalfDayHourCount) { if (endDateTime < beginDateTime) { endDateTime = endDateTime.AddHours(Constants.HalfDayHourCount); } } } else if (hasLeftPm) { if (beginHour < Constants.HalfDayHourCount) { beginDateTime = beginDateTime.AddHours(Constants.HalfDayHourCount); } if (endHour < Constants.HalfDayHourCount) { if (endDateTime < beginDateTime) { var span = beginDateTime - endDateTime; if (span.TotalHours >= Constants.HalfDayHourCount) { endDateTime = endDateTime.AddHours(24); } else { endDateTime = endDateTime.AddHours(Constants.HalfDayHourCount); } } } } if (hasRightAm) { if (endHour >= Constants.HalfDayHourCount) { endDateTime = endDateTime.AddHours(-Constants.HalfDayHourCount); } if (beginHour < Constants.HalfDayHourCount) { if (endDateTime < beginDateTime) { beginDateTime = beginDateTime.AddHours(-Constants.HalfDayHourCount); } } } else if (hasRightPm) { if (endHour < Constants.HalfDayHourCount) { endDateTime = endDateTime.AddHours(Constants.HalfDayHourCount); } if (beginHour < Constants.HalfDayHourCount) { if (endDateTime < beginDateTime) { beginDateTime = beginDateTime.AddHours(-Constants.HalfDayHourCount); } else { var span = endDateTime - beginDateTime; if (span.TotalHours > Constants.HalfDayHourCount) { beginDateTime = beginDateTime.AddHours(Constants.HalfDayHourCount); } } } } } // No 'am' or 'pm' indicator else if (!hasLeft && !hasRight && beginHour <= Constants.HalfDayHourCount && endHour <= Constants.HalfDayHourCount) { if (beginHour > endHour) { if (beginHour == Constants.HalfDayHourCount) { beginDateTime = beginDateTime.AddHours(-Constants.HalfDayHourCount); } else { endDateTime = endDateTime.AddHours(Constants.HalfDayHourCount); } } ret.Comment = Constants.Comment_AmPm; } if (endDateTime < beginDateTime) { endDateTime = endDateTime.AddHours(24); } var beginStr = FormatUtil.ShortTime(beginDateTime.Hour, beginMinute, beginSecond); var endStr = FormatUtil.ShortTime(endDateTime.Hour, endMinute, endSecond); ret.Success = true; ret.Timex = $"({beginStr},{endStr},{FormatUtil.LuisTimeSpan(endDateTime - beginDateTime)})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>( beginDateTime, endDateTime); ret.SubDateTimeEntities = new List <object>(); // In SplitDateAndTime mode, time points will be get from these SubDateTimeEntities // Cases like "from 4 to 5pm", "4" should not be treated as SubDateTimeEntity if (hasLeft || beginMinute != invalidFlag || beginSecond != invalidFlag) { var er = new ExtractResult() { Start = time1StartIndex, Length = time1EndIndex - time1StartIndex, Text = text.Substring(time1StartIndex, time1EndIndex - time1StartIndex), Type = $"{Constants.SYS_DATETIME_TIME}" }; DateTimeParseResult pr = this.config.TimeParser.Parse(er, referenceTime); ret.SubDateTimeEntities.Add(pr); } // Cases like "from 4am to 5", "5" should not be treated as SubDateTimeEntity if (hasRight || endMinute != invalidFlag || endSecond != invalidFlag) { var er = new ExtractResult() { Start = time2StartIndex, Length = time2EndIndex - time2StartIndex, Text = text.Substring(time2StartIndex, time2EndIndex - time2StartIndex), Type = $"{Constants.SYS_DATETIME_TIME}" }; DateTimeParseResult pr = this.config.TimeParser.Parse(er, referenceTime); ret.SubDateTimeEntities.Add(pr); } ret.Success = true; } return(ret); }
public DateTimeParseResult Parse(ExtractResult er, DateObject refDate) { var referenceTime = refDate; object value = null; if (er.Type.Equals(ParserName, StringComparison.Ordinal)) { var innerResult = MergeDateAndTimePeriod(er.Text, referenceTime); if (!innerResult.Success) { innerResult = MergeTwoTimePoints(er.Text, referenceTime); } if (!innerResult.Success) { innerResult = ParseSpecificNight(er.Text, referenceTime); } if (!innerResult.Success) { innerResult = ParseNumberWithUnit(er.Text, referenceTime); } if (innerResult.Success) { innerResult.FutureResolution = new Dictionary <string, string> { { TimeTypeConstants.START_DATETIME, DateTimeFormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)innerResult.FutureValue).Item1) }, { TimeTypeConstants.END_DATETIME, DateTimeFormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)innerResult.FutureValue).Item2) }, }; innerResult.PastResolution = new Dictionary <string, string> { { TimeTypeConstants.START_DATETIME, DateTimeFormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)innerResult.PastValue).Item1) }, { TimeTypeConstants.END_DATETIME, DateTimeFormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)innerResult.PastValue).Item2) }, }; value = innerResult; } } var ret = new DateTimeParseResult { Text = er.Text, Start = er.Start, Length = er.Length, Type = er.Type, Data = er.Data, Value = value, TimexStr = value == null ? string.Empty : ((DateTimeResolutionResult)value).Timex, ResolutionStr = string.Empty, }; return(ret); }
private static DateTimeResolutionResult GetAgoLaterResult( DateTimeParseResult durationParseResult, string afterStr, string beforeStr, DateObject referenceTime, IParser numberParser, IDateTimeUtilityConfiguration utilityConfiguration, AgoLaterMode mode, SwiftDayDelegate swiftDay) { var ret = new DateTimeResolutionResult(); var resultDateTime = referenceTime; var timex = durationParseResult.TimexStr; if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.MORE_THAN_MOD) { ret.Mod = Constants.MORE_THAN_MOD; } else if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.LESS_THAN_MOD) { ret.Mod = Constants.LESS_THAN_MOD; } int swift = 0; bool isMatch = false, isLater = false; string dayStr = null; // Item2 is a label identifying the regex defined in Item1 var agoLaterRegexTuples = new List <(Regex, string)> { (utilityConfiguration.AgoRegex, Constants.AGO_LABEL), (utilityConfiguration.LaterRegex, Constants.LATER_LABEL), }; // AgoRegex and LaterRegex cases foreach (var regex in agoLaterRegexTuples) { // Match in afterStr if (MatchingUtil.ContainsAgoLaterIndex(afterStr, regex.Item1, inSuffix: true)) { isMatch = true; isLater = regex.Item2 == Constants.LATER_LABEL; var match = regex.Item1.Match(afterStr); dayStr = match.Groups["day"].Value; } if (utilityConfiguration.CheckBothBeforeAfter) { // Match split between beforeStr and afterStr if (string.IsNullOrEmpty(dayStr) && isMatch) { var match = regex.Item1.Match(beforeStr + " " + afterStr); dayStr = match.Groups["day"].Value; } // Match in beforeStr if (string.IsNullOrEmpty(dayStr) && MatchingUtil.ContainsAgoLaterIndex(beforeStr, regex.Item1, inSuffix: false)) { isMatch = true; isLater = regex.Item2 == Constants.LATER_LABEL; var match = regex.Item1.Match(beforeStr); dayStr = match.Groups["day"].Value; } } if (isMatch) { break; } } // InConnectorRegex cases if (!isMatch) { if (MatchingUtil.ContainsTermIndex(beforeStr, utilityConfiguration.InConnectorRegex)) { // Match in afterStr isMatch = isLater = true; var match = utilityConfiguration.LaterRegex.Match(afterStr); dayStr = match.Groups["day"].Value; } else if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.InConnectorRegex, inSuffix: true)) { // Match in beforeStr isMatch = isLater = true; var match = utilityConfiguration.LaterRegex.Match(beforeStr); dayStr = match.Groups["day"].Value; } } if (isMatch) { // Handle cases like "3 days before yesterday", "3 days after tomorrow" if (!string.IsNullOrEmpty(dayStr)) { swift = swiftDay(dayStr); } if (isLater) { var yearMatch = utilityConfiguration.SinceYearSuffixRegex.Match(afterStr); if (yearMatch.Success) { var yearString = yearMatch.Groups[Constants.YearGroupName].Value; var yearEr = new ExtractResult { Text = yearString }; var year = Convert.ToInt32((double)(numberParser.Parse(yearEr).Value ?? 0)); referenceTime = DateObject.MinValue.SafeCreateFromValue(year, 1, 1); } } var isFuture = isLater; resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), future: isFuture); ((DateTimeResolutionResult)durationParseResult.Value).Mod = isLater ? Constants.AFTER_MOD : Constants.BEFORE_MOD; } if (resultDateTime != referenceTime) { if (mode.Equals(AgoLaterMode.Date)) { ret.Timex = $"{DateTimeFormatUtil.LuisDate(resultDateTime)}"; } else if (mode.Equals(AgoLaterMode.DateTime)) { ret.Timex = $"{DateTimeFormatUtil.LuisDateTime(resultDateTime)}"; } ret.FutureValue = ret.PastValue = resultDateTime; ret.SubDateTimeEntities = new List <object> { durationParseResult }; ret.Success = true; } return(ret); }
public DateTimeParseResult Parse(ExtractResult er, DateObject refDate) { var referenceDate = refDate; object value = null; if (er.Type.Equals(ParserName)) { var innerResult = ParseMonthWithYear(er.Text, referenceDate); if (!innerResult.Success) { innerResult = ParseSimpleCases(er.Text, referenceDate); } if (!innerResult.Success) { innerResult = ParseOneWordPeriod(er.Text, referenceDate); } if (!innerResult.Success) { innerResult = MergeTwoTimePoints(er.Text, referenceDate); } if (!innerResult.Success) { innerResult = ParseYear(er.Text, referenceDate); } if (!innerResult.Success) { innerResult = ParseNumberWithUnit(er.Text, referenceDate); } if (!innerResult.Success) { innerResult = ParseWeekOfMonth(er.Text, referenceDate); } if (!innerResult.Success) { innerResult = ParseWeekOfYear(er.Text, referenceDate); } if (!innerResult.Success) { innerResult = ParseQuarter(er.Text, referenceDate); } if (!innerResult.Success) { innerResult = ParseSeason(er.Text, referenceDate); } if (!innerResult.Success) { innerResult = ParseWhichWeek(er.Text, referenceDate); } if (!innerResult.Success) { innerResult = ParseWeekOfDate(er.Text, referenceDate); } if (!innerResult.Success) { innerResult = ParseMonthOfDate(er.Text, referenceDate); } if (innerResult.Success) { if (innerResult.FutureValue != null && innerResult.PastValue != null) { innerResult.FutureResolution = new Dictionary <string, string> { { TimeTypeConstants.START_DATE, FormatUtil.FormatDate(((Tuple <DateObject, DateObject>)innerResult.FutureValue).Item1) }, { TimeTypeConstants.END_DATE, FormatUtil.FormatDate(((Tuple <DateObject, DateObject>)innerResult.FutureValue).Item2) } }; innerResult.PastResolution = new Dictionary <string, string> { { TimeTypeConstants.START_DATE, FormatUtil.FormatDate(((Tuple <DateObject, DateObject>)innerResult.PastValue).Item1) }, { TimeTypeConstants.END_DATE, FormatUtil.FormatDate(((Tuple <DateObject, DateObject>)innerResult.PastValue).Item2) } }; } else { innerResult.FutureResolution = innerResult.PastResolution = new Dictionary <string, string>(); } value = innerResult; } } var ret = new DateTimeParseResult { Text = er.Text, Start = er.Start, Length = er.Length, Type = er.Type, Data = er.Data, Value = value, TimexStr = value == null ? "" : ((DateTimeResolutionResult)value).Timex, ResolutionStr = "" }; return(ret); }
private DateTimeResolutionResult ParseDateTimeAndTimeAlt(ExtractResult er, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); // Original type of the extracted entity var subType = ((Dictionary <string, object>)er.Data)[Constants.SubType].ToString(); var dateTimeEr = new ExtractResult(); // e.g. {next week Mon} or {Tue}, former--"next week Mon" doesn't contain "context" key var hasContext = false; ExtractResult contextEr = null; if (((Dictionary <string, object>)er.Data).ContainsKey(Constants.Context)) { contextEr = (ExtractResult)((Dictionary <string, object>)er.Data)[Constants.Context]; if (contextEr.Type.Equals(Constants.ContextType_RelativeSuffix, StringComparison.Ordinal)) { dateTimeEr.Text = $"{er.Text} {contextEr.Text}"; } else { dateTimeEr.Text = $"{contextEr.Text} {er.Text}"; } hasContext = true; } else { dateTimeEr.Text = er.Text; } dateTimeEr.Data = er.Data; var dateTimePr = new DateTimeParseResult(); if (subType == Constants.SYS_DATETIME_DATE) { dateTimeEr.Type = Constants.SYS_DATETIME_DATE; dateTimePr = this.config.DateParser.Parse(dateTimeEr, referenceTime); } else if (subType == Constants.SYS_DATETIME_TIME) { if (!hasContext) { dateTimeEr.Type = Constants.SYS_DATETIME_TIME; dateTimePr = this.config.TimeParser.Parse(dateTimeEr, referenceTime); } else if (contextEr.Type == Constants.SYS_DATETIME_DATE || contextEr.Type == Constants.ContextType_RelativePrefix) { // For cases: // Monday 9 am or 11 am // next 9 am or 11 am dateTimeEr.Type = Constants.SYS_DATETIME_DATETIME; dateTimePr = this.config.DateTimeParser.Parse(dateTimeEr, referenceTime); } else if (contextEr.Type == Constants.ContextType_AmPm) { // For cases: in the afternoon 3 o'clock or 5 o'clock dateTimeEr.Type = Constants.SYS_DATETIME_TIME; dateTimePr = this.config.TimeParser.Parse(dateTimeEr, referenceTime); } } else if (subType == Constants.SYS_DATETIME_DATETIME) { // "next week Mon 9 am or Tue 1 pm" dateTimeEr.Type = Constants.SYS_DATETIME_DATETIME; dateTimePr = this.config.DateTimeParser.Parse(dateTimeEr, referenceTime); } else if (subType == Constants.SYS_DATETIME_TIMEPERIOD) { if (!hasContext) { dateTimeEr.Type = Constants.SYS_DATETIME_TIMEPERIOD; dateTimePr = this.config.TimePeriodParser.Parse(dateTimeEr, referenceTime); } else if (contextEr.Type == Constants.SYS_DATETIME_DATE || contextEr.Type == Constants.ContextType_RelativePrefix) { dateTimeEr.Type = Constants.SYS_DATETIME_DATETIMEPERIOD; dateTimePr = this.config.DateTimePeriodParser.Parse(dateTimeEr, referenceTime); } } else if (subType == Constants.SYS_DATETIME_DATETIMEPERIOD) { dateTimeEr.Type = Constants.SYS_DATETIME_DATETIMEPERIOD; dateTimePr = this.config.DateTimePeriodParser.Parse(dateTimeEr, referenceTime); } else if (subType == Constants.SYS_DATETIME_DATEPERIOD) { dateTimeEr.Type = Constants.SYS_DATETIME_DATEPERIOD; dateTimePr = this.config.DatePeriodParser.Parse(dateTimeEr, referenceTime); } if (dateTimePr.Value != null) { ret.FutureValue = ((DateTimeResolutionResult)dateTimePr.Value).FutureValue; ret.PastValue = ((DateTimeResolutionResult)dateTimePr.Value).PastValue; ret.Timex = dateTimePr.TimexStr; // Create resolution ret = GetResolution(er, dateTimePr, ret); ret.Success = true; } return(ret); }
public DateTimeParseResult Parse(ExtractResult er, DateObject refTime) { var referenceTime = refTime; object value = null; if (er.Type.Equals(ParserName)) { var innerResult = MergeDateWithSingleTimePeriod(er.Text, referenceTime); if (!innerResult.Success) { innerResult = MergeTwoTimePoints(er.Text, referenceTime); } if (!innerResult.Success) { innerResult = ParseSpecificTimeOfDay(er.Text, referenceTime); } if (!innerResult.Success) { innerResult = ParseDuration(er.Text, referenceTime); } if (!innerResult.Success) { innerResult = ParseRelativeUnit(er.Text, referenceTime); } if (!innerResult.Success) { innerResult = ParseDateWithPeriodPrefix(er.Text, referenceTime); } if (!innerResult.Success) { // Cases like "today after 2:00pm", "1/1/2015 before 2:00 in the afternoon" innerResult = ParseDateWithTimePeriodSuffix(er.Text, referenceTime); } if (innerResult.Success) { if (!IsBeforeOrAfterMod(innerResult.Mod)) { innerResult.FutureResolution = new Dictionary <string, string> { { TimeTypeConstants.START_DATETIME, DateTimeFormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)innerResult.FutureValue).Item1) }, { TimeTypeConstants.END_DATETIME, DateTimeFormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)innerResult.FutureValue).Item2) } }; innerResult.PastResolution = new Dictionary <string, string> { { TimeTypeConstants.START_DATETIME, DateTimeFormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)innerResult.PastValue).Item1) }, { TimeTypeConstants.END_DATETIME, DateTimeFormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)innerResult.PastValue).Item2) } }; } else { if (innerResult.Mod == Constants.AFTER_MOD) { // Cases like "1/1/2015 after 2:00" there is no EndTime innerResult.FutureResolution = new Dictionary <string, string> { { TimeTypeConstants.START_DATETIME, DateTimeFormatUtil.FormatDateTime((DateObject)(innerResult.FutureValue)) } }; innerResult.PastResolution = new Dictionary <string, string> { { TimeTypeConstants.START_DATETIME, DateTimeFormatUtil.FormatDateTime((DateObject)(innerResult.PastValue)) } }; } else { // Cases like "1/1/2015 before 5:00 in the afternoon" there is no StartTime innerResult.FutureResolution = new Dictionary <string, string> { { TimeTypeConstants.END_DATETIME, DateTimeFormatUtil.FormatDateTime((DateObject)(innerResult.FutureValue)) } }; innerResult.PastResolution = new Dictionary <string, string> { { TimeTypeConstants.END_DATETIME, DateTimeFormatUtil.FormatDateTime((DateObject)(innerResult.PastValue)) } }; } } value = innerResult; } } var ret = new DateTimeParseResult { Text = er.Text, Start = er.Start, Length = er.Length, Type = er.Type, Data = er.Data, Value = value, TimexStr = value == null ? "" : ((DateTimeResolutionResult)value).Timex, ResolutionStr = "" }; return(ret); }
// merge the entity with its related contexts and then parse the combine text private static DateTimeResolutionResult GetResolution(ExtractResult er, DateTimeParseResult pr, DateTimeResolutionResult ret) { var parentText = (string)((Dictionary <string, object>)er.Data)[ExtendedModelResult.ParentTextKey]; var type = pr.Type; var singlePointResolution = string.Empty; var pastStartPointResolution = string.Empty; var pastEndPointResolution = string.Empty; var futureStartPointResolution = string.Empty; var futureEndPointResolution = string.Empty; var singlePointType = string.Empty; var startPointType = string.Empty; var endPointType = string.Empty; if (type == Constants.SYS_DATETIME_DATEPERIOD || type == Constants.SYS_DATETIME_TIMEPERIOD || type == Constants.SYS_DATETIME_DATETIMEPERIOD) { switch (type) { case Constants.SYS_DATETIME_DATEPERIOD: startPointType = TimeTypeConstants.START_DATE; endPointType = TimeTypeConstants.END_DATE; pastStartPointResolution = DateTimeFormatUtil.FormatDate(((Tuple <DateObject, DateObject>)ret.PastValue).Item1); pastEndPointResolution = DateTimeFormatUtil.FormatDate(((Tuple <DateObject, DateObject>)ret.PastValue).Item2); futureStartPointResolution = DateTimeFormatUtil.FormatDate(((Tuple <DateObject, DateObject>)ret.FutureValue).Item1); futureEndPointResolution = DateTimeFormatUtil.FormatDate(((Tuple <DateObject, DateObject>)ret.FutureValue).Item2); break; case Constants.SYS_DATETIME_DATETIMEPERIOD: startPointType = TimeTypeConstants.START_DATETIME; endPointType = TimeTypeConstants.END_DATETIME; if (ret.PastValue is Tuple <DateObject, DateObject> tuple) { pastStartPointResolution = DateTimeFormatUtil.FormatDateTime(tuple.Item1); pastEndPointResolution = DateTimeFormatUtil.FormatDateTime(tuple.Item2); futureStartPointResolution = DateTimeFormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)ret.FutureValue).Item1); futureEndPointResolution = DateTimeFormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)ret.FutureValue).Item2); } else if (ret.PastValue is DateObject datetime) { pastStartPointResolution = DateTimeFormatUtil.FormatDateTime(datetime); futureStartPointResolution = DateTimeFormatUtil.FormatDateTime((DateObject)ret.FutureValue); } break; case Constants.SYS_DATETIME_TIMEPERIOD: startPointType = TimeTypeConstants.START_TIME; endPointType = TimeTypeConstants.END_TIME; pastStartPointResolution = DateTimeFormatUtil.FormatTime(((Tuple <DateObject, DateObject>)ret.PastValue).Item1); pastEndPointResolution = DateTimeFormatUtil.FormatTime(((Tuple <DateObject, DateObject>)ret.PastValue).Item2); futureStartPointResolution = DateTimeFormatUtil.FormatTime(((Tuple <DateObject, DateObject>)ret.FutureValue).Item1); futureEndPointResolution = DateTimeFormatUtil.FormatTime(((Tuple <DateObject, DateObject>)ret.FutureValue).Item2); break; } } else { switch (type) { case Constants.SYS_DATETIME_DATE: singlePointType = TimeTypeConstants.DATE; singlePointResolution = DateTimeFormatUtil.FormatDate((DateObject)ret.FutureValue); break; case Constants.SYS_DATETIME_DATETIME: singlePointType = TimeTypeConstants.DATETIME; singlePointResolution = DateTimeFormatUtil.FormatDateTime((DateObject)ret.FutureValue); break; case Constants.SYS_DATETIME_TIME: singlePointType = TimeTypeConstants.TIME; singlePointResolution = DateTimeFormatUtil.FormatTime((DateObject)ret.FutureValue); break; } } ret.FutureResolution = new Dictionary <string, string>(); ret.PastResolution = new Dictionary <string, string>(); if (!string.IsNullOrEmpty(futureStartPointResolution)) { ret.FutureResolution.Add(startPointType, futureStartPointResolution); } if (!string.IsNullOrEmpty(futureEndPointResolution)) { ret.FutureResolution.Add(endPointType, futureEndPointResolution); } if (!string.IsNullOrEmpty(pastStartPointResolution)) { ret.PastResolution.Add(startPointType, pastStartPointResolution); } if (!string.IsNullOrEmpty(pastEndPointResolution)) { ret.PastResolution.Add(endPointType, pastEndPointResolution); } if (!string.IsNullOrEmpty(singlePointResolution)) { ret.FutureResolution.Add(singlePointType, singlePointResolution); ret.PastResolution.Add(singlePointType, singlePointResolution); } if (!string.IsNullOrEmpty(parentText)) { ret.FutureResolution.Add(ExtendedModelResult.ParentTextKey, parentText); ret.PastResolution.Add(ExtendedModelResult.ParentTextKey, parentText); } if (((DateTimeResolutionResult)pr.Value).Mod != null) { ret.Mod = ((DateTimeResolutionResult)pr.Value).Mod; } if (((DateTimeResolutionResult)pr.Value).TimeZoneResolution != null) { ret.TimeZoneResolution = ((DateTimeResolutionResult)pr.Value).TimeZoneResolution; } return(ret); }
public DateTimeParseResult Parse(ExtractResult er, DateObject refTime) { var referenceTime = refTime; DateTimeParseResult pr = null; var originText = er.Text; if ((this.Config.Options & DateTimeOptions.EnablePreview) != 0) { er.Text = MatchingUtil.PreProcessTextRemoveSuperfluousWords(er.Text, Config.SuperfluousWordMatcher, out var _); er.Length += er.Text.Length - originText.Length; } // Push, save the MOD string bool hasBefore = false, hasAfter = false, hasSince = false, hasAround = false, hasDateAfter = false; // "InclusiveModifier" means MOD should include the start/end time // For example, cases like "on or later than", "earlier than or in" have inclusive modifier var hasInclusiveModifier = false; var modStr = string.Empty; var beforeMatch = Config.BeforeRegex.MatchBegin(er.Text, trim: true); var afterMatch = Config.AfterRegex.MatchBegin(er.Text, trim: true); var sinceMatch = Config.SinceRegex.MatchBegin(er.Text, trim: true); var aroundMatch = Config.AroundRegex.MatchBegin(er.Text, trim: true); if (beforeMatch.Success) { hasBefore = true; er.Start += beforeMatch.Length; er.Length -= beforeMatch.Length; er.Text = er.Text.Substring(beforeMatch.Length); modStr = beforeMatch.Value; if (!string.IsNullOrEmpty(beforeMatch.Groups["include"].Value)) { hasInclusiveModifier = true; } } else if (afterMatch.Success) { hasAfter = true; er.Start += afterMatch.Length; er.Length -= afterMatch.Length; er.Text = er.Text.Substring(afterMatch.Length); modStr = afterMatch.Value; if (!string.IsNullOrEmpty(afterMatch.Groups["include"].Value)) { hasInclusiveModifier = true; } } else if (sinceMatch.Success) { hasSince = true; er.Start += sinceMatch.Length; er.Length -= sinceMatch.Length; er.Text = er.Text.Substring(sinceMatch.Length); modStr = sinceMatch.Value; } else if (aroundMatch.Success) { hasAround = true; er.Start += aroundMatch.Length; er.Length -= aroundMatch.Length; er.Text = er.Text.Substring(aroundMatch.Length); modStr = aroundMatch.Value; } else if ((er.Type.Equals(Constants.SYS_DATETIME_DATEPERIOD, StringComparison.Ordinal) && Config.YearRegex.Match(er.Text).Success) || er.Type.Equals(Constants.SYS_DATETIME_DATE, StringComparison.Ordinal) || er.Type.Equals(Constants.SYS_DATETIME_TIME, StringComparison.Ordinal)) { // This has to be put at the end of the if, or cases like "before 2012" and "after 2012" would fall into this // 2012 or after/above // 3 pm or later var match = Config.SuffixAfter.MatchEnd(er.Text, trim: true); if (match.Success) { hasDateAfter = true; er.Length -= match.Length; er.Text = er.Text.Substring(0, er.Length ?? 0); modStr = match.Value; } } pr = ParseResult(er, referenceTime); if (pr == null) { return(null); } // Pop, restore the MOD string if (hasBefore && pr.Value != null) { pr.Length += modStr.Length; pr.Start -= modStr.Length; pr.Text = modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; val.Mod = CombineMod(val.Mod, !hasInclusiveModifier ? Constants.BEFORE_MOD : Constants.UNTIL_MOD); pr.Value = val; } if (hasAfter && pr.Value != null) { pr.Length += modStr.Length; pr.Start -= modStr.Length; pr.Text = modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; if (!hasInclusiveModifier) { val.Mod = CombineMod(val.Mod, Constants.AFTER_MOD); } else { val.Mod = CombineMod(val.Mod, Constants.SINCE_MOD); } pr.Value = val; } if (hasSince && pr.Value != null) { pr.Length += modStr.Length; pr.Start -= modStr.Length; pr.Text = modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; val.Mod = CombineMod(val.Mod, Constants.SINCE_MOD); pr.Value = val; } if (hasAround && pr.Value != null) { pr.Length += modStr.Length; pr.Start -= modStr.Length; pr.Text = modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; val.Mod = CombineMod(val.Mod, Constants.APPROX_MOD); pr.Value = val; } if (hasDateAfter && pr.Value != null) { pr.Length += modStr.Length; pr.Text = pr.Text + modStr; var val = (DateTimeResolutionResult)pr.Value; val.Mod = CombineMod(val.Mod, Constants.SINCE_MOD); pr.Value = val; hasSince = true; } // For cases like "3 pm or later on monday" if (pr.Value != null && Config.SuffixAfter.Match(pr.Text)?.Index != 0 && pr.Type.Equals(Constants.SYS_DATETIME_DATETIME, StringComparison.Ordinal)) { var val = (DateTimeResolutionResult)pr.Value; val.Mod = CombineMod(val.Mod, Constants.SINCE_MOD); pr.Value = val; hasSince = true; } if ((Config.Options & DateTimeOptions.SplitDateAndTime) != 0 && ((DateTimeResolutionResult)pr?.Value)?.SubDateTimeEntities != null) { pr.Value = DateTimeResolutionForSplit(pr); } else { var hasRangeChangingMod = hasBefore || hasAfter || hasSince; if (pr.Value != null) { ((DateTimeResolutionResult)pr.Value).HasRangeChangingMod = hasRangeChangingMod; } pr = SetParseResult(pr, hasRangeChangingMod); } // In this version, ExperimentalMode only cope with the "IncludePeriodEnd" case if ((this.Config.Options & DateTimeOptions.ExperimentalMode) != 0) { if (pr?.Metadata != null && pr.Metadata.PossiblyIncludePeriodEnd) { pr = SetInclusivePeriodEnd(pr); } } if ((this.Config.Options & DateTimeOptions.EnablePreview) != 0) { if (pr != null) { pr.Length += originText.Length - pr.Text.Length; pr.Text = originText; } } return(pr); }
public DateTimeParseResult Parse(ExtractResult er, DateObject refTime) { var referenceTime = refTime; object value = null; if (er.Type.Equals(ParserName, StringComparison.Ordinal)) { var innerResult = ParseMergedDuration(er.Text, referenceTime); if (!innerResult.Success) { innerResult = ParseNumberWithUnit(er.Text, referenceTime); } if (!innerResult.Success) { innerResult = ParseImplicitDuration(er.Text, referenceTime); } if (innerResult.Success) { innerResult.FutureResolution = new Dictionary <string, string> { { TimeTypeConstants.DURATION, innerResult.FutureValue.ToString() }, }; innerResult.PastResolution = new Dictionary <string, string> { { TimeTypeConstants.DURATION, innerResult.PastValue.ToString() }, }; value = innerResult; } } var res = (DateTimeResolutionResult)value; if (res != null && er.Data != null) { if (er.Data.Equals(Constants.MORE_THAN_MOD)) { res.Mod = Constants.MORE_THAN_MOD; } else if (er.Data.Equals(Constants.LESS_THAN_MOD)) { res.Mod = Constants.LESS_THAN_MOD; } } var ret = new DateTimeParseResult { Text = er.Text, Start = er.Start, Length = er.Length, Type = er.Type, Data = er.Data, Value = value, TimexStr = value == null ? string.Empty : ((DateTimeResolutionResult)value).Timex, ResolutionStr = string.Empty, }; return(ret); }
private DateTimeParseResult ParseResult(ExtractResult extractResult, DateObject referenceTime) { DateTimeParseResult parseResult = null; switch (extractResult.Type) { case Constants.SYS_DATETIME_DATE: if (extractResult.Metadata != null && extractResult.Metadata.IsHoliday) { parseResult = Config.HolidayParser.Parse(extractResult, referenceTime); } else { parseResult = this.Config.DateParser.Parse(extractResult, referenceTime); } break; case Constants.SYS_DATETIME_TIME: parseResult = this.Config.TimeParser.Parse(extractResult, referenceTime); break; case Constants.SYS_DATETIME_DATETIME: parseResult = this.Config.DateTimeParser.Parse(extractResult, referenceTime); break; case Constants.SYS_DATETIME_DATEPERIOD: parseResult = this.Config.DatePeriodParser.Parse(extractResult, referenceTime); break; case Constants.SYS_DATETIME_TIMEPERIOD: parseResult = this.Config.TimePeriodParser.Parse(extractResult, referenceTime); break; case Constants.SYS_DATETIME_DATETIMEPERIOD: parseResult = this.Config.DateTimePeriodParser.Parse(extractResult, referenceTime); break; case Constants.SYS_DATETIME_DURATION: parseResult = this.Config.DurationParser.Parse(extractResult, referenceTime); break; case Constants.SYS_DATETIME_SET: parseResult = this.Config.SetParser.Parse(extractResult, referenceTime); break; case Constants.SYS_DATETIME_DATETIMEALT: parseResult = this.Config.DateTimeAltParser.Parse(extractResult, referenceTime); break; case Constants.SYS_DATETIME_TIMEZONE: if ((Config.Options & DateTimeOptions.EnablePreview) != 0) { parseResult = this.Config.TimeZoneParser.Parse(extractResult, referenceTime); } break; default: return(null); } return(parseResult); }
private static string GetParentText(DateTimeParseResult parsedDateTime) { return(((Dictionary <string, object>)parsedDateTime.Data)[ExtendedModelResult.ParentTextKey].ToString()); }
public SortedDictionary <string, object> DateTimeResolution(DateTimeParseResult slot, bool hasBefore, bool hasAfter, bool hasSince) { var resolutions = new List <Dictionary <string, string> >(); var res = new Dictionary <string, object>(); var type = slot.Type; var typeOutput = DetermineDateTimeType(slot.Type, hasBefore, hasAfter, hasSince); var timex = slot.TimexStr; var val = (DateTimeResolutionResult)slot.Value; if (val == null) { return(null); } var isLunar = val.IsLunar; var mod = val.Mod; var comment = val.Comment; if (!string.IsNullOrEmpty(timex)) { res.Add(DateTimeResolutionKey.Timex, timex); } if (!string.IsNullOrEmpty(comment)) { res.Add(Constants.Comment, comment); } if (!string.IsNullOrEmpty(mod)) { res.Add(DateTimeResolutionKey.Mod, mod); } if (!string.IsNullOrEmpty(type)) { res.Add(ResolutionKey.Type, typeOutput); } var pastResolutionStr = ((DateTimeResolutionResult)slot.Value).PastResolution; var futureResolutionStr = ((DateTimeResolutionResult)slot.Value).FutureResolution; var resolutionPast = GenerateResolution(type, pastResolutionStr, mod); var resolutionFuture = GenerateResolution(type, futureResolutionStr, mod); // if past and future are same, keep only one if (resolutionFuture.OrderBy(t => t.Key).Select(t => t.Value).SequenceEqual(resolutionPast.OrderBy(t => t.Key).Select(t => t.Value))) { if (resolutionPast.Count > 0) { res.Add(Constants.Resolve, resolutionPast); } } else { if (resolutionPast.Count > 0) { res.Add(Constants.ResolveToPast, resolutionPast); } if (resolutionFuture.Count > 0) { res.Add(Constants.ResolveToFuture, resolutionFuture); } } // if ampm, double our resolution accordingly if (!string.IsNullOrEmpty(comment) && comment.Equals(Constants.Comment_AmPm)) { if (res.ContainsKey(Constants.Resolve)) { ResolveAmpm(res, Constants.Resolve); } else { ResolveAmpm(res, Constants.ResolveToPast); ResolveAmpm(res, Constants.ResolveToFuture); } } if (isLunar) { res.Add(DateTimeResolutionKey.IsLunar, isLunar); } foreach (var p in res) { if (p.Value is Dictionary <string, string> dictionary) { var value = new Dictionary <string, string>(); if (!string.IsNullOrEmpty(timex)) { value.Add(DateTimeResolutionKey.Timex, timex); } if (!string.IsNullOrEmpty(mod)) { value.Add(DateTimeResolutionKey.Mod, mod); } if (!string.IsNullOrEmpty(type)) { value.Add(ResolutionKey.Type, typeOutput); } foreach (var q in dictionary) { if (value.ContainsKey(q.Key)) { value[q.Key] = q.Value; } else { value.Add(q.Key, q.Value); } } resolutions.Add(value); } } if (resolutionPast.Count == 0 && resolutionFuture.Count == 0) { var notResolved = new Dictionary <string, string> { { DateTimeResolutionKey.Timex, timex }, { ResolutionKey.Type, typeOutput }, { ResolutionKey.Value, "not resolved" }, }; resolutions.Add(notResolved); } return(new SortedDictionary <string, object> { { ResolutionKey.ValueSet, resolutions } }); }
public DateTimeParseResult Parse(ExtractResult er, DateObject refDate) { object value = null; if (er.Type.Equals(ParserName)) { var innerResult = ParseEachUnit(er.Text); if (!innerResult.Success) { innerResult = ParseEachDuration(er.Text, refDate); } if (!innerResult.Success) { innerResult = ParserTimeEveryday(er.Text, refDate); } // NOTE: Please do not change the order of following function // datetimeperiod>dateperiod>timeperiod>datetime>date>time if (!innerResult.Success) { innerResult = ParseEach(config.DateTimePeriodExtractor, config.DateTimePeriodParser, er.Text, refDate); } if (!innerResult.Success) { innerResult = ParseEach(config.DatePeriodExtractor, config.DatePeriodParser, er.Text, refDate); } if (!innerResult.Success) { innerResult = ParseEach(config.TimePeriodExtractor, config.TimePeriodParser, er.Text, refDate); } if (!innerResult.Success) { innerResult = ParseEach(config.DateTimeExtractor, config.DateTimeParser, er.Text, refDate); } if (!innerResult.Success) { innerResult = ParseEach(config.DateExtractor, config.DateParser, er.Text, refDate); } if (!innerResult.Success) { innerResult = ParseEach(config.TimeExtractor, config.TimeParser, er.Text, refDate); } if (innerResult.Success) { innerResult.FutureResolution = new Dictionary <string, string> { { TimeTypeConstants.SET, (string)innerResult.FutureValue }, }; innerResult.PastResolution = new Dictionary <string, string> { { TimeTypeConstants.SET, (string)innerResult.PastValue }, }; value = innerResult; } } var ret = new DateTimeParseResult { Text = er.Text, Start = er.Start, Length = er.Length, Type = er.Type, Data = er.Data, Value = value, TimexStr = value == null ? string.Empty : ((DateTimeResolutionResult)value).Timex, ResolutionStr = string.Empty, }; return(ret); }
public DateTimeParseResult Parse(ExtractResult er, DateObject reference) { var referenceDate = reference; object value = null; if (er.Type.Equals(ParserName)) { var innerResult = ParseBasicRegexMatch(er.Text, referenceDate); if (!innerResult.Success) { innerResult = ParseImplicitDate(er.Text, referenceDate); } if (!innerResult.Success) { innerResult = ParseWeekdayOfMonth(er.Text, referenceDate); } if (!innerResult.Success) { innerResult = ParseDurationWithAgoAndLater(er.Text, referenceDate); } // NumberWithMonth must be the second last one, because it only need to find a number and a month to get a "success" if (!innerResult.Success) { innerResult = ParseNumberWithMonth(er.Text, referenceDate); } // SingleNumber last one if (!innerResult.Success) { innerResult = ParseSingleNumber(er.Text, referenceDate); } if (innerResult.Success) { innerResult.FutureResolution = new Dictionary <string, string> { { TimeTypeConstants.DATE, DateTimeFormatUtil.FormatDate((DateObject)innerResult.FutureValue) } }; innerResult.PastResolution = new Dictionary <string, string> { { TimeTypeConstants.DATE, DateTimeFormatUtil.FormatDate((DateObject)innerResult.PastValue) } }; value = innerResult; } } var ret = new DateTimeParseResult { Text = er.Text, Start = er.Start, Length = er.Length, Type = er.Type, Data = er.Data, Value = value, TimexStr = value == null ? "" : ((DateTimeResolutionResult)value).Timex, ResolutionStr = "" }; 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); 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 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 = string.Empty; var rightTimex = string.Empty; // "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); }
private DateTimeResolutionResult MergeTwoTimePoints(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); DateTimeParseResult pr1 = null, pr2 = null; var validTimeNumber = false; var ers = this.config.TimeExtractor.Extract(text, referenceTime); if (ers.Count != 2) { if (ers.Count == 1) { var numErs = this.config.IntegerExtractor.Extract(text); foreach (var num in numErs) { int midStrBegin = 0, midStrEnd = 0; // ending number if (num.Start > ers[0].Start + ers[0].Length) { midStrBegin = ers[0].Start + ers[0].Length ?? 0; midStrEnd = num.Start - midStrBegin ?? 0; } else if (num.Start + num.Length < ers[0].Start) { midStrBegin = num.Start + num.Length ?? 0; midStrEnd = ers[0].Start - midStrBegin ?? 0; } // check if the middle string between the time point and the valid number is a connect string. var middleStr = text.Substring(midStrBegin, midStrEnd); var tillMatch = this.config.TillRegex.Match(middleStr); if (tillMatch.Success) { num.Data = null; num.Type = Constants.SYS_DATETIME_TIME; ers.Add(num); validTimeNumber = true; break; } } ers.Sort((x, y) => (x.Start - y.Start ?? 0)); } if (!validTimeNumber) { return(ret); } } pr1 = this.config.TimeParser.Parse(ers[0], referenceTime); pr2 = this.config.TimeParser.Parse(ers[1], referenceTime); if (pr1.Value == null || pr2.Value == null) { return(ret); } var ampmStr1 = ((DateTimeResolutionResult)pr1.Value).Comment; var ampmStr2 = ((DateTimeResolutionResult)pr2.Value).Comment; var beginTime = (DateObject)((DateTimeResolutionResult)pr1.Value).FutureValue; var endTime = (DateObject)((DateTimeResolutionResult)pr2.Value).FutureValue; if (!string.IsNullOrEmpty(ampmStr2) && ampmStr2.EndsWith(Constants.Comment_AmPm) && endTime <= beginTime && endTime.AddHours(Constants.HalfDayHourCount) > beginTime) { endTime = endTime.AddHours(Constants.HalfDayHourCount); ((DateTimeResolutionResult)pr2.Value).FutureValue = endTime; pr2.TimexStr = $"T{endTime.Hour}"; if (endTime.Minute > 0) { pr2.TimexStr = $"{pr2.TimexStr}:{endTime.Minute}"; } } if (!string.IsNullOrEmpty(ampmStr1) && ampmStr1.EndsWith(Constants.Comment_AmPm) && endTime > beginTime.AddHours(Constants.HalfDayHourCount)) { beginTime = beginTime.AddHours(Constants.HalfDayHourCount); ((DateTimeResolutionResult)pr1.Value).FutureValue = beginTime; pr1.TimexStr = $"T{beginTime.Hour}"; if (beginTime.Minute > 0) { pr1.TimexStr = $"{pr1.TimexStr}:{beginTime.Minute}"; } } if (endTime < beginTime) { endTime = endTime.AddDays(1); } var minutes = (endTime - beginTime).Minutes; var hours = (endTime - beginTime).Hours; ret.Timex = $"({pr1.TimexStr},{pr2.TimexStr}," + $"PT{(hours > 0 ? hours + "H" : "")}{(minutes > 0 ? minutes + "M" : "")})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginTime, endTime); ret.Success = true; if (!string.IsNullOrEmpty(ampmStr1) && ampmStr1.EndsWith(Constants.Comment_AmPm) && !string.IsNullOrEmpty(ampmStr2) && ampmStr2.EndsWith(Constants.Comment_AmPm)) { ret.Comment = Constants.Comment_AmPm; } if (((DateTimeResolutionResult)pr1.Value).TimeZoneResolution != null) { ret.TimeZoneResolution = ((DateTimeResolutionResult)pr1.Value).TimeZoneResolution; } else if (((DateTimeResolutionResult)pr2.Value).TimeZoneResolution != null) { ret.TimeZoneResolution = ((DateTimeResolutionResult)pr2.Value).TimeZoneResolution; } ret.SubDateTimeEntities = new List <object> { pr1, pr2 }; return(ret); }
private static DateTimeResolutionResult GetAgoLaterResult( DateTimeParseResult durationParseResult, string afterStr, string beforeStr, DateObject referenceTime, IParser numberParser, IDateTimeUtilityConfiguration utilityConfiguration, AgoLaterMode mode, SwiftDayDelegate swiftDay) { var ret = new DateTimeResolutionResult(); var resultDateTime = referenceTime; var timex = durationParseResult.TimexStr; if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.MORE_THAN_MOD) { ret.Mod = Constants.MORE_THAN_MOD; } else if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.LESS_THAN_MOD) { ret.Mod = Constants.LESS_THAN_MOD; } if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.AgoRegex)) { var match = utilityConfiguration.AgoRegex.Match(afterStr); var swift = 0; // Handle cases like "3 days before yesterday" if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } else if (utilityConfiguration.CheckBothBeforeAfter && match.Success && !MatchingUtil.ContainsAgoLaterIndexInBeforeString(beforeStr, utilityConfiguration.AgoRegex)) { match = utilityConfiguration.AgoRegex.Match(beforeStr + " " + afterStr); if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } } resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), false); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.BEFORE_MOD; } else if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.ContainsAgoLaterIndexInBeforeString(beforeStr, utilityConfiguration.AgoRegex)) { var match = utilityConfiguration.AgoRegex.Match(beforeStr); var swift = 0; // Handle cases like "3 days before yesterday" if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), false); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.BEFORE_MOD; } else if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.LaterRegex) || MatchingUtil.ContainsTermIndex(beforeStr, utilityConfiguration.InConnectorRegex) || (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.ContainsAgoLaterIndexInBeforeString(beforeStr, utilityConfiguration.LaterRegex))) { var match = utilityConfiguration.LaterRegex.Match(afterStr); var swift = 0; if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.ContainsAgoLaterIndexInBeforeString(beforeStr, utilityConfiguration.LaterRegex) && string.IsNullOrEmpty(match.Groups["day"].Value)) { match = utilityConfiguration.LaterRegex.Match(beforeStr); } // Handle cases like "3 days after tomorrow" if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } var yearMatch = utilityConfiguration.SinceYearSuffixRegex.Match(afterStr); if (yearMatch.Success) { var yearString = yearMatch.Groups[Constants.YearGroupName].Value; var yearEr = new ExtractResult { Text = yearString }; var year = Convert.ToInt32((double)(numberParser.Parse(yearEr).Value ?? 0)); referenceTime = DateObject.MinValue.SafeCreateFromValue(year, 1, 1); } resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), true); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.AFTER_MOD; } else if (utilityConfiguration.CheckBothBeforeAfter && (MatchingUtil.ContainsAgoLaterIndexInBeforeString(beforeStr, utilityConfiguration.LaterRegex) || MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.InConnectorRegex) || MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.LaterRegex))) { // Check also beforeStr var match = utilityConfiguration.LaterRegex.Match(beforeStr); var swift = 0; if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.LaterRegex) && string.IsNullOrEmpty(match.Groups["day"].Value)) { match = utilityConfiguration.LaterRegex.Match(beforeStr); } // Handle cases like "3 days after tomorrow" if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } var yearMatch = utilityConfiguration.SinceYearSuffixRegex.Match(beforeStr); if (yearMatch.Success) { var yearString = yearMatch.Groups[Constants.YearGroupName].Value; var yearEr = new ExtractResult { Text = yearString }; var year = Convert.ToInt32((double)(numberParser.Parse(yearEr).Value ?? 0)); referenceTime = DateObject.MinValue.SafeCreateFromValue(year, 1, 1); } resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), true); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.AFTER_MOD; } if (resultDateTime != referenceTime) { if (mode.Equals(AgoLaterMode.Date)) { ret.Timex = $"{DateTimeFormatUtil.LuisDate(resultDateTime)}"; } else if (mode.Equals(AgoLaterMode.DateTime)) { ret.Timex = $"{DateTimeFormatUtil.LuisDateTime(resultDateTime)}"; } ret.FutureValue = ret.PastValue = resultDateTime; ret.SubDateTimeEntities = new List <object> { durationParseResult }; ret.Success = true; } return(ret); }