用于解析人类可读算术计算的数据库

Date library for parsing human readable arithmetic calculations

我正在编写一个 QA 测试自动化程序,人们将在其中输入人类可读的持续时间字符串,这些字符串具有 now - 5dyesterdaynow + 8 days 等值的算术运算,我需要将它们解析为 java 8 LocalDateTime 个实例。

简单地说,我需要这样的实用程序:

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

如何在 Java 中编写代码?或者是否有一些已经存在的库我应该使用而不是试图重新发明轮子?

我认为几乎不可能(或至少很难)涵盖每个可能的字符串输入到有效日期的转换。它甚至可能需要一些智能的自然语言处理。

我建议使用一组为输入公开的字段,并将它们 convert 到所需的对象。如果有最终用户,您可以让用户 select 无论他们想要添加还是减去日期,然后呈现一个文本输入,他们可以在其中输入天数。您可以将 "Yesterday" 和 "Tomorrow" 之类的输入作为特殊输入处理。

Java 的日期包非常有用,并且有 methods 用于添加和减去给定的天数。

这是一个起点。我猜你会想要进一步详细说明。

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();
    }
}

让我们试试看:

    System.out.println(parseRelativeTime("now - 5d"));
    System.out.println(parseRelativeTime("yesterday"));
    System.out.println(parseRelativeTime("now + 8d"));

我刚才运行时输出:

2020-03-30T09:49:18.300731
2020-04-03T00:00
2020-04-12T09:49:18.307784

按照我的方法,它接受小写的 nowyesterday 中的任一个,可选地后跟一个符号(+-)和 年-月-周-日 小时-分钟-秒的持续时间。后者每一个都必须使用一个字母缩写来表示时间单位(y、m、w、d、h、m、s;当有歧义的m单独出现时,它被视为月份)。期间或持续时间内不允许有 space。

可以想到的进一步发展包括:

  • 添加更多字词:todaytomorrow;考虑允许大写和混合大小写。
  • 允许单位完整并带有 space,例如 8 days。在最终解析为 Period.
  • 之前,进一步的正则表达式会将其转换为 8d
  • 不允许模棱两可的 2m 强制用户指定例如 2m0d(2 个月 0 天)或 2m0s(2 分钟 0 秒)。或者强制大写 M 表示月份,小写 m 表示分钟。
  • 复杂的部分:为无法解析的字符串提供有用的错误消息。