in Java/libraries/recognizers-text-date-time/src/main/java/com/microsoft/recognizers/text/datetime/parsers/BaseDatePeriodParser.java [1091:1244]
private DateTimeResolutionResult parseDuration(String text, LocalDateTime referenceDate) {
DateTimeResolutionResult ret = new DateTimeResolutionResult();
LocalDateTime beginDate = referenceDate;
LocalDateTime endDate = referenceDate;
String timex = "";
boolean restNowSunday = false;
List<LocalDateTime> dateList = null;
List<ExtractResult> durationErs = config.getDurationExtractor().extract(text, referenceDate);
if (durationErs.size() == 1) {
ParseResult durationPr = config.getDurationParser().parse(durationErs.get(0));
String beforeStr = text.substring(0, (durationPr.getStart() != null) ? durationPr.getStart() : 0).trim().toLowerCase();
String afterStr = text.substring(
((durationPr.getStart() != null) ? durationPr.getStart() : 0) + ((durationPr.getLength() != null) ? durationPr.getLength() : 0))
.trim().toLowerCase();
List<ExtractResult> numbersInSuffix = config.getCardinalExtractor().extract(beforeStr);
List<ExtractResult> numbersInDuration = config.getCardinalExtractor().extract(durationErs.get(0).getText());
// Handle cases like "2 upcoming days", "5 previous years"
if (!numbersInSuffix.isEmpty() && numbersInDuration.isEmpty()) {
ExtractResult numberEr = numbersInSuffix.stream().findFirst().get();
String numberText = numberEr.getText();
String durationText = durationErs.get(0).getText();
String combinedText = String.format("%s %s", numberText, durationText);
List<ExtractResult> combinedDurationEr = config.getDurationExtractor().extract(combinedText, referenceDate);
if (!combinedDurationEr.isEmpty()) {
durationPr = config.getDurationParser().parse(combinedDurationEr.stream().findFirst().get());
int startIndex = numberEr.getStart() + numberEr.getLength();
beforeStr = beforeStr.substring(startIndex).trim();
}
}
GetModAndDateResult getModAndDateResult = new GetModAndDateResult();
if (durationPr.getValue() != null) {
DateTimeResolutionResult durationResult = (DateTimeResolutionResult)durationPr.getValue();
if (StringUtility.isNullOrEmpty(durationResult.getTimex())) {
return ret;
}
Optional<Match> prefixMatch = Arrays.stream(RegExpUtility.getMatches(config.getPastRegex(), beforeStr)).findFirst();
Optional<Match> suffixMatch = Arrays.stream(RegExpUtility.getMatches(config.getPastRegex(), afterStr)).findFirst();
if (prefixMatch.isPresent() || suffixMatch.isPresent()) {
getModAndDateResult = getModAndDate(beginDate, endDate, referenceDate, durationResult.getTimex(), false);
beginDate = getModAndDateResult.beginDate;
}
// Handle the "within two weeks" case which means from today to the end of next two weeks
// Cases like "within 3 days before/after today" is not handled here (4th condition)
boolean isMatch = false;
if (RegexExtension.isExactMatch(config.getWithinNextPrefixRegex(), beforeStr, true)) {
getModAndDateResult = getModAndDate(beginDate, endDate, referenceDate, durationResult.getTimex(), true);
beginDate = getModAndDateResult.beginDate;
endDate = getModAndDateResult.endDate;
// In GetModAndDate, this "future" resolution will add one day to beginDate/endDate, but for the "within" case it should start from the current day.
beginDate = beginDate.minusDays(1);
endDate = endDate.minusDays(1);
isMatch = true;
}
if (RegexExtension.isExactMatch(config.getFutureRegex(), beforeStr, true)) {
getModAndDateResult = getModAndDate(beginDate, endDate, referenceDate, durationResult.getTimex(), true);
beginDate = getModAndDateResult.beginDate;
endDate = getModAndDateResult.endDate;
isMatch = true;
}
Optional<Match> futureSuffixMatch = Arrays.stream(RegExpUtility.getMatches(config.getFutureSuffixRegex(), afterStr)).findFirst();
if (futureSuffixMatch.isPresent()) {
getModAndDateResult = getModAndDate(beginDate, endDate, referenceDate, durationResult.getTimex(), true);
beginDate = getModAndDateResult.beginDate;
endDate = getModAndDateResult.endDate;
}
// Handle the "in two weeks" case which means the second week
if (RegexExtension.isExactMatch(config.getInConnectorRegex(), beforeStr, true) &&
!DurationParsingUtil.isMultipleDuration(durationResult.getTimex()) && !isMatch) {
getModAndDateResult = getModAndDate(beginDate, endDate, referenceDate, durationResult.getTimex(), true);
beginDate = getModAndDateResult.beginDate;
endDate = getModAndDateResult.endDate;
// Change the duration value and the beginDate
String unit = durationResult.getTimex().substring(durationResult.getTimex().length() - 1);
durationResult.setTimex(String.format("P1%s", unit));
beginDate = DurationParsingUtil.shiftDateTime(durationResult.getTimex(), endDate, false);
}
if (!StringUtility.isNullOrEmpty(getModAndDateResult.mod)) {
((DateTimeResolutionResult)durationPr.getValue()).setMod(getModAndDateResult.mod);
}
timex = durationResult.getTimex();
List<Object> subDateTimeEntities = new ArrayList<>();
subDateTimeEntities.add(durationPr);
ret.setSubDateTimeEntities(subDateTimeEntities);
if (getModAndDateResult.dateList != null) {
ret.setList(getModAndDateResult.dateList.stream().map(e -> (Object)e).collect(Collectors.toList()));
}
}
}
// Parse "rest of"
Optional<Match> match = Arrays.stream(RegExpUtility.getMatches(this.config.getRestOfDateRegex(), text)).findFirst();
if (match.isPresent()) {
String durationStr = match.get().getGroup("duration").value;
String durationUnit = this.config.getUnitMap().get(durationStr);
switch (durationUnit) {
case "W":
int diff = Constants.WeekDayCount - ((beginDate.getDayOfWeek().getValue()) == 0 ? Constants.WeekDayCount : beginDate.getDayOfWeek().getValue());
endDate = beginDate.plusDays(diff);
timex = String.format("P%s%s", diff, Constants.TimexDay);
if (diff == 0) {
restNowSunday = true;
}
break;
case "MON":
endDate = DateUtil.safeCreateFromMinValue(beginDate.getYear(), beginDate.getMonthValue(), 1);
endDate = endDate.plusMonths(1).minusDays(1);
diff = (int)ChronoUnit.DAYS.between(beginDate, endDate) + 1;
timex = String.format("P%s%s", diff, Constants.TimexDay);
break;
case "Y":
endDate = DateUtil.safeCreateFromMinValue(beginDate.getYear(), 12, 1);
endDate = endDate.plusMonths(1).minusDays(1);
diff = (int)ChronoUnit.DAYS.between(beginDate, endDate) + 1;
timex = String.format("P%s%s", diff, Constants.TimexDay);
break;
default:
break;
}
}
if (!beginDate.equals(endDate) || restNowSunday) {
endDate = inclusiveEndPeriod ? endDate.minusDays(1) : endDate;
ret.setTimex(String.format("(%s,%s,%s)", DateTimeFormatUtil.luisDate(beginDate), DateTimeFormatUtil.luisDate(endDate), timex));
ret.setFutureValue(new Pair<>(beginDate, endDate));
ret.setPastValue(new Pair<>(beginDate, endDate));
ret.setSuccess(true);
return ret;
}
return ret;
}