private parseSpecificTimeCases()

in JavaScript/packages/recognizers-date-time/src/dateTime/baseTimePeriod.ts [364:618]


    private parseSpecificTimeCases(source: string, reference: Date): DateTimeResolutionResult {
        let result = new DateTimeResolutionResult();
        let year = reference.getFullYear();
        let month = reference.getMonth();
        let day = reference.getDate();
        let trimmedText = source.trim().toLowerCase();

        // Handle cases like "from 4:30 to 5"
        let match = RegExpUtility.getMatches(this.config.specificTimeFromToRegex, source).pop();
        if (!match) {
            // Handle cases like "between 5:10 and 7"
            match = RegExpUtility.getMatches(this.config.specificTimeBetweenAndRegex, source).pop();
        }

        if (match && match.index === 0 && match.index + match.length === trimmedText.length) {
            // Cases like "half past seven" are not handled here
            if (match.groups('prefix').value !== '') {
                return result;
            }

            // Cases like "4" is different with "4:00" as the Timex is different "T04H" vs "T04H00M"
            // Uses this invalidFlag to differentiate
            let beginHour: number;
            let invalidFlag = -1;
            let beginMinute = invalidFlag;
            let beginSecond = invalidFlag;
            let endHour: number;
            let endMinute = invalidFlag;
            let endSecond = invalidFlag;

            // Get time1 and time2
            let hourGroup = match.groups('hour');
            let hourStr = hourGroup.captures[0];

            if (this.config.numbers.has(hourStr)) {
                beginHour = this.config.numbers.get(hourStr);
            }
            else {
                beginHour = parseInt(hourStr, 10);
            }

            hourStr = hourGroup.captures[1];

            if (this.config.numbers.has(hourStr)) {
                endHour = this.config.numbers.get(hourStr);
            }
            else {
                endHour = parseInt(hourStr, 10);
            }

            let time1StartIndex = match.groups('time1').index;
            let time1EndIndex = time1StartIndex + match.groups('time1').length;
            let time2StartIndex = match.groups('time2').index;
            let time2EndIndex = time2StartIndex + match.groups('time2').length;

            // Get beginMinute (if exists) and endMinute (if exists)
            let lastGroupIndex = 0;
            for (let i = 0; i < match.groups('min').captures.length; i++) {
                let minuteCapture = match.groups('min').captures[i];

                let minuteCaptureIndex = source.indexOf(minuteCapture, lastGroupIndex);

                if (minuteCaptureIndex >= time1StartIndex && minuteCaptureIndex + minuteCapture.length <= time1EndIndex) {
                    beginMinute = parseInt(minuteCapture, 10);
                }
                else if (minuteCaptureIndex >= time2StartIndex && minuteCaptureIndex + minuteCapture.length <= time2EndIndex) {
                    endMinute = parseInt(minuteCapture, 10);
                }
                lastGroupIndex = minuteCaptureIndex + 1;
            }

            lastGroupIndex = 0;

            // Get beginSecond (if exists) and endSecond (if exists)
            for (let i = 0; i < match.groups('sec').captures.length; i++) {
                let secondCapture = match.groups('sec').captures[i];

                let secondCaptureIndex = source.indexOf(secondCapture, lastGroupIndex);

                if (secondCaptureIndex >= time1StartIndex && secondCaptureIndex + secondCapture.length <= time1EndIndex) {
                    beginSecond = parseInt(secondCapture, 10);
                }
                else if (secondCaptureIndex >= time2StartIndex && secondCaptureIndex + secondCapture.length <= time2EndIndex) {
                    endSecond = parseInt(secondCapture, 10);
                }
                lastGroupIndex = secondCaptureIndex + 1;
            }

            lastGroupIndex = 0;
            // Desc here means descriptions like "am / pm / o'clock"
            // Get leftDesc (if exists) and rightDesc (if exists)
            let leftDesc = match.groups('leftDesc').value;
            let rightDesc = match.groups('rightDesc').value;

            for (let i = 0; i < match.groups('desc').captures.length; i++) {
                let descCapture = match.groups('desc').captures[i];

                let descCaptureIndex = source.indexOf(descCapture, lastGroupIndex);

                if (descCaptureIndex >= time1StartIndex && descCaptureIndex + descCapture.length <= time1EndIndex && StringUtility.isNullOrEmpty(leftDesc)) {
                    leftDesc = descCapture;
                }
                else if (descCaptureIndex >= time2StartIndex && descCaptureIndex + descCapture.length <= time2EndIndex && StringUtility.isNullOrEmpty(rightDesc)) {
                    rightDesc = descCapture;
                }

                lastGroupIndex = descCaptureIndex + 1;
            }

            let beginDateTime = DateUtils.safeCreateFromMinValue(year, month, day, beginHour, beginMinute >= 0 ? beginMinute : 0, beginSecond >= 0 ? beginSecond : 0);
            let endDateTime = DateUtils.safeCreateFromMinValue(year, month, day, endHour, endMinute >= 0 ? endMinute : 0, endSecond >= 0 ? endSecond : 0);

            let hasLeftAm = !StringUtility.isNullOrEmpty(leftDesc) && leftDesc.toLowerCase().startsWith('a');
            let hasLeftPm = !StringUtility.isNullOrEmpty(leftDesc) && leftDesc.toLowerCase().startsWith('p');
            let hasRightAm = !StringUtility.isNullOrEmpty(rightDesc) && rightDesc.toLowerCase().startsWith('a');
            let hasRightPm = !StringUtility.isNullOrEmpty(rightDesc) && rightDesc.toLowerCase().startsWith('p');
            let hasLeft = hasLeftAm || hasLeftPm;
            let hasRight = hasRightAm || hasRightPm;

            // Both timepoint has description like 'am' or 'pm'
            if (hasLeft && hasRight) {
                if (hasLeftAm) {
                    if (beginHour >= 12) {
                        beginDateTime = DateUtils.addHours(beginDateTime, -12);
                    }
                }
                else if (hasLeftPm) {
                    if (beginHour < 12) {
                        beginDateTime = DateUtils.addHours(beginDateTime, 12);
                    }
                }

                if (hasRightAm) {
                    if (endHour >= 12) {
                        endDateTime = DateUtils.addHours(endDateTime, -12);
                    }
                }
                else if (hasRightPm) {
                    if (endHour < 12) {
                        endDateTime = DateUtils.addHours(endDateTime, 12);
                    }
                }
            }
            else if (hasLeft || hasRight) {
                if (hasLeftAm) {
                    if (beginHour >= 12) {
                        beginDateTime = DateUtils.addHours(beginDateTime, -12);
                    }

                    if (endHour < 12) {
                        if (endDateTime < beginDateTime) {
                            endDateTime = DateUtils.addHours(endDateTime, 12);
                        }
                    }
                }
                else if (hasLeftPm) {
                    if (beginHour < 12) {
                        beginDateTime = DateUtils.addHours(beginDateTime, 12);
                    }

                    if (endHour < 12) {
                        if (endDateTime.getTime() < beginDateTime.getTime()) {
                            let span = DateUtils.totalHoursFloor(beginDateTime, endDateTime);
                            if (span >= 12) {
                                endDateTime = DateUtils.addHours(endDateTime, 24);
                            }
                            else {
                                endDateTime = DateUtils.addHours(endDateTime, 12);
                            }
                        }
                    }
                }

                if (hasRightAm) {
                    if (endHour >= 12) {
                        endDateTime = DateUtils.addHours(endDateTime, -12);
                    }

                    if (beginHour < 12) {
                        if (endDateTime.getTime() < beginDateTime.getTime()) {
                            beginDateTime = DateUtils.addHours(beginDateTime, -12);
                        }
                    }
                }
                else if (hasRightPm) {
                    if (endHour < 12) {
                        endDateTime = DateUtils.addHours(endDateTime, 12);
                    }

                    if (beginHour < 12) {
                        if (endDateTime.getTime() < beginDateTime.getTime()) {
                            beginDateTime = DateUtils.addHours(beginDateTime, -12);
                        }
                        else {
                            let span = DateUtils.totalHoursFloor(endDateTime, beginDateTime);
                            if (span > 12) {
                                beginDateTime = DateUtils.addHours(beginDateTime, 12);
                            }
                        }
                    }
                }
            }
            else if (!hasLeft && !hasRight && beginHour <= 12 && endHour <= 12) {
                if (beginHour > endHour) {
                    if (beginHour === 12) {
                        beginDateTime = DateUtils.addHours(beginDateTime, -12);
                    }
                    else {
                        endDateTime = DateUtils.addHours(endDateTime, 12);
                    }
                }
                result.comment = Constants.CommentAmPm;
            }

            if (endDateTime.getTime() < beginDateTime.getTime()) {
                endDateTime = DateUtils.addHours(endDateTime, 24);
            }

            let beginStr = DateTimeFormatUtil.shortTime(beginDateTime.getHours(), beginMinute, beginSecond);
            let endStr = DateTimeFormatUtil.shortTime(endDateTime.getHours(), endMinute, endSecond);

            result.success = true;
            result.timex = `(${beginStr},${endStr},${DateTimeFormatUtil.luisTimeSpan(endDateTime, beginDateTime)})`;

            result.futureValue = result.pastValue = { item1: beginDateTime, item2: endDateTime };

            result.subDateTimeEntities = [];

            // 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) {
                let er = {
                    start: time1StartIndex,
                    length: time1EndIndex - time1StartIndex,
                    text: source.substring(time1StartIndex, time1EndIndex),
                    type: Constants.SYS_DATETIME_TIME
                } as ExtractResult;
                let pr = this.config.timeParser.parse(er, reference);
                result.subDateTimeEntities.push(pr);
            }

            // Cases like "from 4am to 5", "5" should not be treated as SubDateTimeEntity
            if (hasRight || endMinute !== invalidFlag || endSecond !== invalidFlag) {
                let er = {
                    start: time2StartIndex,
                    length: time2EndIndex - time2StartIndex,
                    text: source.substring(time2StartIndex, time2EndIndex),
                    type: Constants.SYS_DATETIME_TIME
                } as ExtractResult;
                let pr = this.config.timeParser.parse(er, reference);
                result.subDateTimeEntities.push(pr);
            }
        }
        return result;
    }