Parsing a Duration String in Kotlin

前提是你 提交于 2019-12-30 11:29:22

问题


I'm working on a Android application and I need to parse a duration string of this form "00:00:00.000" (Ex: "00:00:38.47" or "00:03:27.11").

My final goal is to convert this string into a double of total seconds with milliseconds to get a progression percent.

I already looked into SimpleDateFormatter, but I'm having some issue understanding how it works or how I'm supposed to use it.

I've tried this:

val timeString = "00:01:08.83"
val df = SimpleDateFormat("HH:mm:ss.SS")
df.parse(timeString)?.seconds!!.toFloat() // Returns 8.00, I want to have 68.83 for this example string

So is there a simple/efficient way of doing this ?


回答1:


  val time = LocalTime.parse("00:01:08.83", DateTimeFormatter.ofPattern("HH:mm:ss.SS"))

  println(time.toSecondOfDay())
  println(time.toNanoOfDay())
  println(time.toNanoOfDay().toFloat() / 1_000_000_000)

Output:

68
68830000000
68.83



回答2:


java.time.Duration

As shown in the linked questions there are several ways to do this. I am afraid that there isn’t one objectively best way.

You should most probably use a Duration from java.time, the modern Java date and time API, for your duration.

Unfortunately there isn’t a way to parse your string directly into a Duration. My preference is for modifying your string into ISO 8601 format, the format that the Duration class knows how to parse. I trust you to translate my Java code into even more beautiful Kotlin code.

    String timeString = "00:01:08.83";
    String isoDurationString = timeString
            .replaceFirst("(\\d+):(\\d{2}):(\\d{2}(?:\\.\\d+)?)", "PT$1H$2M$3S");
    Duration dur = Duration.parse(isoDurationString);
    System.out.println(dur);

Output from this snippet is:

PT1M8.83S

The regular expression is powerful but hard to read. The round brackets denote groups that I want to keep in the modified string; I refer to them as $1 etc. in the replacement string. (?:\\.\\d+) is a non-capturing group, one that I don’t need to use in the replacement. The ? after the non-capturing group says that it needs not be there (so the expression matches just 00:01:08 as well).

For a percentage there are some options again. Duration objects can be directly multiplied by 100 and since Java 9 divided by each other. Assuming that you are not yet on Java 9, I would probably make the calculation based on milliseconds or nanoseconds (rather than seconds with a fraction). For example:

    long totalMilliseconds = dur.toMillis();
    System.out.println(totalMilliseconds);

68830

However to answer your question here’s how I would convert to seconds in a float:

    float totalSeconds = ((float) dur.toNanos()) / TimeUnit.SECONDS.toNanos(1);
    System.out.println(totalSeconds);

68.83




回答3:


The method getSeconds() that you use returns only the seconds of the parsed time and also it is deprecated.
If you can't use LocalTime.parse() in your Android app because it requires API level 26, then split the time string and parse it by multiplying each part with the appropriate factor:

val timeString = "00:01:08.83"
val factors = arrayOf(3600.0, 60.0, 1.0, 0.01)
var value = 0.0
timeString.replace(".", ":").split(":").forEachIndexed { i, s -> value += factors[i] * s.toDouble() }
println(value)

will print:

68.83

You could also create an extension function:

fun String.toSeconds(): Double {
    val factors = arrayOf(3600.0, 60.0, 1.0, 0.01)
    var value = 0.0
    this.replace(".", ":").split(":").forEachIndexed { i, s -> value += factors[i] * s.toDouble() }
    return value
}

and use it:

val timeString = "00:01:08.83"
val seconds = timeString.toSeconds()
println(seconds)


来源:https://stackoverflow.com/questions/58670865/parsing-a-duration-string-in-kotlin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!