8

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 ?

3
  • As an aside consider throwing away the long outmoded and notoriously troublesome SimpleDateFormat and friends, and adding ThreeTenABP to your Android project in order to use java.time, the modern Java date and time API. It is so much nicer to work with. Commented Nov 3, 2019 at 12:21
  • Possible duplicate of Java: How to convert a string (HH:MM:SS) to a duration? And/or of Java 8 Time API: how to parse string of format “mm:ss” to Duration? There are more questions like it, please search. Commented Nov 3, 2019 at 12:25
  • I've searched before asking my question, but I couldn't find a definitive answer to my (specific ?) question, current accepted answer isn't in your proposed duplicates Commented Nov 3, 2019 at 12:53

3 Answers 3

5
 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 
Sign up to request clarification or add additional context in comments.

6 Comments

Looks great, but do we have a built-in constant for this 1 billion ? Random constant value isn't good for my health :D
There is one, but it has package visibility in LocalTime... The good news is that the number of nanoseconds within a second will not change soon :-)
Note that this works only if hours component is less than 24.
A LocalTime is a time of day. For a duration you want a Duration object. Using one for the other is not correct is very likely to confuse those reading your code.
That's a good point, but looking at your answer, using a duration looks way more annoying that using this. It's only one of code that can be easily commented
|
4

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

Comments

1

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) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.