简体   繁体   中英

Date library for parsing human readable arithmetic calculations

I am writing a QA test automation program where people are going to input human readable duration strings with arithmetic operations with values like now - 5d , yesterday , now + 8 days , and I need parse them into java 8 LocalDateTime instances.

So simply stated, I need a utility like this:

LocalDateTime nowMinus5Days = DurationUtil.parseHumanReadableDuration("now - 5d")

How can I code this in Java? Or is there some library that already exists that I should use instead of trying to reinvent the wheel?

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.

I think it is pretty much impossible (or at least hard) to cover conversion of every possible String input to a valid date. It could even need some intelligent Natural Language Processing.

I would suggest using a set of fields exposed for input and convert them to a desired object. If there is an end user, you can have a user select whether they want to add or subtract date and then present a Text Input where they can enter the number of days. You can handle inputs like "Yesterday" and "Tomorrow" as special inputs.

Java's Date Package is pretty useful and has methods for adding and subtracting a given number of days.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM