From 18fe661862be7e2b235732616a09a193f225a6f1 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Nov 2024 14:24:53 +0800 Subject: [PATCH] [EN DateTimeV2] Add support for time range with duration (#3174) * Datetime for longer span - local draft commit * DateTimeForLongerSpan - Implement for from * DateTimeForLongerSpan - from datetime for duration local commit * DateTimeForLongerSpan - Parsing time period with duration initial commit * DateTimeForLongerSpan - Parsing time period with duration update test cases * DateTimeForLongerSpan - Add support for time range with duration - Update test case to trigger rebuild * DateTimeForLongerSpan - Add support for time range with duration - Update test case to trigger rebuild --------- Co-authored-by: Michael Wang (Centific Technologies Inc) --- .../English/DateTimeDefinitions.cs | 3 + ...EnglishTimePeriodExtractorConfiguration.cs | 3 + .../EnglishTimePeriodParserConfiguration.cs | 9 + .../Extractors/BaseTimePeriodExtractor.cs | 19 +- .../Parsers/BaseTimePeriodParser.cs | 139 +++++++++++- Patterns/English/English-DateTime.yaml | 9 + Specs/DateTime/English/DateTimeModel.json | 212 ++++++++++++++++++ .../English/DateTimePeriodExtractor.json | 26 ++- .../English/DateTimePeriodParser.json | 52 +++++ .../DateTime/English/TimePeriodExtractor.json | 72 ++++++ Specs/DateTime/English/TimePeriodParser.json | 156 +++++++++++++ 11 files changed, 697 insertions(+), 3 deletions(-) diff --git a/.NET/Microsoft.Recognizers.Definitions.Common/English/DateTimeDefinitions.cs b/.NET/Microsoft.Recognizers.Definitions.Common/English/DateTimeDefinitions.cs index 1d9e716ec5..8e5662c43d 100644 --- a/.NET/Microsoft.Recognizers.Definitions.Common/English/DateTimeDefinitions.cs +++ b/.NET/Microsoft.Recognizers.Definitions.Common/English/DateTimeDefinitions.cs @@ -316,6 +316,9 @@ public static class DateTimeDefinitions public static readonly string TasksModeSupressionRegexes = $@"({AmPmDescRegex}|{TasksModeSpecialDescRegex}|{TasksModeHolidayListSupression}|{DecadeRegex}|{DecadeWithCenturyRegex}|{QuarterRegex}|{QuarterRegexYearFront}|{AllHalfYearRegex}|{SeasonRegex})"; public const string TasksModeNextPrefix = @"(?next\s+)"; public static readonly string TasksModeDurationToDatePatterns = $@"\b({TasksModeNextPrefix}((?week)|(?month)|(?year)))\b"; + public static readonly string TimePeriodFromForRegex = $@"(from\s+)(?(({TimeRegex2}|{FirstTimeRegexInTimeRange})|({HourRegex}|{PeriodHourNumRegex})(\s*(?{DescRegex}))?))\s*for\s+(.*?)\s+({DurationUnitRegex})(\s+(.*?)\s+({DurationUnitRegex}))?"; + public static readonly string TimePeriodForFromRegex = $@"for\s+(.*?)\s+({DurationUnitRegex})(\s+(.*?)\s+({DurationUnitRegex}))?\s+(from\s+)(?(({TimeRegex2}|{FirstTimeRegexInTimeRange})|({HourRegex}|{PeriodHourNumRegex})(\s*(?{DescRegex}))?))"; + public static readonly string TimePeriodWithDurationRegex = $@"({TimePeriodFromForRegex}|{TimePeriodForFromRegex})"; public static readonly Dictionary UnitMap = new Dictionary { { @"decades", @"10Y" }, diff --git a/.NET/Microsoft.Recognizers.Text.DateTime/English/Extractors/EnglishTimePeriodExtractorConfiguration.cs b/.NET/Microsoft.Recognizers.Text.DateTime/English/Extractors/EnglishTimePeriodExtractorConfiguration.cs index b344f3ad44..ad89094978 100644 --- a/.NET/Microsoft.Recognizers.Text.DateTime/English/Extractors/EnglishTimePeriodExtractorConfiguration.cs +++ b/.NET/Microsoft.Recognizers.Text.DateTime/English/Extractors/EnglishTimePeriodExtractorConfiguration.cs @@ -64,6 +64,9 @@ public class EnglishTimePeriodExtractorConfiguration : BaseDateTimeOptionsConfig public static readonly Regex GeneralEndingRegex = new Regex(DateTimeDefinitions.GeneralEndingRegex, RegexFlags, RegexTimeOut); + public static readonly Regex TimePeriodWithDurationRegex = + new Regex(DateTimeDefinitions.TimePeriodWithDurationRegex, RegexFlags, RegexTimeOut); + private const RegexOptions RegexFlags = RegexOptions.Singleline | RegexOptions.ExplicitCapture; public EnglishTimePeriodExtractorConfiguration(IDateTimeOptionsConfiguration config) diff --git a/.NET/Microsoft.Recognizers.Text.DateTime/English/Parsers/EnglishTimePeriodParserConfiguration.cs b/.NET/Microsoft.Recognizers.Text.DateTime/English/Parsers/EnglishTimePeriodParserConfiguration.cs index 4f1b3393a4..6900777393 100644 --- a/.NET/Microsoft.Recognizers.Text.DateTime/English/Parsers/EnglishTimePeriodParserConfiguration.cs +++ b/.NET/Microsoft.Recognizers.Text.DateTime/English/Parsers/EnglishTimePeriodParserConfiguration.cs @@ -27,6 +27,9 @@ public EnglishTimePeriodParserConfiguration(ICommonDateTimeParserConfiguration c TimeOfDayRegex = EnglishTimePeriodExtractorConfiguration.TimeOfDayRegex; GeneralEndingRegex = EnglishTimePeriodExtractorConfiguration.GeneralEndingRegex; TillRegex = EnglishTimePeriodExtractorConfiguration.TillRegex; + TimePeriodWithDurationRegex = EnglishTimePeriodExtractorConfiguration.TimePeriodWithDurationRegex; + DurationParser = config.DurationParser; + DurationExtractor = config.DurationExtractor; Numbers = config.Numbers; UtilityConfiguration = config.UtilityConfiguration; @@ -40,6 +43,10 @@ public EnglishTimePeriodParserConfiguration(ICommonDateTimeParserConfiguration c public IDateTimeParser TimeZoneParser { get; } + public IDateTimeParser DurationParser { get; } + + public IDateTimeExtractor DurationExtractor { get; } + public Regex SpecificTimeFromToRegex { get; } public Regex SpecificTimeBetweenAndRegex { get; } @@ -54,6 +61,8 @@ public EnglishTimePeriodParserConfiguration(ICommonDateTimeParserConfiguration c public Regex TillRegex { get; } + public Regex TimePeriodWithDurationRegex { get; } + public IImmutableDictionary Numbers { get; } public IDateTimeUtilityConfiguration UtilityConfiguration { get; } diff --git a/.NET/Microsoft.Recognizers.Text.DateTime/Extractors/BaseTimePeriodExtractor.cs b/.NET/Microsoft.Recognizers.Text.DateTime/Extractors/BaseTimePeriodExtractor.cs index 451da7d669..5ef4c4126b 100644 --- a/.NET/Microsoft.Recognizers.Text.DateTime/Extractors/BaseTimePeriodExtractor.cs +++ b/.NET/Microsoft.Recognizers.Text.DateTime/Extractors/BaseTimePeriodExtractor.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; - +using Microsoft.Recognizers.Text.DateTime.English; using Microsoft.Recognizers.Text.InternalCache; using Microsoft.Recognizers.Text.Utilities; using DateObject = System.DateTime; @@ -55,6 +55,7 @@ private List ExtractImpl(string text, DateObject reference) { var tokens = new List(); tokens.AddRange(MatchSimpleCases(text)); + tokens.AddRange(MatchTimePeriodWithDurationCases(text)); tokens.AddRange(MergeTwoTimePoints(text, reference)); tokens.AddRange(MatchTimeOfDay(text)); @@ -153,6 +154,22 @@ private List MatchSimpleCases(string text) return ret; } + // Cases like "from 6am for 3 hours" and "for 3 hours from 6 am" are extracted as timerange here. + private List MatchTimePeriodWithDurationCases(string text) + { + var ret = new List(); + if (this.config as EnglishTimePeriodExtractorConfiguration != null) + { + Match match = EnglishTimePeriodExtractorConfiguration.TimePeriodWithDurationRegex.Match(text); + if (match.Success) + { + ret.Add(new Token(match.Index, match.Index + match.Length)); + } + } + + return ret; + } + private bool StartsWithTimeZone(string afterText) { var startsWithTimeZone = false; diff --git a/.NET/Microsoft.Recognizers.Text.DateTime/Parsers/BaseTimePeriodParser.cs b/.NET/Microsoft.Recognizers.Text.DateTime/Parsers/BaseTimePeriodParser.cs index 694f1ed155..35dff5df1f 100644 --- a/.NET/Microsoft.Recognizers.Text.DateTime/Parsers/BaseTimePeriodParser.cs +++ b/.NET/Microsoft.Recognizers.Text.DateTime/Parsers/BaseTimePeriodParser.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using System.Globalization; - +using Microsoft.Recognizers.Text.DateTime.English; using Microsoft.Recognizers.Text.Utilities; using DateObject = System.DateTime; @@ -120,6 +120,11 @@ private DateTimeResolutionResult InternalParse(string entityText, DateObject ref innerResult = ParseTimeOfDay(entityText, referenceTime); } + if (!innerResult.Success) + { + innerResult = ParseTimePeroidWithDuration(entityText, referenceTime); + } + return innerResult; } @@ -669,6 +674,138 @@ private DateTimeResolutionResult ParseSpecificTimeCases(string text, DateObject return ret; } + // Cases like "from 6am for 3 hours" and "for 3 hours from 6am" are parsing here. + private DateTimeResolutionResult ParseTimePeroidWithDuration(string text, DateObject referenceTime) + { + var parserConfig = this.config as EnglishTimePeriodParserConfiguration; + var ret = new DateTimeResolutionResult(); + if (parserConfig != null) + { + var match = parserConfig.TimePeriodWithDurationRegex.MatchExact(text, trim: true); + + if (match.Success) + { + var erDuration = parserConfig.DurationExtractor.Extract(text); + + if (erDuration is null || erDuration.Count == 0) + { + return ret; + } + + var prDuration = parserConfig.DurationParser.Parse(erDuration[0]); + int year = referenceTime.Year, month = referenceTime.Month, day = referenceTime.Day; + + // 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" + int beginHour; + int beginMinute = Constants.InvalidMinute; + int beginSecond = Constants.InvalidSecond; + + // Get time1 + 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, CultureInfo.InvariantCulture); + } + + var time1StartIndex = match.Groups["time1"].Index; + var time1EndIndex = time1StartIndex + match.Groups["time1"].Length; + + // Get beginMinute (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, CultureInfo.InvariantCulture); + } + } + + // Get beginSecond (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, CultureInfo.InvariantCulture); + } + } + + // Desc here means descriptions like "am / pm / o'clock" + // Get leftDesc (if exists) + var leftDesc = match.Groups["leftDesc"].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; + } + } + + var beginDateTime = DateObject.MinValue.SafeCreateFromValue(year, month, day, beginHour, beginMinute >= 0 ? beginMinute : 0, beginSecond >= 0 ? beginSecond : 0); + + var hasLeftAm = !string.IsNullOrEmpty(leftDesc) && leftDesc.StartsWith("a", StringComparison.Ordinal); + var hasLeftPm = !string.IsNullOrEmpty(leftDesc) && leftDesc.StartsWith("p", StringComparison.Ordinal); + + // one of the time point has description like 'am' or 'pm' + if (hasLeftAm) + { + if (beginHour >= Constants.HalfDayHourCount) + { + beginDateTime = beginDateTime.AddHours(-Constants.HalfDayHourCount); + } + } + else if (hasLeftPm) + { + if (beginHour < Constants.HalfDayHourCount) + { + beginDateTime = beginDateTime.AddHours(Constants.HalfDayHourCount); + } + } + + var endDateTime = beginDateTime.AddSeconds(Convert.ToInt32((prDuration.Value as DateTimeResolutionResult).FutureValue, CultureInfo.InvariantCulture)); + + var beginStr = DateTimeFormatUtil.ShortTime(beginDateTime.Hour, beginMinute, beginSecond); + var endStr = DateTimeFormatUtil.ShortTime(endDateTime.Hour, endDateTime.Minute, endDateTime.Second); + + ret.Success = true; + + ret.Timex = $"({beginStr},{endStr},{DateTimeFormatUtil.LuisTimeSpan(endDateTime - beginDateTime)})"; + + ret.FutureValue = ret.PastValue = new Tuple( + beginDateTime, + endDateTime); + + ret.SubDateTimeEntities = new List(); + var er = new ExtractResult() + { + Start = time1StartIndex, + Length = time1EndIndex - time1StartIndex, + Text = text.Substring(time1StartIndex, time1EndIndex - time1StartIndex), + Type = $"{Constants.SYS_DATETIME_TIME}", + }; + + var pr = this.config.TimeParser.Parse(er, referenceTime); + ret.SubDateTimeEntities.Add(pr); + } + } + + return ret; + } + private DateTimeResolutionResult MergeTwoTimePoints(string text, DateObject referenceTime) { var ret = new DateTimeResolutionResult(); diff --git a/Patterns/English/English-DateTime.yaml b/Patterns/English/English-DateTime.yaml index 31d3532599..60f80caecc 100644 --- a/Patterns/English/English-DateTime.yaml +++ b/Patterns/English/English-DateTime.yaml @@ -768,6 +768,15 @@ TasksModeNextPrefix: !simpleRegex TasksModeDurationToDatePatterns: !nestedRegex def: \b({TasksModeNextPrefix}((?week)|(?month)|(?year)))\b references: [TasksModeNextPrefix] +TimePeriodFromForRegex: !nestedRegex + def: (from\s+)(?(({TimeRegex2}|{FirstTimeRegexInTimeRange})|({HourRegex}|{PeriodHourNumRegex})(\s*(?{DescRegex}))?))\s*for\s+(.*?)\s+({DurationUnitRegex})(\s+(.*?)\s+({DurationUnitRegex}))? + references: [ TimeRegex2, FirstTimeRegexInTimeRange, TimeRegexWithDotConnector, TillRegex, HourRegex, PeriodHourNumRegex, DescRegex, PmRegex, AmRegex, RangePrefixRegex, DurationUnitRegex ] +TimePeriodForFromRegex: !nestedRegex + def: for\s+(.*?)\s+({DurationUnitRegex})(\s+(.*?)\s+({DurationUnitRegex}))?\s+(from\s+)(?(({TimeRegex2}|{FirstTimeRegexInTimeRange})|({HourRegex}|{PeriodHourNumRegex})(\s*(?{DescRegex}))?)) + references: [ TimeRegex2, FirstTimeRegexInTimeRange, TimeRegexWithDotConnector, TillRegex, HourRegex, PeriodHourNumRegex, DescRegex, PmRegex, AmRegex, RangePrefixRegex, DurationUnitRegex ] +TimePeriodWithDurationRegex: !nestedRegex + def: ({TimePeriodFromForRegex}|{TimePeriodForFromRegex}) + references: [ TimePeriodFromForRegex, TimePeriodForFromRegex ] UnitMap: !dictionary types: [ string, string ] entries: diff --git a/Specs/DateTime/English/DateTimeModel.json b/Specs/DateTime/English/DateTimeModel.json index ff100ed2e3..aec4bdbf18 100644 --- a/Specs/DateTime/English/DateTimeModel.json +++ b/Specs/DateTime/English/DateTimeModel.json @@ -1740,6 +1740,156 @@ } ] }, + { + "Input": "The meeting is start from 9 for 2.5 hrs", + "Context": { + "ReferenceDateTime": "2016-11-07T16:12:00" + }, + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "from 9 for 2.5 hrs", + "Start": 21, + "End": 38, + "TypeName": "datetimeV2.timerange", + "Resolution": { + "values": [ + { + "timex": "(T09,T11:30:00,PT2H30M)", + "type": "timerange", + "start": "09:00:00", + "end": "11:30:00" + } + ] + } + } + ] + }, + { + "Input": "The meeting is start from 10 am for 3 hours 30 minutes", + "Context": { + "ReferenceDateTime": "2016-11-07T16:12:00" + }, + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "from 10 am for 3 hours 30 minutes", + "Start": 21, + "End": 53, + "TypeName": "datetimeV2.timerange", + "Resolution": { + "values": [ + { + "timex": "(T10,T13:30:00,PT3H30M)", + "type": "timerange", + "start": "10:00:00", + "end": "13:30:00" + } + ] + } + } + ] + }, + { + "Input": "The meeting is start from 2pm for 2 hours", + "Context": { + "ReferenceDateTime": "2016-11-07T16:12:00" + }, + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "from 2pm for 2 hours", + "Start": 21, + "End": 40, + "TypeName": "datetimeV2.timerange", + "Resolution": { + "values": [ + { + "timex": "(T14,T16:00:00,PT2H)", + "type": "timerange", + "start": "14:00:00", + "end": "16:00:00" + } + ] + } + } + ] + }, + { + "Input": "The meeting will last for 2.5 hours from 9", + "Context": { + "ReferenceDateTime": "2016-11-07T16:12:00" + }, + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "for 2.5 hours from 9", + "Start": 22, + "End": 41, + "TypeName": "datetimeV2.timerange", + "Resolution": { + "values": [ + { + "timex": "(T09,T11:30:00,PT2H30M)", + "type": "timerange", + "start": "09:00:00", + "end": "11:30:00" + } + ] + } + } + ] + }, + { + "Input": "The meeting will last for 3 hours from 10 am", + "Context": { + "ReferenceDateTime": "2016-11-07T16:12:00" + }, + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "for 3 hours from 10 am", + "Start": 22, + "End": 43, + "TypeName": "datetimeV2.timerange", + "Resolution": { + "values": [ + { + "timex": "(T10,T13:00:00,PT3H)", + "type": "timerange", + "start": "10:00:00", + "end": "13:00:00" + } + ] + } + } + ] + }, + { + "Input": "The meeting will last for 2 hours from 2pm", + "Context": { + "ReferenceDateTime": "2016-11-07T16:12:00" + }, + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "for 2 hours from 2pm", + "Start": 22, + "End": 41, + "TypeName": "datetimeV2.timerange", + "Resolution": { + "values": [ + { + "timex": "(T14,T16:00:00,PT2H)", + "type": "timerange", + "start": "14:00:00", + "end": "16:00:00" + } + ] + } + } + ] + }, { "Input": "I'll be out 5 to seven in the morning", "Context": { @@ -3828,6 +3978,68 @@ } ] }, + { + "Input": "Book meeting room on 14th Feb for 7 hours from 9:30am", + "Context": { + "ReferenceDateTime": "2018-05-31T00:00:00" + }, + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "14th feb for 7 hours from 9:30am", + "Start": 21, + "End": 52, + "TypeName": "datetimeV2.datetimerange", + "Resolution": { + "values": [ + { + "timex": "(XXXX-02-14T09:30,XXXX-02-14T16:30:00,PT7H)", + "type": "datetimerange", + "start": "2018-02-14 09:30:00", + "end": "2018-02-14 16:30:00" + }, + { + "timex": "(XXXX-02-14T09:30,XXXX-02-14T16:30:00,PT7H)", + "type": "datetimerange", + "start": "2019-02-14 09:30:00", + "end": "2019-02-14 16:30:00" + } + ] + } + } + ] + }, + { + "Input": "Book meeting room on 14th Feb from 9:30am for 7 hours", + "Context": { + "ReferenceDateTime": "2018-05-31T00:00:00" + }, + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "14th feb from 9:30am for 7 hours", + "Start": 21, + "End": 52, + "TypeName": "datetimeV2.datetimerange", + "Resolution": { + "values": [ + { + "timex": "(XXXX-02-14T09:30,XXXX-02-14T16:30:00,PT7H)", + "type": "datetimerange", + "start": "2018-02-14 09:30:00", + "end": "2018-02-14 16:30:00" + }, + { + "timex": "(XXXX-02-14T09:30,XXXX-02-14T16:30:00,PT7H)", + "type": "datetimerange", + "start": "2019-02-14 09:30:00", + "end": "2019-02-14 16:30:00" + } + ] + } + } + ] + }, { "Input": "It will happen 1/1/2015 between 10 and 11:30", "Context": { diff --git a/Specs/DateTime/English/DateTimePeriodExtractor.json b/Specs/DateTime/English/DateTimePeriodExtractor.json index 9a66ff83bc..0590d471f5 100644 --- a/Specs/DateTime/English/DateTimePeriodExtractor.json +++ b/Specs/DateTime/English/DateTimePeriodExtractor.json @@ -166,6 +166,30 @@ } ] }, + { + "Input": "Book meeting room on 14th Feb for 7 hours from 9:30am", + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "14th Feb for 7 hours from 9:30am", + "Type": "datetimerange", + "Start": 21, + "Length": 32 + } + ] + }, + { + "Input": "Book meeting room on 14th Feb from 9:30am for 7 hours", + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "14th Feb from 9:30am for 7 hours", + "Type": "datetimerange", + "Start": 21, + "Length": 32 + } + ] + }, { "Input": "I'll go back tonight", "Results": [ @@ -1047,7 +1071,7 @@ "Text": "from 12-04-2019 6:00am until 12-05-2019 8:00pm", "Type": "datetimerange", "Start": 20, - "Length": 46 + "Length": 46 } ] }, diff --git a/Specs/DateTime/English/DateTimePeriodParser.json b/Specs/DateTime/English/DateTimePeriodParser.json index a44b6916e9..620d5c4dde 100644 --- a/Specs/DateTime/English/DateTimePeriodParser.json +++ b/Specs/DateTime/English/DateTimePeriodParser.json @@ -302,6 +302,58 @@ } ] }, + { + "Input": "Book meeting room on 14th Feb for 7 hours from 9:30am", + "Context": { + "ReferenceDateTime": "2016-11-07T16:12:00" + }, + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "14th feb for 7 hours from 9:30am", + "Type": "datetimerange", + "Value": { + "Timex": "(XXXX-02-14T09:30,XXXX-02-14T16:30:00,PT7H)", + "FutureResolution": { + "startDateTime": "2017-02-14 09:30:00", + "endDateTime": "2017-02-14 16:30:00" + }, + "PastResolution": { + "startDateTime": "2016-02-14 09:30:00", + "endDateTime": "2016-02-14 16:30:00" + } + }, + "Start": 21, + "Length": 32 + } + ] + }, + { + "Input": "Book meeting room on 14th Feb from 9:30am for 7 hours", + "Context": { + "ReferenceDateTime": "2016-11-07T16:12:00" + }, + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "14th Feb from 9:30am for 7 hours", + "Type": "datetimerange", + "Value": { + "Timex": "(XXXX-02-14T09:30,XXXX-02-14T16:30:00,PT7H)", + "FutureResolution": { + "startDateTime": "2017-02-14 09:30:00", + "endDateTime": "2017-02-14 16:30:00" + }, + "PastResolution": { + "startDateTime": "2016-02-14 09:30:00", + "endDateTime": "2016-02-14 16:30:00" + } + }, + "Start": 21, + "Length": 32 + } + ] + }, { "Input": "I'll go back tonight", "Context": { diff --git a/Specs/DateTime/English/TimePeriodExtractor.json b/Specs/DateTime/English/TimePeriodExtractor.json index 1bc85cb6b2..f3553565b9 100644 --- a/Specs/DateTime/English/TimePeriodExtractor.json +++ b/Specs/DateTime/English/TimePeriodExtractor.json @@ -54,6 +54,78 @@ } ] }, + { + "Input": "The meeting is start from 9 for 2.5 hrs", + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "from 9 for 2.5 hrs", + "Type": "timerange", + "Start": 21, + "Length": 18 + } + ] + }, + { + "Input": "The meeting is start from 10 am for 3 hours 30 minutes", + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "from 10 am for 3 hours 30 minutes", + "Type": "timerange", + "Start": 21, + "Length": 33 + } + ] + }, + { + "Input": "The meeting is start from 2pm for 2 hours", + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "from 2pm for 2 hours", + "Type": "timerange", + "Start": 21, + "Length": 20 + } + ] + }, + { + "Input": "The meeting will last for 2.5 hours from 9", + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "for 2.5 hours from 9", + "Type": "timerange", + "Start": 22, + "Length": 20 + } + ] + }, + { + "Input": "The meeting will last for 3 hours from 10 am", + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "for 3 hours from 10 am", + "Type": "timerange", + "Start": 22, + "Length": 22 + } + ] + }, + { + "Input": "The meeting will last for 2 hours from 2pm", + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "for 2 hours from 2pm", + "Type": "timerange", + "Start": 22, + "Length": 20 + } + ] + }, { "Input": "I'll be out between 5 and 6pm", "Results": [ diff --git a/Specs/DateTime/English/TimePeriodParser.json b/Specs/DateTime/English/TimePeriodParser.json index 8885dee761..0f99dcbd78 100644 --- a/Specs/DateTime/English/TimePeriodParser.json +++ b/Specs/DateTime/English/TimePeriodParser.json @@ -99,6 +99,162 @@ } ] }, + { + "Input": "The meeting is start from 9 for 2.5 hrs", + "Context": { + "ReferenceDateTime": "2016-11-07T16:12:00" + }, + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "from 9 for 2.5 hrs", + "Type": "timerange", + "Value": { + "Timex": "(T09,T11:30:00,PT2H30M)", + "FutureResolution": { + "startTime": "09:00:00", + "endTime": "11:30:00" + }, + "PastResolution": { + "startTime": "09:00:00", + "endTime": "11:30:00" + } + }, + "Start": 21, + "Length": 18 + } + ] + }, + { + "Input": "The meeting is start from 10 am for 3 hours 30 minutes", + "Context": { + "ReferenceDateTime": "2016-11-07T16:12:00" + }, + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "from 10 am for 3 hours 30 minutes", + "Type": "timerange", + "Value": { + "Timex": "(T10,T13:30:00,PT3H30M)", + "FutureResolution": { + "startTime": "10:00:00", + "endTime": "13:30:00" + }, + "PastResolution": { + "startTime": "10:00:00", + "endTime": "13:30:00" + } + }, + "Start": 21, + "Length": 33 + } + ] + }, + { + "Input": "The meeting is start from 2pm for 2 hours", + "Context": { + "ReferenceDateTime": "2016-11-07T16:12:00" + }, + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "from 2pm for 2 hours", + "Type": "timerange", + "Value": { + "Timex": "(T14,T16:00:00,PT2H)", + "FutureResolution": { + "startTime": "14:00:00", + "endTime": "16:00:00" + }, + "PastResolution": { + "startTime": "14:00:00", + "endTime": "16:00:00" + } + }, + "Start": 21, + "Length": 20 + } + ] + }, + { + "Input": "The meeting will last for 2.5 hours from 9", + "Context": { + "ReferenceDateTime": "2016-11-07T16:12:00" + }, + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "for 2.5 hours from 9", + "Type": "timerange", + "Value": { + "Timex": "(T09,T11:30:00,PT2H30M)", + "FutureResolution": { + "startTime": "09:00:00", + "endTime": "11:30:00" + }, + "PastResolution": { + "startTime": "09:00:00", + "endTime": "11:30:00" + } + }, + "Start": 22, + "Length": 20 + } + ] + }, + { + "Input": "The meeting will last for 3 hours from 10 am", + "Context": { + "ReferenceDateTime": "2016-11-07T16:12:00" + }, + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "for 3 hours from 10 am", + "Type": "timerange", + "Value": { + "Timex": "(T10,T13:00:00,PT3H)", + "FutureResolution": { + "startTime": "10:00:00", + "endTime": "13:00:00" + }, + "PastResolution": { + "startTime": "10:00:00", + "endTime": "13:00:00" + } + }, + "Start": 22, + "Length": 22 + } + ] + }, + { + "Input": "The meeting will last for 2 hours from 2pm", + "Context": { + "ReferenceDateTime": "2016-11-07T16:12:00" + }, + "NotSupported": "java, javascript, python", + "Results": [ + { + "Text": "for 2 hours from 2pm", + "Type": "timerange", + "Value": { + "Timex": "(T14,T16:00:00,PT2H)", + "FutureResolution": { + "startTime": "14:00:00", + "endTime": "16:00:00" + }, + "PastResolution": { + "startTime": "14:00:00", + "endTime": "16:00:00" + } + }, + "Start": 22, + "Length": 20 + } + ] + }, { "Input": "I'll be out between 5 and 6pm", "Context": {