Here’s a starting point. I am guessing that you will want to elaborate it further.
private static Pattern relativeTimePattern
= Pattern.compile("(\\w+)\\s*(?:([+-])\\s*(\\w+))?");
private static Map<String, Supplier<LocalDateTime>> bases
= Map.of("now", () -> LocalDateTime.now(),
"yesterday", () -> LocalDate.now().minusDays(1).atStartOfDay());
public static LocalDateTime parseRelativeTime(String timeString) {
Matcher m = relativeTimePattern.matcher(timeString);
if (m.matches()) {
String baseString = m.group(1);
LocalDateTime result = bases.get(baseString).get();
String signString = m.group(2);
if (signString != null) {
boolean subtract = signString.equals("-");
String diffString = m.group(3);
TemporalAmount diff;
try {
diff = Period.parse("P" + diffString);
} catch (DateTimeParseException dtpe) {
// try a Duration instead
diff = Duration.parse("PT" + diffString);
}
if (subtract) {
result = result.minus(diff);
} else {
result = result.plus(diff);
}
}
return result;
} else {
throw new IllegalArgumentException();
}
}
Let’s try it out:
System.out.println(parseRelativeTime("now - 5d"));
System.out.println(parseRelativeTime("yesterday"));
System.out.println(parseRelativeTime("now + 8d"));
Output when I ran just now:
2020-03-30T09:49:18.300731
2020-04-03T00:00
2020-04-12T09:49:18.307784
As my method stands, it accepts either of now
and yesterday
in lower case optionally followed by a sign (+
or -
) and either a period of years-months-weeks-days or a duration of hours-minutes-seconds. Each of the latter must use one letter abbreviations for the time units (y, m, w, d, h, m, s; when the ambiguous m comes alone, it is taken as months). No spaces are allowed inside the period or duration.
Thinkable further developments include:
- Add more words:
today
, tomorrow
; consider allowing upper case and mixed case.
- Allow units in full and with space, for example
8 days
. A further regex will convert this to 8d
before the final parsing into a Period
.
- Disallow the ambiguous
2m
forcing the user to specify for example 2m0d
(2 months 0 days) or 2m0s
(2 minutes 0 seconds). Or force uppercase M
for months and lowercase m
for minutes.
- The complicated part: provide useful error messages for strings that cannot be parsed.