// handle cases like "5分钟前", "1小时以后"
        private DateTimeResolutionResult ParserDurationWithBeforeAndAfter(string text, DateObject referenceDate)
        {
            var ret         = new DateTimeResolutionResult();
            var durationRes = durationExtractor.Extract(text, referenceDate);
            var numStr      = string.Empty;
            var unitStr     = string.Empty;

            if (durationRes.Count > 0)
            {
                var match = DateTimeExtractorChs.DateTimePeriodUnitRegex.Match(text);
                if (match.Success)
                {
                    var suffix =
                        text.Substring((int)durationRes[0].Start + (int)durationRes[0].Length)
                        .Trim()
                        .ToLowerInvariant();
                    var srcUnit   = match.Groups["unit"].Value.ToLowerInvariant();
                    var numberStr =
                        text.Substring((int)durationRes[0].Start, match.Index - (int)durationRes[0].Start)
                        .Trim()
                        .ToLowerInvariant();
                    var number = ConvertChineseToNum(numberStr);
                    if (this.config.UnitMap.ContainsKey(srcUnit))
                    {
                        unitStr = this.config.UnitMap[srcUnit];
                        numStr  = number.ToString();

                        var beforeMatch = DateTimeExtractorChs.BeforeRegex.Match(suffix);
                        if (beforeMatch.Success && suffix.StartsWith(beforeMatch.Value))
                        {
                            DateObject date;
                            switch (unitStr)
                            {
                            case Constants.TimexHour:
                                date = referenceDate.AddHours(-double.Parse(numStr));
                                break;

                            case Constants.TimexMinute:
                                date = referenceDate.AddMinutes(-double.Parse(numStr));
                                break;

                            case Constants.TimexSecond:
                                date = referenceDate.AddSeconds(-double.Parse(numStr));
                                break;

                            default:
                                return(ret);
                            }

                            ret.Timex       = $"{DateTimeFormatUtil.LuisDate(date)}";
                            ret.FutureValue = ret.PastValue = date;
                            ret.Success     = true;
                            return(ret);
                        }

                        var afterMatch = DateTimeExtractorChs.AfterRegex.Match(suffix);
                        if (afterMatch.Success && suffix.StartsWith(afterMatch.Value))
                        {
                            DateObject date;
                            switch (unitStr)
                            {
                            case Constants.TimexHour:
                                date = referenceDate.AddHours(double.Parse(numStr));
                                break;

                            case Constants.TimexMinute:
                                date = referenceDate.AddMinutes(double.Parse(numStr));
                                break;

                            case Constants.TimexSecond:
                                date = referenceDate.AddSeconds(double.Parse(numStr));
                                break;

                            default:
                                return(ret);
                            }

                            ret.Timex       = $"{DateTimeFormatUtil.LuisDate(date)}";
                            ret.FutureValue = ret.PastValue = date;
                            ret.Success     = true;
                            return(ret);
                        }
                    }
                }
            }

            return(ret);
        }
Пример #2
0
        protected override DateTimeResolutionResult ParseSpecificTimeOfDay(string text, DateObject referenceTime)
        {
            var ret         = new DateTimeResolutionResult();
            var trimmedText = text.Trim();

            // handle morning, afternoon..
            if (!this.Config.GetMatchedTimeRange(trimmedText, out string timeStr, out int beginHour, out int endHour, out int endMin))
            {
                return(ret);
            }

            var exactMatch = this.Config.SpecificTimeOfDayRegex.MatchExact(trimmedText, trim: true);

            if (exactMatch.Success)
            {
                var swift = this.Config.GetSwiftPrefix(trimmedText);

                var date = referenceTime.AddDays(swift).Date;
                int day = date.Day, month = date.Month, year = date.Year;

                ret.Timex         = DateTimeFormatUtil.FormatDate(date) + timeStr;
                ret.FutureValue   =
                    ret.PastValue =
                        new Tuple <DateObject, DateObject>(
                            DateObject.MinValue.SafeCreateFromValue(year, month, day, beginHour, 0, 0),
                            DateObject.MinValue.SafeCreateFromValue(year, month, day, endHour, endMin, endMin));
                ret.Success = true;
                return(ret);
            }

            var startIndex = trimmedText.IndexOf(DateTimeDefinitions.Tomorrow, StringComparison.Ordinal) == 0 ? DateTimeDefinitions.Tomorrow.Length : 0;

            // handle Date followed by morning, afternoon
            // Add handling code to handle morning, afternoon followed by Date
            // Add handling code to handle early/late morning, afternoon
            var match = this.Config.TimeOfDayRegex.Match(trimmedText.Substring(startIndex));

            if (match.Success)
            {
                var beforeStr = trimmedText.Substring(0, match.Index + startIndex).Trim();
                var ers       = this.Config.DateExtractor.Extract(beforeStr, referenceTime);

                if (ers.Count == 0)
                {
                    return(ret);
                }

                var pr         = this.Config.DateParser.Parse(ers[0], referenceTime);
                var futureDate = (DateObject)((DateTimeResolutionResult)pr.Value).FutureValue;
                var pastDate   = (DateObject)((DateTimeResolutionResult)pr.Value).PastValue;

                ret.Timex = pr.TimexStr + timeStr;

                ret.FutureValue =
                    new Tuple <DateObject, DateObject>(
                        DateObject.MinValue.SafeCreateFromValue(futureDate.Year, futureDate.Month, futureDate.Day, beginHour, 0, 0),
                        DateObject.MinValue.SafeCreateFromValue(futureDate.Year, futureDate.Month, futureDate.Day, endHour, endMin, endMin));

                ret.PastValue =
                    new Tuple <DateObject, DateObject>(
                        DateObject.MinValue.SafeCreateFromValue(pastDate.Year, pastDate.Month, pastDate.Day, beginHour, 0, 0),
                        DateObject.MinValue.SafeCreateFromValue(pastDate.Year, pastDate.Month, pastDate.Day, endHour, endMin, endMin));

                ret.Success = true;

                return(ret);
            }

            return(ret);
        }
        // parse "in 20 minutes"
        private DateTimeResolutionResult ParseNumberWithUnit(string text, DateObject referenceTime)
        {
            var    ret = new DateTimeResolutionResult();
            string unitStr;

            // if there are spaces between number and unit
            var ers = cardinalExtractor.Extract(text);

            if (ers.Count == 1)
            {
                var pr      = cardinalParser.Parse(ers[0]);
                var srcUnit = text.Substring(ers[0].Start + ers[0].Length ?? 0).Trim();

                if (srcUnit.StartsWith("个", StringComparison.Ordinal))
                {
                    srcUnit = srcUnit.Substring(1);
                }

                var beforeStr = text.Substring(0, ers[0].Start ?? 0);
                if (this.config.UnitMap.ContainsKey(srcUnit))
                {
                    var numStr = pr.ResolutionStr;
                    unitStr = this.config.UnitMap[srcUnit];
                    var prefixMatch = ChineseDateTimePeriodExtractorConfiguration.PastRegex.MatchExact(beforeStr, trim: true);

                    if (prefixMatch.Success)
                    {
                        DateObject beginDate, endDate;
                        switch (unitStr)
                        {
                        case "H":
                            beginDate = referenceTime.AddHours(-(double)pr.Value);
                            endDate   = referenceTime;
                            break;

                        case "M":
                            beginDate = referenceTime.AddMinutes(-(double)pr.Value);
                            endDate   = referenceTime;
                            break;

                        case "S":
                            beginDate = referenceTime.AddSeconds(-(double)pr.Value);
                            endDate   = referenceTime;
                            break;

                        default:
                            return(ret);
                        }

                        ret.Timex =
                            $"({DateTimeFormatUtil.LuisDate(beginDate)}T{DateTimeFormatUtil.LuisTime(beginDate)},{DateTimeFormatUtil.LuisDate(endDate)}T{DateTimeFormatUtil.LuisTime(endDate)},PT{numStr}{unitStr[0]})";
                        ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate);
                        ret.Success     = true;
                        return(ret);
                    }

                    prefixMatch = ChineseDateTimePeriodExtractorConfiguration.FutureRegex.MatchExact(beforeStr, trim: true);

                    if (prefixMatch.Success)
                    {
                        DateObject beginDate, endDate;
                        switch (unitStr)
                        {
                        case "H":
                            beginDate = referenceTime;
                            endDate   = referenceTime.AddHours((double)pr.Value);
                            break;

                        case "M":
                            beginDate = referenceTime;
                            endDate   = referenceTime.AddMinutes((double)pr.Value);
                            break;

                        case "S":
                            beginDate = referenceTime;
                            endDate   = referenceTime.AddSeconds((double)pr.Value);
                            break;

                        default:
                            return(ret);
                        }

                        ret.Timex =
                            $"({DateTimeFormatUtil.LuisDate(beginDate)}T{DateTimeFormatUtil.LuisTime(beginDate)},{DateTimeFormatUtil.LuisDate(endDate)}T{DateTimeFormatUtil.LuisTime(endDate)},PT{numStr}{unitStr[0]})";
                        ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate);
                        ret.Success     = true;
                        return(ret);
                    }
                }
            }

            // handle "last hour"
            var match = ChineseDateTimePeriodExtractorConfiguration.UnitRegex.Match(text);

            if (match.Success)
            {
                var srcUnit   = match.Groups["unit"].Value;
                var beforeStr = text.Substring(0, match.Index).Trim();
                if (this.config.UnitMap.ContainsKey(srcUnit))
                {
                    unitStr = this.config.UnitMap[srcUnit];

                    if (ChineseDateTimePeriodExtractorConfiguration.PastRegex.IsExactMatch(beforeStr, trim: true))
                    {
                        DateObject beginDate, endDate;
                        switch (unitStr)
                        {
                        case "H":
                            beginDate = referenceTime.AddHours(-1);
                            endDate   = referenceTime;
                            break;

                        case "M":
                            beginDate = referenceTime.AddMinutes(-1);
                            endDate   = referenceTime;
                            break;

                        case "S":
                            beginDate = referenceTime.AddSeconds(-1);
                            endDate   = referenceTime;
                            break;

                        default:
                            return(ret);
                        }

                        ret.Timex =
                            $"({DateTimeFormatUtil.LuisDate(beginDate)}T{DateTimeFormatUtil.LuisTime(beginDate)},{DateTimeFormatUtil.LuisDate(endDate)}T{DateTimeFormatUtil.LuisTime(endDate)},PT1{unitStr[0]})";
                        ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate);
                        ret.Success     = true;
                        return(ret);
                    }

                    if (ChineseDateTimePeriodExtractorConfiguration.FutureRegex.IsExactMatch(beforeStr, trim: true))
                    {
                        DateObject beginDate, endDate;
                        switch (unitStr)
                        {
                        case "H":
                            beginDate = referenceTime;
                            endDate   = referenceTime.AddHours(1);
                            break;

                        case "M":
                            beginDate = referenceTime;
                            endDate   = referenceTime.AddMinutes(1);
                            break;

                        case "S":
                            beginDate = referenceTime;
                            endDate   = referenceTime.AddSeconds(1);
                            break;

                        default:
                            return(ret);
                        }

                        ret.Timex =
                            $"({DateTimeFormatUtil.LuisDate(beginDate)}T{DateTimeFormatUtil.LuisTime(beginDate)},{DateTimeFormatUtil.LuisDate(endDate)}T{DateTimeFormatUtil.LuisTime(endDate)},PT1{unitStr[0]})";
                        ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate);
                        ret.Success     = true;
                        return(ret);
                    }
                }
            }

            return(ret);
        }
        private DateTimeResolutionResult ParseTimeOfToday(string text, DateObject referenceTime)
        {
            var ret = new DateTimeResolutionResult();
            var ers = SingleTimeExtractor.Extract(text, referenceTime);

            if (ers.Count != 1)
            {
                return(ret);
            }

            // TODO: Add reference time
            var pr = this.config.TimeParser.Parse(ers[0], referenceTime);

            if (pr.Value == null)
            {
                return(ret);
            }

            var time = (DateObject)((DateTimeResolutionResult)pr.Value).FutureValue;

            var hour = time.Hour;
            var min  = time.Minute;
            var sec  = time.Second;

            var match = DateTimeExtractorChs.TimeOfTodayRegex.Match(text);

            if (match.Success)
            {
                var matchStr = match.Value.ToLowerInvariant();

                var swift = 0;
                switch (matchStr)
                {
                case "今晚":
                    if (hour < Constants.HalfDayHourCount)
                    {
                        hour += Constants.HalfDayHourCount;
                    }

                    break;

                case "今早":
                case "今晨":
                    if (hour >= Constants.HalfDayHourCount)
                    {
                        hour -= Constants.HalfDayHourCount;
                    }

                    break;

                case "明晚":
                    swift = 1;
                    if (hour < Constants.HalfDayHourCount)
                    {
                        hour += Constants.HalfDayHourCount;
                    }

                    break;

                case "明早":
                case "明晨":
                    swift = 1;
                    if (hour >= Constants.HalfDayHourCount)
                    {
                        hour -= Constants.HalfDayHourCount;
                    }

                    break;

                case "昨晚":
                    swift = -1;
                    if (hour < Constants.HalfDayHourCount)
                    {
                        hour += Constants.HalfDayHourCount;
                    }

                    break;

                default:
                    break;
                }

                var date = referenceTime.AddDays(swift).Date;

                // in this situation, luisStr cannot end up with "ampm", because we always have a "morning" or "night"
                var timeStr = pr.TimexStr;
                if (timeStr.EndsWith(Constants.Comment_AmPm))
                {
                    timeStr = timeStr.Substring(0, timeStr.Length - 4);
                }

                timeStr = "T" + hour.ToString("D2") + timeStr.Substring(3);

                ret.Timex       = DateTimeFormatUtil.FormatDate(date) + timeStr;
                ret.FutureValue = ret.PastValue = DateObject.MinValue.SafeCreateFromValue(date.Year, date.Month, date.Day, hour, min, sec);
                ret.Success     = true;
                return(ret);
            }

            return(ret);
        }
        private DateTimeResolutionResult MergeTwoTimePoints(string text, DateObject referenceTime)
        {
            var ret = new DateTimeResolutionResult();
            DateTimeParseResult pr1 = null, pr2 = null;
            bool bothHaveDates = false, beginHasDate = false, endHasDate = false;

            var er1 = SingleTimeExtractor.Extract(text, referenceTime);
            var er2 = TimeWithDateExtractor.Extract(text, referenceTime);

            var rightTime = DateObject.MinValue.SafeCreateFromValue(referenceTime.Year, referenceTime.Month, referenceTime.Day);
            var leftTime  = DateObject.MinValue.SafeCreateFromValue(referenceTime.Year, referenceTime.Month, referenceTime.Day);

            if (er2.Count == 2)
            {
                pr1           = this.config.DateTimeParser.Parse(er2[0], referenceTime);
                pr2           = this.config.DateTimeParser.Parse(er2[1], referenceTime);
                bothHaveDates = true;
            }
            else if (er2.Count == 1 && er1.Count == 2)
            {
                if (!er2[0].IsOverlap(er1[0]))
                {
                    pr1        = this.config.TimeParser.Parse(er1[0], referenceTime);
                    pr2        = this.config.DateTimeParser.Parse(er2[0], referenceTime);
                    endHasDate = true;
                }
                else
                {
                    pr1          = this.config.DateTimeParser.Parse(er2[0], referenceTime);
                    pr2          = this.config.TimeParser.Parse(er1[1], referenceTime);
                    beginHasDate = true;
                }
            }
            else if (er2.Count == 1 && er1.Count == 1)
            {
                if (er1[0].Start < er2[0].Start)
                {
                    pr1        = this.config.TimeParser.Parse(er1[0], referenceTime);
                    pr2        = this.config.DateTimeParser.Parse(er2[0], referenceTime);
                    endHasDate = true;
                }
                else
                {
                    pr1          = this.config.DateTimeParser.Parse(er2[0], referenceTime);
                    pr2          = this.config.TimeParser.Parse(er1[0], referenceTime);
                    beginHasDate = true;
                }
            }
            else if (er1.Count == 2)
            {
                // if both ends are Time. then this is a TimePeriod, not a DateTimePeriod
                return(ret);
            }
            else
            {
                return(ret);
            }

            if (pr1.Value == null || pr2.Value == null)
            {
                return(ret);
            }

            DateObject futureBegin = (DateObject)((DateTimeResolutionResult)pr1.Value).FutureValue,
                       futureEnd   = (DateObject)((DateTimeResolutionResult)pr2.Value).FutureValue;

            DateObject pastBegin = (DateObject)((DateTimeResolutionResult)pr1.Value).PastValue,
                       pastEnd   = (DateObject)((DateTimeResolutionResult)pr2.Value).PastValue;

            if (futureBegin > futureEnd)
            {
                futureBegin = pastBegin;
            }

            if (pastEnd < pastBegin)
            {
                pastEnd = futureEnd;
            }

            if (bothHaveDates)
            {
                rightTime = DateObject.MinValue.SafeCreateFromValue(futureEnd.Year, futureEnd.Month, futureEnd.Day);
                leftTime  = DateObject.MinValue.SafeCreateFromValue(futureBegin.Year, futureBegin.Month, futureBegin.Day);
            }
            else if (beginHasDate)
            {
                // TODO: Handle "明天下午两点到五点"
                futureEnd = DateObject.MinValue.SafeCreateFromValue(
                    futureBegin.Year, futureBegin.Month, futureBegin.Day, futureEnd.Hour, futureEnd.Minute, futureEnd.Second);
                pastEnd = DateObject.MinValue.SafeCreateFromValue(
                    pastBegin.Year, pastBegin.Month, pastBegin.Day, pastEnd.Hour, pastEnd.Minute, pastEnd.Second);

                leftTime = DateObject.MinValue.SafeCreateFromValue(futureBegin.Year, futureBegin.Month, futureBegin.Day);
            }
            else if (endHasDate)
            {
                // TODO: Handle "明天下午两点到五点"
                futureBegin = DateObject.MinValue.SafeCreateFromValue(
                    futureEnd.Year, futureEnd.Month, futureEnd.Day, futureBegin.Hour, futureBegin.Minute, futureBegin.Second);
                pastBegin = DateObject.MinValue.SafeCreateFromValue(
                    pastEnd.Year, pastEnd.Month, pastEnd.Day, pastBegin.Hour, pastBegin.Minute, pastBegin.Second);

                rightTime = DateObject.MinValue.SafeCreateFromValue(futureEnd.Year, futureEnd.Month, futureEnd.Day);
            }

            var leftResult      = (DateTimeResolutionResult)pr1.Value;
            var rightResult     = (DateTimeResolutionResult)pr2.Value;
            var leftResultTime  = (DateObject)leftResult.FutureValue;
            var rightResultTime = (DateObject)rightResult.FutureValue;

            int day   = referenceTime.Day,
                month = referenceTime.Month,
                year  = referenceTime.Year;

            // check if the right time is smaller than the left time, if yes, add one day
            int hour   = leftResultTime.Hour > 0 ? leftResultTime.Hour : 0,
                min    = leftResultTime.Minute > 0 ? leftResultTime.Minute : 0,
                second = leftResultTime.Second > 0 ? leftResultTime.Second : 0;

            leftTime = leftTime.AddHours(hour);
            leftTime = leftTime.AddMinutes(min);
            leftTime = leftTime.AddSeconds(second);
            DateObject.MinValue.SafeCreateFromValue(year, month, day, hour, min, second);

            hour   = rightResultTime.Hour > 0 ? rightResultTime.Hour : 0;
            min    = rightResultTime.Minute > 0 ? rightResultTime.Minute : 0;
            second = rightResultTime.Second > 0 ? rightResultTime.Second : 0;

            rightTime = rightTime.AddHours(hour);
            rightTime = rightTime.AddMinutes(min);
            rightTime = rightTime.AddSeconds(second);

            // the right side time contains "ampm", while the left side doesn't
            if (rightResult.Comment != null && rightResult.Comment.Equals(Constants.Comment_AmPm, StringComparison.Ordinal) &&
                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);
        }
        // parse "this night"
        private DateTimeResolutionResult ParseSpecificNight(string text, DateObject referenceTime)
        {
            var    ret = new DateTimeResolutionResult();
            var    trimmedText = text.Trim();
            int    beginHour, endHour, endMin = 0;
            string timeStr;

            // handle 昨晚,今晨
            if (ChineseDateTimePeriodExtractorConfiguration.SpecificTimeOfDayRegex.IsExactMatch(trimmedText, trim: true))
            {
                var swift = 0;
                switch (trimmedText)
                {
                case "今晚":
                    swift     = 0;
                    timeStr   = "TEV";
                    beginHour = 16;
                    endHour   = 20;
                    break;

                case "今早":
                case "今晨":
                    swift     = 0;
                    timeStr   = "TMO";
                    beginHour = 8;
                    endHour   = Constants.HalfDayHourCount;
                    break;

                case "明晚":
                    swift     = 1;
                    timeStr   = "TEV";
                    beginHour = 16;
                    endHour   = 20;
                    break;

                case "明早":
                case "明晨":
                    swift     = 1;
                    timeStr   = "TMO";
                    beginHour = 8;
                    endHour   = Constants.HalfDayHourCount;
                    break;

                case "昨晚":
                    swift     = -1;
                    timeStr   = "TEV";
                    beginHour = 16;
                    endHour   = 20;
                    break;

                default:
                    return(ret);
                }

                var date = referenceTime.AddDays(swift).Date;
                int day = date.Day, month = date.Month, year = date.Year;

                ret.Timex         = DateTimeFormatUtil.FormatDate(date) + timeStr;
                ret.FutureValue   =
                    ret.PastValue =
                        new Tuple <DateObject, DateObject>(
                            DateObject.MinValue.SafeCreateFromValue(year, month, day, beginHour, 0, 0),
                            DateObject.MinValue.SafeCreateFromValue(year, month, day, endHour, endMin, endMin));
                ret.Success = true;
                return(ret);
            }

            // handle morning, afternoon..
            if (MORegex.IsMatch(trimmedText))
            {
                timeStr   = "TMO";
                beginHour = 8;
                endHour   = Constants.HalfDayHourCount;
            }
            else if (MIRegex.IsMatch(trimmedText))
            {
                timeStr   = "TMI";
                beginHour = 11;
                endHour   = 13;
            }
            else if (AFRegex.IsMatch(trimmedText))
            {
                timeStr   = "TAF";
                beginHour = Constants.HalfDayHourCount;
                endHour   = 16;
            }
            else if (EVRegex.IsMatch(trimmedText))
            {
                timeStr   = "TEV";
                beginHour = 16;
                endHour   = 20;
            }
            else if (NIRegex.IsMatch(trimmedText))
            {
                timeStr   = "TNI";
                beginHour = 20;
                endHour   = 23;
                endMin    = 59;
            }
            else
            {
                return(ret);
            }

            if (ChineseDateTimePeriodExtractorConfiguration.SpecificTimeOfDayRegex.IsExactMatch(trimmedText, trim: true))
            {
                var swift = 0;
                if (ChineseDateTimePeriodExtractorConfiguration.NextRegex.IsMatch(trimmedText))
                {
                    swift = 1;
                }
                else if (ChineseDateTimePeriodExtractorConfiguration.LastRegex.IsMatch(trimmedText))
                {
                    swift = -1;
                }

                var date = referenceTime.AddDays(swift).Date;
                int day = date.Day, month = date.Month, year = date.Year;

                ret.Timex         = DateTimeFormatUtil.FormatDate(date) + timeStr;
                ret.FutureValue   =
                    ret.PastValue =
                        new Tuple <DateObject, DateObject>(
                            DateObject.MinValue.SafeCreateFromValue(year, month, day, beginHour, 0, 0),
                            DateObject.MinValue.SafeCreateFromValue(year, month, day, endHour, endMin, endMin));
                ret.Success = true;
                return(ret);
            }

            // handle Date followed by morning, afternoon
            var match = ChineseDateTimePeriodExtractorConfiguration.TimeOfDayRegex.Match(trimmedText);

            if (match.Success)
            {
                var beforeStr = trimmedText.Substring(0, match.Index).Trim();
                var ers       = SingleDateExtractor.Extract(beforeStr, referenceTime);

                if (ers.Count == 0 || ers[0].Length != beforeStr.Length)
                {
                    return(ret);
                }

                var pr         = this.config.DateParser.Parse(ers[0], referenceTime);
                var futureDate = (DateObject)((DateTimeResolutionResult)pr.Value).FutureValue;
                var pastDate   = (DateObject)((DateTimeResolutionResult)pr.Value).PastValue;

                ret.Timex = pr.TimexStr + timeStr;

                ret.FutureValue =
                    new Tuple <DateObject, DateObject>(
                        DateObject.MinValue.SafeCreateFromValue(futureDate.Year, futureDate.Month, futureDate.Day, beginHour, 0, 0),
                        DateObject.MinValue.SafeCreateFromValue(futureDate.Year, futureDate.Month, futureDate.Day, endHour, endMin, endMin));

                ret.PastValue =
                    new Tuple <DateObject, DateObject>(
                        DateObject.MinValue.SafeCreateFromValue(pastDate.Year, pastDate.Month, pastDate.Day, beginHour, 0, 0),
                        DateObject.MinValue.SafeCreateFromValue(pastDate.Year, pastDate.Month, pastDate.Day, endHour, endMin, endMin));

                ret.Success = true;

                return(ret);
            }

            return(ret);
        }
Пример #7
0
        // parse a regex match which includes 'day', 'month' and 'year' (optional) group
        protected DateTimeResolutionResult Match2Date(Match match, DateObject referenceDate)
        {
            var ret = new DateTimeResolutionResult();

            var monthStr = match.Groups["month"].Value.ToLower();
            var dayStr = match.Groups["day"].Value.ToLower();
            var yearStr = match.Groups["year"].Value.ToLower();
            var yearChsStr = match.Groups["yearchs"].Value.ToLower();
            int month = 0, day = 0, year = 0;

            var tmp = ConvertChineseYearToInteger(yearChsStr);

            year = tmp == -1 ? 0 : tmp;

            if (this.config.MonthOfYear.ContainsKey(monthStr) && this.config.DayOfMonth.ContainsKey(dayStr))
            {
                month = this.config.MonthOfYear[monthStr] > 12 ? this.config.MonthOfYear[monthStr] % 12 : this.config.MonthOfYear[monthStr];
                day   = this.config.DayOfMonth[dayStr] > 31 ? this.config.DayOfMonth[dayStr] % 31 : this.config.DayOfMonth[dayStr];
                if (!string.IsNullOrEmpty(yearStr))
                {
                    year = int.Parse(yearStr);
                    if (year < 100 && year >= Constants.MinTwoDigitYearPastNum)
                    {
                        year += 1900;
                    }
                    else if (year >= 0 && year < Constants.MaxTwoDigitYearFutureNum)
                    {
                        year += 2000;
                    }
                }
            }

            var noYear = false;

            if (year == 0)
            {
                year      = referenceDate.Year;
                ret.Timex = DateTimeFormatUtil.LuisDate(-1, month, day);
                noYear    = true;
            }
            else
            {
                ret.Timex = DateTimeFormatUtil.LuisDate(year, month, day);
            }

            var futureDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);
            var pastDate   = DateObject.MinValue.SafeCreateFromValue(year, month, day);

            if (noYear && futureDate < referenceDate)
            {
                futureDate = futureDate.AddYears(+1);
            }

            if (noYear && pastDate >= referenceDate)
            {
                pastDate = pastDate.AddYears(-1);
            }

            ret.FutureValue = futureDate;
            ret.PastValue   = pastDate;
            ret.Success     = true;

            return(ret);
        }
        public 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);
        }
Пример #9
0
        // match several other cases
        // including '今天', '后天', '十三日'
        protected DateTimeResolutionResult ParseImplicitDate(string text, DateObject referenceDate)
        {
            var ret = new DateTimeResolutionResult();

            // handle "十二日" "明年这个月三日" "本月十一日"
            var match = ChineseDateExtractorConfiguration.SpecialDate.MatchExact(text, trim: true);

            if (match.Success)
            {
                var yearStr  = match.Groups["thisyear"].Value.ToLower();
                var monthStr = match.Groups["thismonth"].Value.ToLower();
                var dayStr   = match.Groups["day"].Value.ToLower();

                int month = referenceDate.Month, year = referenceDate.Year;
                var day = this.config.DayOfMonth[dayStr];

                bool hasYear = false, hasMonth = false;

                if (!string.IsNullOrEmpty(monthStr))
                {
                    hasMonth = true;
                    if (ChineseDateExtractorConfiguration.NextRe.Match(monthStr).Success)
                    {
                        month++;
                        if (month == Constants.MaxMonth + 1)
                        {
                            month = Constants.MinMonth;
                            year++;
                        }
                    }
                    else if (ChineseDateExtractorConfiguration.LastRe.Match(monthStr).Success)
                    {
                        month--;
                        if (month == Constants.MinMonth - 1)
                        {
                            month = Constants.MaxMonth;
                            year--;
                        }
                    }

                    if (!string.IsNullOrEmpty(yearStr))
                    {
                        hasYear = true;
                        if (ChineseDateExtractorConfiguration.NextRe.Match(yearStr).Success)
                        {
                            ++year;
                        }
                        else if (ChineseDateExtractorConfiguration.LastRe.Match(yearStr).Success)
                        {
                            --year;
                        }
                    }
                }

                ret.Timex = DateTimeFormatUtil.LuisDate(hasYear ? year : -1, hasMonth ? month : -1, day);

                DateObject futureDate, pastDate;

                if (day > GetMonthMaxDay(year, month))
                {
                    var futureMonth = month + 1;
                    var pastMonth   = month - 1;
                    var futureYear  = year;
                    var pastYear    = year;

                    if (futureMonth == Constants.MaxMonth + 1)
                    {
                        futureMonth = Constants.MinMonth;
                        futureYear  = year++;
                    }

                    if (pastMonth == Constants.MinMonth - 1)
                    {
                        pastMonth = Constants.MaxMonth;
                        pastYear  = year--;
                    }

                    var isFutureValid = DateObjectExtension.IsValidDate(futureYear, futureMonth, day);
                    var isPastValid   = DateObjectExtension.IsValidDate(pastYear, pastMonth, day);

                    if (isFutureValid && isPastValid)
                    {
                        futureDate = DateObject.MinValue.SafeCreateFromValue(futureYear, futureMonth, day);
                        pastDate   = DateObject.MinValue.SafeCreateFromValue(pastYear, pastMonth, day);
                    }
                    else if (isFutureValid && !isPastValid)
                    {
                        futureDate = pastDate = DateObject.MinValue.SafeCreateFromValue(futureYear, futureMonth, day);
                    }
                    else if (!isFutureValid && !isPastValid)
                    {
                        futureDate = pastDate = DateObject.MinValue.SafeCreateFromValue(pastYear, pastMonth, day);
                    }
                    else
                    {
                        // Fall back to normal cases, might lead to resolution failure
                        // TODO: Ideally, this failure should be filtered out in extract phase
                        futureDate = pastDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);
                    }
                }
                else
                {
                    futureDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);
                    pastDate   = DateObject.MinValue.SafeCreateFromValue(year, month, day);

                    if (!hasMonth)
                    {
                        if (futureDate < referenceDate)
                        {
                            if (IsValidDate(year, month + 1, day))
                            {
                                futureDate = futureDate.AddMonths(1);
                            }
                        }

                        if (pastDate >= referenceDate)
                        {
                            if (IsValidDate(year, month - 1, day))
                            {
                                pastDate = pastDate.AddMonths(-1);
                            }
                            else if (IsNonleapYearFeb29th(year, month - 1, day))
                            {
                                pastDate = pastDate.AddMonths(-2);
                            }
                        }
                    }
                    else if (!hasYear)
                    {
                        if (futureDate < referenceDate)
                        {
                            if (IsValidDate(year + 1, month, day))
                            {
                                futureDate = futureDate.AddYears(1);
                            }
                        }

                        if (pastDate >= referenceDate)
                        {
                            if (IsValidDate(year - 1, month, day))
                            {
                                pastDate = pastDate.AddYears(-1);
                            }
                        }
                    }
                }

                ret.FutureValue = futureDate;
                ret.PastValue   = pastDate;
                ret.Success     = true;

                return(ret);
            }

            // handle cases like "昨日", "明日", "大后天"
            match = ChineseDateExtractorConfiguration.SpecialDayRegex.MatchExact(text, trim: true);

            if (match.Success)
            {
                var value = referenceDate.AddDays(config.GetSwiftDay(match.Value.ToLower()));
                ret.Timex       = DateTimeFormatUtil.LuisDate(value);
                ret.FutureValue = ret.PastValue = value;
                ret.Success     = true;

                return(ret);
            }

            if (!ret.Success)
            {
                ret = MatchThisWeekday(text, referenceDate);
            }

            if (!ret.Success)
            {
                ret = MatchNextWeekday(text, referenceDate);
            }

            if (!ret.Success)
            {
                ret = MatchLastWeekday(text, referenceDate);
            }

            if (!ret.Success)
            {
                ret = MatchWeekdayAlone(text, referenceDate);
            }

            return(ret);
        }
Пример #10
0
        // Handle cases like "三天前"
        private DateTimeResolutionResult ParserDurationWithAgoAndLater(string text, DateObject referenceDate)
        {
            var ret     = new DateTimeResolutionResult();
            var numStr  = string.Empty;
            var unitStr = string.Empty;

            var durationRes = durationExtractor.Extract(text, referenceDate);

            if (durationRes.Count > 0)
            {
                var match = ChineseDateExtractorConfiguration.UnitRegex.Match(text);
                if (match.Success)
                {
                    var suffix  = text.Substring((int)durationRes[0].Start + (int)durationRes[0].Length).Trim();
                    var srcUnit = match.Groups["unit"].Value;

                    var numberStr = text.Substring((int)durationRes[0].Start, match.Index - (int)durationRes[0].Start).Trim();
                    var number    = ConvertChineseToNum(numberStr);

                    if (this.config.UnitMap.ContainsKey(srcUnit))
                    {
                        unitStr = this.config.UnitMap[srcUnit];

                        var beforeMatch = ChineseDateExtractorConfiguration.BeforeRegex.Match(suffix);
                        if (beforeMatch.Success && suffix.StartsWith(beforeMatch.Value, StringComparison.Ordinal))
                        {
                            DateObject date;
                            switch (unitStr)
                            {
                            case Constants.TimexDay:
                                date = referenceDate.AddDays(-number);
                                break;

                            case Constants.TimexWeek:
                                date = referenceDate.AddDays(-7 * number);
                                break;

                            case Constants.TimexMonthFull:
                                date = referenceDate.AddMonths(-number);
                                break;

                            case Constants.TimexYear:
                                date = referenceDate.AddYears(-number);
                                break;

                            default:
                                return(ret);
                            }

                            ret.Timex       = $"{DateTimeFormatUtil.LuisDate(date)}";
                            ret.FutureValue = ret.PastValue = date;
                            ret.Success     = true;
                            return(ret);
                        }

                        var afterMatch = ChineseDateExtractorConfiguration.AfterRegex.Match(suffix);
                        if (afterMatch.Success && suffix.StartsWith(afterMatch.Value, StringComparison.Ordinal))
                        {
                            DateObject date;
                            switch (unitStr)
                            {
                            case Constants.TimexDay:
                                date = referenceDate.AddDays(number);
                                break;

                            case Constants.TimexWeek:
                                date = referenceDate.AddDays(7 * number);
                                break;

                            case Constants.TimexMonthFull:
                                date = referenceDate.AddMonths(number);
                                break;

                            case Constants.TimexYear:
                                date = referenceDate.AddYears(number);
                                break;

                            default:
                                return(ret);
                            }

                            ret.Timex       = $"{DateTimeFormatUtil.LuisDate(date)}";
                            ret.FutureValue = ret.PastValue = date;
                            ret.Success     = true;
                            return(ret);
                        }
                    }
                }
            }

            return(ret);
        }
Пример #11
0
        // match several other cases
        // including '今天', '后天', '十三日'
        protected DateTimeResolutionResult ParseImplicitDate(string text, DateObject referenceDate)
        {
            var ret = new DateTimeResolutionResult();

            // handle "十二日" "明年这个月三日" "本月十一日"
            var match = JapaneseDateExtractorConfiguration.SpecialDate.MatchExact(text, trim: true);

            if (match.Success)
            {
                var yearStr  = match.Groups["thisyear"].Value;
                var monthStr = match.Groups["thismonth"].Value;
                var dayStr   = match.Groups["day"].Value;

                int month = referenceDate.Month, year = referenceDate.Year;
                var day = this.config.DayOfMonth[dayStr];

                bool hasYear = false, hasMonth = false;

                if (!string.IsNullOrEmpty(monthStr))
                {
                    hasMonth = true;
                    if (JapaneseDateExtractorConfiguration.NextRe.Match(monthStr).Success)
                    {
                        month++;
                        if (month == 13)
                        {
                            month = 1;
                            year++;
                        }
                    }
                    else if (JapaneseDateExtractorConfiguration.LastRe.Match(monthStr).Success)
                    {
                        month--;
                        if (month == 0)
                        {
                            month = 12;
                            year--;
                        }
                    }

                    if (!string.IsNullOrEmpty(yearStr))
                    {
                        hasYear = true;
                        if (JapaneseDateExtractorConfiguration.NextRe.Match(yearStr).Success)
                        {
                            ++year;
                        }
                        else if (JapaneseDateExtractorConfiguration.LastRe.Match(yearStr).Success)
                        {
                            --year;
                        }
                    }
                }

                ret.Timex = DateTimeFormatUtil.LuisDate(hasYear ? year : -1, hasMonth ? month : -1, day);

                DateObject futureDate, pastDate;

                if (day > MonthMaxDays[month - 1])
                {
                    futureDate = DateObject.MinValue.SafeCreateFromValue(year, month + 1, day);
                    pastDate   = DateObject.MinValue.SafeCreateFromValue(year, month - 1, day);
                }
                else
                {
                    futureDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);
                    pastDate   = DateObject.MinValue.SafeCreateFromValue(year, month, day);
                    if (!hasMonth)
                    {
                        if (futureDate < referenceDate)
                        {
                            futureDate = futureDate.AddMonths(1);
                        }

                        if (pastDate >= referenceDate)
                        {
                            pastDate = pastDate.AddMonths(-1);
                        }
                    }
                    else if (!hasYear)
                    {
                        if (futureDate < referenceDate)
                        {
                            futureDate = futureDate.AddYears(1);
                        }

                        if (pastDate >= referenceDate)
                        {
                            pastDate = pastDate.AddYears(-1);
                        }
                    }
                }

                ret.FutureValue = futureDate;
                ret.PastValue   = pastDate;
                ret.Success     = true;

                return(ret);
            }

            // handle cases like "昨日", "明日", "大后天"
            match = JapaneseDateExtractorConfiguration.SpecialDayRegex.MatchExact(text, trim: true);

            if (match.Success)
            {
                var value = referenceDate.AddDays(JapaneseDateTimeParserConfiguration.GetSwiftDay(match.Value));
                ret.Timex       = DateTimeFormatUtil.LuisDate(value);
                ret.FutureValue = ret.PastValue = value;
                ret.Success     = true;

                return(ret);
            }

            match = JapaneseDateExtractorConfiguration.SpecialMonthRegex.MatchExact(text, trim: true);

            if (match.Success)
            {
                var value = referenceDate.AddMonths(JapaneseDateTimeParserConfiguration.GetSwiftMonth(match.Value));
                ret.Timex       = DateTimeFormatUtil.LuisDate(value);
                ret.FutureValue = ret.PastValue = value;
                ret.Success     = true;

                return(ret);
            }

            match = JapaneseDateExtractorConfiguration.SpecialYearRegex.MatchExact(text, trim: true);

            if (match.Success)
            {
                var value = referenceDate.AddYears(JapaneseDateTimeParserConfiguration.GetSwiftYear(match.Value));
                ret.Timex       = DateTimeFormatUtil.LuisDate(value);
                ret.FutureValue = ret.PastValue = value;
                ret.Success     = true;

                return(ret);
            }

            if (!ret.Success)
            {
                ret = MatchThisWeekday(text, referenceDate);
            }

            if (!ret.Success)
            {
                ret = MatchNextWeekday(text, referenceDate);
            }

            if (!ret.Success)
            {
                ret = MatchLastWeekday(text, referenceDate);
            }

            if (!ret.Success)
            {
                ret = MatchWeekdayAlone(text, referenceDate);
            }

            return(ret);
        }
Пример #12
0
        protected override DateTimeResolutionResult ParseSpecificTimeOfDay(string text, DateObject referenceTime)
        {
            var ret         = new DateTimeResolutionResult();
            var trimmedText = text.Trim();

            // handle morning, afternoon..
            if (!this.Config.GetMatchedTimeRange(trimmedText, out string timeStr, out int beginHour, out int endHour, out int endMin))
            {
                return(ret);
            }

            var exactMatch = this.Config.SpecificTimeOfDayRegex.MatchExact(trimmedText, trim: true);

            if (!exactMatch.Success)
            {
                exactMatch = this.Config.PeriodTimeOfDayWithDateRegex.MatchExact(trimmedText, trim: true);
            }

            if (exactMatch.Success)
            {
                // Extract early/late prefix from text if any
                bool hasEarly = false;
                if (!string.IsNullOrEmpty(exactMatch.Groups["early"].Value))
                {
                    hasEarly    = true;
                    ret.Comment = Constants.Comment_Early;
                    ret.Mod     = Constants.EARLY_MOD;
                    endHour     = beginHour + 2;

                    // Handling special case: night ends with 23:59 due to C# issues.
                    if (endMin == 59)
                    {
                        endMin = 0;
                    }
                }

                if (!hasEarly && !string.IsNullOrEmpty(exactMatch.Groups["late"].Value))
                {
                    ret.Comment = Constants.Comment_Late;
                    ret.Mod     = Constants.LATE_MOD;
                    beginHour   = beginHour + 2;
                }

                var swift = this.Config.GetSwiftPrefix(trimmedText);

                var date = referenceTime.AddDays(swift).Date;
                int day = date.Day, month = date.Month, year = date.Year;

                ret.Timex         = DateTimeFormatUtil.FormatDate(date) + timeStr;
                ret.FutureValue   =
                    ret.PastValue =
                        new Tuple <DateObject, DateObject>(
                            DateObject.MinValue.SafeCreateFromValue(year, month, day, beginHour, 0, 0),
                            DateObject.MinValue.SafeCreateFromValue(year, month, day, endHour, endMin, endMin));
                ret.Success = true;
                return(ret);
            }

            var startIndex = trimmedText.IndexOf(DateTimeDefinitions.Tomorrow, StringComparison.Ordinal) == 0 ? DateTimeDefinitions.Tomorrow.Length : 0;

            // handle Date followed by morning, afternoon
            // Add handling code to handle morning, afternoon followed by Date
            // Add handling code to handle early/late morning, afternoon
            var match = this.Config.TimeOfDayRegex.Match(trimmedText.Substring(startIndex));

            if (match.Success)
            {
                var beforeStr = trimmedText.Substring(0, match.Index + startIndex).Trim();
                var ers       = this.Config.DateExtractor.Extract(beforeStr, referenceTime);

                if (ers.Count == 0)
                {
                    return(ret);
                }

                // Check if Date and TimeOfDay are contiguous
                var middleStr = beforeStr.Substring((int)ers[0].Start + (int)ers[0].Length).Trim();
                if (!(string.IsNullOrWhiteSpace(middleStr) || ConnectorRegex.IsMatch(middleStr)))
                {
                    return(ret);
                }

                var pr         = this.Config.DateParser.Parse(ers[0], referenceTime);
                var futureDate = (DateObject)((DateTimeResolutionResult)pr.Value).FutureValue;
                var pastDate   = (DateObject)((DateTimeResolutionResult)pr.Value).PastValue;

                ret.Timex = pr.TimexStr + timeStr;

                ret.FutureValue =
                    new Tuple <DateObject, DateObject>(
                        DateObject.MinValue.SafeCreateFromValue(futureDate.Year, futureDate.Month, futureDate.Day, beginHour, 0, 0),
                        DateObject.MinValue.SafeCreateFromValue(futureDate.Year, futureDate.Month, futureDate.Day, endHour, endMin, endMin));

                ret.PastValue =
                    new Tuple <DateObject, DateObject>(
                        DateObject.MinValue.SafeCreateFromValue(pastDate.Year, pastDate.Month, pastDate.Day, beginHour, 0, 0),
                        DateObject.MinValue.SafeCreateFromValue(pastDate.Year, pastDate.Month, pastDate.Day, endHour, endMin, endMin));

                ret.Success = true;

                return(ret);
            }

            return(ret);
        }
        public DateTimeParseResult Parse(ExtractResult er, DateObject refDate)
        {
            var referenceTime = refDate;
            var extra         = er.Data as DateTimeExtra <PeriodType>;

            if (extra == null)
            {
                var result = new JapaneseTimeExtractorConfiguration().Extract(er.Text, refDate);
                extra = result[0]?.Data as DateTimeExtra <PeriodType>;
            }

            if (extra != null)
            {
                // Handle special case like '上午', '下午'
                var parseResult = ParseJapaneseTimeOfDay(er.Text, referenceTime);

                if (!parseResult.Success)
                {
                    parseResult = TimePeriodFunctions.Handle(this.config.TimeParser, extra, referenceTime, 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);
        }