从字符串中提取多个 TimeUnits

Extract multiple TimeUnits from a String

我正在尝试去除字符串的每个时间单位,例如

字符串“4w10d50m39s”将return TimeUnit 为 4 周,TimeUnit 为 10 天,TimeUnit 为 50 分钟,TimeUnit 为 39 秒。

我怎样才能做到这一点?

上下文:我需要他们将所有时间单位加起来转换为毫秒并将其用作时间戳,它将在 Minecraft 服务器内部使用,用于为特定用户添加等级的命令时间量,例如:/addrank iLalox Vip 4w5d,这会将到期日期设置为:System.currentMillis() + timeInMillis.

要提取单位,您可以使用正则表达式

\d+[wdms]

Demo

然后您可以使用 matcher 从字符串中提取匹配项并创建 TimeUnitTimeUnit 中没有 Week 常量,所以我将周表示为 amount of weeks * 7 天数。

public static void main(String[] args) {
    String test = new String("4w10d50m39s");
    Pattern pattern = Pattern.compile("\d+[wdms]");
    Matcher matcher = pattern.matcher(test);

    while(matcher.find()) {
        String unit = matcher.group();
        char timeType = unit.charAt(unit.length() - 1);
        int timeAmount = Integer.parseInt(unit.substring(0, unit.length() - 1));
        if(timeType == 'd') {
            System.out.println(TimeUnit.DAYS.toDays(timeAmount) + " DAYS");
        }

        if(timeType == 'm') {
            System.out.println(TimeUnit.MINUTES.toMinutes(timeAmount) + " MINUTES");
        }

        if(timeType == 's') {
            System.out.println(TimeUnit.SECONDS.toSeconds(timeAmount) + " SECONDS");
        }

        if(timeType == 'w') {
            System.out.println(TimeUnit.DAYS.toDays(timeAmount * 7L) + " DAYS IN WEEK");
        }
    }
}

输出:

28 DAYS IN WEEK
10 DAYS
50 MINUTES
39 SECONDS

java.time

的周期、持续时间和瞬间

我建议您使用 java.time,现代 Java 日期和时间 API,作为您的日期和时间工作。假设您的到期时间是实时的(不是 Minecraft 时间):

    String string = "4w10d50m39s";
     
    String dayBasedString
            = string.replaceFirst("(^(?:\d+w)?(?:\d+d)?).*$", "");
    String timeBasedString = string.substring(dayBasedString.length());

    Period period = dayBasedString.isEmpty()
            ? Period.ZERO
            : Period.parse("P" + dayBasedString);
    assert period.getYears() == 0 : period;
    assert period.getMonths() == 0 : period;

    Duration dur = timeBasedString.isEmpty()
            ? Duration.ZERO
            : Duration.parse("PT" + timeBasedString); 
    dur = Duration.ofDays(period.getDays()).plus(dur);
    
    Instant now = Instant.now();
    Instant expiration = now.plus(dur);
    
    System.out.format("Now: %s; expiration: %s%n", now, expiration);

我运行刚才的代码片段时的输出:

Now: 2021-08-20T18:24:35.701136Z; expiration: 2021-09-27T19:15:14.701136Z

Java 有 classes Period 用于基于天的周期,Duration 用于基于时间的周期。由于您的字符串是两者,因此我同时使用 classes。 Instant class 时间点,例如 运行k 的到期时间。

Period class 可以像 P4w10d 一样原生地解析字符串,Duration class 像 PT50m39s 一样。挑战在于在几周和几天之后以及小时、分钟和秒之前拆分您的字符串。我的正则表达式匹配包含周 and/or 天的字符串的任何(可能为空)部分,并将这部分复制到一个单独的变量。然后将其余部分复制到另一个变量并没有那么复杂。 Period 可能包含年、月和日(周自动转换为日)。为了使我的以下计算起作用,我需要假设没有年或月,因为我不知道这些天有多少天。我还假设一天是 24 小时,尽管现实生活中并非总是如此。

作为变体,您可以使用 ZonedDateTime 表示当前时间。优点是您可以先直接添加 Period,然后再添加 Duration,而无需先将周和日转换为 Duration。作为进一步的变体,您可以使用 ThreeTen Extra 项目中的 PeriodDuration class。我没有检查过,但我希望可以将 PeriodDuration 添加到 ZonedDateTime,因为它很有意义。

I need them to sum all the Time unit converted to millis and use it as a time stamp, …

为此,您既不需要自己对单位求和,也不需要转换为毫秒。 PeriodDuration 解析较大的字符串块,Instant.plus() 直接接受我们最终得到的 Duration 对象。

链接