protected DateTimeResolutionResult parseSpecificTimeOfDay()

in Java/libraries/recognizers-text-date-time/src/main/java/com/microsoft/recognizers/text/datetime/parsers/BaseDateTimePeriodParser.java [525:736]


    protected DateTimeResolutionResult parseSpecificTimeOfDay(String text, LocalDateTime referenceDate) {
        DateTimeResolutionResult result = new DateTimeResolutionResult();
        String trimmedText = text.trim().toLowerCase();
        String timeText = trimmedText;

        Optional<Match> match = Arrays.stream(RegExpUtility.getMatches(config.getPeriodTimeOfDayWithDateRegex(), trimmedText)).findFirst();

        // Extract early/late prefix from text if any
        boolean hasEarly = false;
        boolean hasLate = false;
        if (match.isPresent()) {
            timeText = match.get().getGroup("timeOfDay").value;

            if (!StringUtility.isNullOrEmpty(match.get().getGroup("early").value)) {
                hasEarly = true;
                result.setComment(Constants.Comment_Early);
                result.setMod(Constants.EARLY_MOD);
            }

            if (!hasEarly && !StringUtility.isNullOrEmpty(match.get().getGroup("late").value)) {
                hasLate = true;
                result.setComment(Constants.Comment_Late);
                result.setMod(Constants.LATE_MOD);
            }
        } else {
            match = Arrays.stream(RegExpUtility.getMatches(config.getAmDescRegex(), trimmedText)).findFirst();
            if (!match.isPresent()) {
                match = Arrays.stream(RegExpUtility.getMatches(config.getPmDescRegex(), trimmedText)).findFirst();
            }

            if (match.isPresent()) {
                timeText = match.get().value;
            }
        }

        // Handle time of day

        String timeStr = null;
        int beginHour = -1;
        int endHour = -1;
        int endMin = -1;

        // Late/early only works with time of day
        // Only standard time of day (morinng, afternoon, evening and night) will not directly return
        MatchedTimeRangeResult matchedTimeRange = config.getMatchedTimeRange(timeText, timeStr, beginHour, endHour, endMin);
        timeStr = matchedTimeRange.getTimeStr();
        beginHour = matchedTimeRange.getBeginHour();
        endHour = matchedTimeRange.getEndHour();
        endMin = matchedTimeRange.getEndMin();

        if (!matchedTimeRange.getMatched()) {
            return result;
        }

        // Modify time period if "early" or "late" exists
        // Since 'time of day' is defined as four hour periods, 
        // the first 2 hours represent early, the later 2 hours represent late
        if (hasEarly) {
            endHour = beginHour + 2;
            // Handling speical case: night ends with 23:59
            if (endMin == 59) {
                endMin = 0;
            }
        } else if (hasLate) {
            beginHour = beginHour + 2;
        }

        if (RegexExtension.isExactMatch(config.getSpecificTimeOfDayRegex(), trimmedText, true)) {
            int swift = config.getSwiftPrefix(trimmedText);

            LocalDateTime date = referenceDate.plusDays(swift);
            int day = date.getDayOfMonth();
            int month = date.getMonthValue();
            int year = date.getYear();

            result.setTimex(DateTimeFormatUtil.formatDate(date) + timeStr);

            Pair<LocalDateTime, LocalDateTime> resultValue = new Pair<LocalDateTime, LocalDateTime>(
                    DateUtil.safeCreateFromMinValue(year, month, day, beginHour, 0, 0),
                    DateUtil.safeCreateFromMinValue(year, month, day, endHour, endMin, endMin)
            );

            result.setFutureValue(resultValue);
            result.setPastValue(resultValue);

            result.setSuccess(true);

            return result;
        }

        // Handle Date followed by morning, afternoon and morning, afternoon followed by Date
        match = Arrays.stream(RegExpUtility.getMatches(config.getPeriodTimeOfDayWithDateRegex(), trimmedText)).findFirst();

        if (!match.isPresent()) {
            match = Arrays.stream(RegExpUtility.getMatches(config.getAmDescRegex(), trimmedText)).findFirst();

            if (!match.isPresent()) {
                match = Arrays.stream(RegExpUtility.getMatches(config.getPmDescRegex(), trimmedText)).findFirst();
            }
        }

        if (match.isPresent()) {
            String beforeStr = trimmedText.substring(0, match.get().index).trim();
            String afterStr = trimmedText.substring(match.get().index + match.get().length).trim();

            // Eliminate time period, if any
            List<ExtractResult> timePeriodErs = config.getTimePeriodExtractor().extract(beforeStr);
            if (timePeriodErs.size() > 0) {
                beforeStr = beforeStr.substring(0, timePeriodErs.get(0).getStart()) + beforeStr.substring(timePeriodErs.get(0).getStart() + timePeriodErs.get(0).getLength())
                        .trim();
            } else {
                timePeriodErs = config.getTimePeriodExtractor().extract(afterStr);
                if (timePeriodErs.size() > 0) {
                    afterStr = afterStr.substring(0, timePeriodErs.get(0).getStart()) + afterStr.substring(timePeriodErs.get(0).getStart() + timePeriodErs.get(0).getLength())
                            .trim();
                }
            }

            List<ExtractResult> ers = config.getDateExtractor().extract(beforeStr + " " + afterStr, referenceDate);

            if (ers.size() == 0 || ers.get(0).getLength() < beforeStr.length()) {
                boolean valid = false;

                if (ers.size() > 0 && ers.get(0).getStart() == 0) {
                    String midStr = beforeStr.substring(ers.get(0).getStart() + ers.get(0).getLength());
                    if (StringUtility.isNullOrWhiteSpace(midStr.replace(",", " "))) {
                        valid = true;
                    }
                }

                if (!valid) {
                    ers = config.getDateExtractor().extract(afterStr, referenceDate);

                    if (ers.size() == 0 || ers.get(0).getLength() != beforeStr.length()) {
                        if (ers.size() > 0 && ers.get(0).getStart() + ers.get(0).getLength() == afterStr.length()) {
                            String midStr = afterStr.substring(0, ers.get(0).getStart());
                            if (StringUtility.isNullOrWhiteSpace(midStr.replace(",", " "))) {
                                valid = true;
                            }
                        }
                    } else {
                        valid = true;
                    }
                }

                if (!valid) {
                    return result;
                }
            }

            boolean hasSpecificTimePeriod = false;
            if (timePeriodErs.size() > 0) {
                DateTimeParseResult timePr = config.getTimePeriodParser().parse(timePeriodErs.get(0), referenceDate);
                if (timePr != null) {
                    Pair<LocalDateTime, LocalDateTime> periodFuture = (Pair<LocalDateTime, LocalDateTime>)((DateTimeResolutionResult)timePr.getValue()).getFutureValue();
                    Pair<LocalDateTime, LocalDateTime> periodPast = (Pair<LocalDateTime, LocalDateTime>)((DateTimeResolutionResult)timePr.getValue()).getPastValue();

                    if (periodFuture == periodPast) {
                        beginHour = periodFuture.getValue0().getHour();
                        endHour = periodFuture.getValue1().getHour();
                    } else {
                        if (periodFuture.getValue0().getHour() >= beginHour || periodFuture.getValue1().getHour() <= endHour) {
                            beginHour = periodFuture.getValue0().getHour();
                            endHour = periodFuture.getValue1().getHour();
                        } else {
                            beginHour = periodPast.getValue0().getHour();
                            endHour = periodPast.getValue1().getHour();
                        }
                    }

                    hasSpecificTimePeriod = true;
                }
            }

            DateTimeParseResult pr = config.getDateParser().parse(ers.get(0), referenceDate);
            LocalDateTime futureDate = (LocalDateTime)((DateTimeResolutionResult)pr.getValue()).getFutureValue();
            LocalDateTime pastDate = (LocalDateTime)((DateTimeResolutionResult)pr.getValue()).getPastValue();

            if (!hasSpecificTimePeriod) {
                result.setTimex(pr.getTimexStr() + timeStr);
            } else {
                result.setTimex(String.format("(%sT%d,%sT%d,PT%dH)", pr.getTimexStr(), beginHour, pr.getTimexStr(), endHour, endHour - beginHour));
            }

            Pair<LocalDateTime, LocalDateTime> futureResult = new Pair<LocalDateTime, LocalDateTime>(
                    DateUtil.safeCreateFromMinValue(
                            futureDate.getYear(), futureDate.getMonthValue(), futureDate.getDayOfMonth(),
                            beginHour, 0, 0),
                    DateUtil.safeCreateFromMinValue(
                            futureDate.getYear(), futureDate.getMonthValue(), futureDate.getDayOfMonth(),
                            endHour, endMin, endMin)
            );

            Pair<LocalDateTime, LocalDateTime> pastResult = new Pair<LocalDateTime, LocalDateTime>(
                    DateUtil.safeCreateFromMinValue(
                            pastDate.getYear(), pastDate.getMonthValue(), pastDate.getDayOfMonth(),
                            beginHour, 0, 0),
                    DateUtil.safeCreateFromMinValue(
                            pastDate.getYear(), pastDate.getMonthValue(), pastDate.getDayOfMonth(),
                            endHour, endMin, endMin)
            );

            result.setFutureValue(futureResult);
            result.setPastValue(pastResult);

            result.setSuccess(true);

            return result;
        }

        return result;
    }