Java 将持续时间字符串解析为毫秒

Java 将持续时间字符串解析为毫秒,java,string,parsing,time,Java,String,Parsing,Time,我需要将形式为98d01h23m45s的持续时间字符串解析为毫秒 我希望对于这样的持续时间有一个类似于SimpleDateFormat,但我找不到任何东西。有人会建议或反对为此目的使用SDF吗 我目前的计划是使用正则表达式来匹配数字,并执行以下操作 Pattern p = Pattern.compile("(\\d+)"); Matcher m = p.matcher("98d 01h 23m 45s"); if (m.find()) { int days = Integer.pars

我需要将形式为
98d01h23m45s
的持续时间字符串解析为毫秒

我希望对于这样的持续时间有一个类似于
SimpleDateFormat
,但我找不到任何东西。有人会建议或反对为此目的使用SDF吗

我目前的计划是使用正则表达式来匹配数字,并执行以下操作

Pattern p = Pattern.compile("(\\d+)");
Matcher m = p.matcher("98d 01h 23m 45s");

if (m.find()) {
    int days = Integer.parseInt(m.group());
}
// etc. for hours, minutes, seconds
然后使用将其全部放在一起,并转换为毫秒

我想我的问题是,这似乎有点过头了,能做得容易些吗?出现了很多关于日期和时间戳的问题,但这可能有点不同。

请查看和发自

您还可以使用
PeriodFormatterBuilder
像这样为字符串构建解析器

String periodString = "98d 01h 23m 45s";

PeriodParser parser = new PeriodFormatterBuilder()
   .appendDays().appendSuffix("d ")
   .appendHours().appendSuffix("h ")
   .appendMinutes().appendSuffix("m ")
   .appendSeconds().appendSuffix("s ")
   .toParser();

MutablePeriod period = new MutablePeriod();
parser.parseInto(period, periodString, 0, Locale.getDefault());

long millis = period.toDurationFrom(new DateTime(0)).getMillis();
现在,所有这些(尤其是
toDurationFrom(…)
部分)看起来可能很棘手,但如果您在Java中处理句点和持续时间,我建议您仔细研究
JodaTime


另外,还要寻求更多的澄清。

使用
模式是一种合理的方式。但是为什么不使用一个单独的字段来获取所有四个字段呢

Pattern p = Pattern.compile("(\\d+)d\\s+(\\d+)h\\s+(\\d+)m\\s+(\\d+)s");
然后使用索引组获取

编辑:

基于您的想法,我最终编写了以下方法

private static Pattern p = Pattern
        .compile("(\\d+)d\\s+(\\d+)h\\s+(\\d+)m\\s+(\\d+)s");

/**
 * Parses a duration string of the form "98d 01h 23m 45s" into milliseconds.
 * 
 * @throws ParseException
 */
public static long parseDuration(String duration) throws ParseException {
    Matcher m = p.matcher(duration);

    long milliseconds = 0;

    if (m.find() && m.groupCount() == 4) {
        int days = Integer.parseInt(m.group(1));
        milliseconds += TimeUnit.MILLISECONDS.convert(days, TimeUnit.DAYS);
        int hours = Integer.parseInt(m.group(2));
        milliseconds += TimeUnit.MILLISECONDS
                .convert(hours, TimeUnit.HOURS);
        int minutes = Integer.parseInt(m.group(3));
        milliseconds += TimeUnit.MILLISECONDS.convert(minutes,
                TimeUnit.MINUTES);
        int seconds = Integer.parseInt(m.group(4));
        milliseconds += TimeUnit.MILLISECONDS.convert(seconds,
                TimeUnit.SECONDS);
    } else {
        throw new ParseException("Cannot parse duration " + duration, 0);
    }

    return milliseconds;
}
Java 8中的新类让您可以直接解析持续时间:

Duration.parse("P98DT01H23M45S").toMillis();
格式稍有不同,因此需要在解析之前进行调整。

我建议使用它,它是Java-8的一部分

根据ISO-8601标准,1天2小时的持续时间表示为P1DT2H,而2小时的持续时间表示为PT2H。将字符串转换为ISO-8601格式后,可以使用以下方法对其进行解析。请注意(由于Ole V.V.提供了此信息),表示天、小时、分钟和秒的后缀“D”、“H”、“M”和“S”可以采用大写或小写形式

演示:

import java.time.Duration;
import java.util.regex.Pattern;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        // Test
        Stream.of(
                "98d 01h 23m 45s",
                "01d 02h 03m 04s",
                "02h 03m 04s",
                "03m 04s",
                "04s"
        ).forEach(s -> System.out.println(durationMillis(s)));
    }

    static long durationMillis(String s) {
        if (Pattern.compile("\\d+d\\s").matcher(s).find()) {
            int idxSpace = s.indexOf(" ");
            s = "P" + s.substring(0, idxSpace) + "T" + s.substring(idxSpace + 1);
        } else
            s = "PT" + s;
        s = s.replace(" ", "");
        return Duration.parse(s).toMillis();
    }
}
8472225000
93784000
7384000
184000
4000
运行示例:

import java.time.Duration;
import java.util.regex.Pattern;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        // Test
        Stream.of(
                "98d 01h 23m 45s",
                "01d 02h 03m 04s",
                "02h 03m 04s",
                "03m 04s",
                "04s"
        ).forEach(s -> System.out.println(durationMillis(s)));
    }

    static long durationMillis(String s) {
        if (Pattern.compile("\\d+d\\s").matcher(s).find()) {
            int idxSpace = s.indexOf(" ");
            s = "P" + s.substring(0, idxSpace) + "T" + s.substring(idxSpace + 1);
        } else
            s = "PT" + s;
        s = s.replace(" ", "");
        return Duration.parse(s).toMillis();
    }
}
8472225000
93784000
7384000
184000
4000
另一种解决方法是检索每个部分(天、小时、分钟和秒)的值,并将它们添加到
持续时间中。零

static long durationMillis(String s) {
    long millis = 0;
    Matcher matcher = Pattern.compile("(?:(?:(?:0*(\\d+)d\\s)?0*(\\d+)h\\s)?0*(\\d+)m\\s)?0*(\\d+)s").matcher(s);
    if (matcher.find()) {
        int days = matcher.group(1) != null ? Integer.parseInt(matcher.group(1)) : 0;
        int hours = matcher.group(2) != null ? Integer.parseInt(matcher.group(2)) : 0;
        int minutes = matcher.group(3) != null ? Integer.parseInt(matcher.group(3)) : 0;
        int seconds = matcher.group(4) != null ? Integer.parseInt(matcher.group(4)) : 0;
        millis = Duration.ZERO.plusDays(days).plusHours(hours).plusMinutes(minutes).plusSeconds(seconds).toMillis();
    }
    return millis;
}
了解有关*的更多信息

说明:

import java.time.Duration;
import java.util.regex.Pattern;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        // Test
        Stream.of(
                "98d 01h 23m 45s",
                "01d 02h 03m 04s",
                "02h 03m 04s",
                "03m 04s",
                "04s"
        ).forEach(s -> System.out.println(durationMillis(s)));
    }

    static long durationMillis(String s) {
        if (Pattern.compile("\\d+d\\s").matcher(s).find()) {
            int idxSpace = s.indexOf(" ");
            s = "P" + s.substring(0, idxSpace) + "T" + s.substring(idxSpace + 1);
        } else
            s = "PT" + s;
        s = s.replace(" ", "");
        return Duration.parse(s).toMillis();
    }
}
8472225000
93784000
7384000
184000
4000
  • (?:
    :开始非捕获组
    • (?:
      :开始非捕获组
      • (?:
        :开始非捕获组
        • 0*
          :任意数量的零
        • (\\d+d\\s
          :一个或多个数字(第1组)后跟
          d
          和一个空格
      • )?
        :非捕获组的结束。
        使其成为可选的
      • 0*
        :任意数量的零
      • (\\d+h\\s
        :一个或多个数字(第2组)后跟
        h
        和一个空格
    • )?
      :非捕获组的结束。
      使其成为可选的
    • 0*
      :任意数量的零
    • (\\d+)m\\s
      :一个或多个数字(第3组)后跟
      m
      和一个空格
  • )?
    :非捕获组结束。
    使其成为可选的
  • 0*
    :任意数量的零
  • (\\d+)s
    :一个或多个数字(第4组)后跟
    s

*无论出于何种原因,如果您必须坚持使用Java6或Java7,您可以使用哪个backport将大部分Java.time功能移植到Java6&7。如果您正在为Android项目工作,并且您的Android API级别仍然不符合Java-8,请检查并确认。

到目前为止,您的方法看起来不错。但是要小心使用
Integer.parseInt()
和前导零。类似于
。。。08h…
将被解释为八进制,无法解析。去掉任何前导零。@PhilippReichart我上面使用它的方式不安全吗,因为
Integer.parseInt(“08”)
返回
8
?也许你想到了前导空格
System.out.println(“Integer.parseInt(“009”);
在我的机器上打印“9”。但是,
h
不应传递给
parseInt
。我的错。我总是假设
Integer.parseInt()
不接受前导零,但八进制数除外。javadocs中没有提到前导零,但它似乎可以正常工作。感谢您的提示:)感谢您的详细回复!不幸的是,我将使用一种不需要添加额外依赖项的解决方案,但我相信有人会使用您的代码。我正要使用您的代码对于解析“00:07:21.5958786”并返回整数(以毫秒或纳秒为单位)来说,这是一个新的SO问题。谢谢!顺便说一句,文档移动了,所以值得注意的是,您推荐java.time.Duration,而不是其他Duration类。