I suggest using java.time.Duration
which is modelled on ISO-8601 standards and was introduced with Java-8 as part of JSR-310 implementation.
As per ISO-8601 standards, the duration of 1 day and 2 hours is represented as P1DT2H whereas the duration of 2 hours is represented as PT2H. After converting your string into ISO-8601 format, you can parse it using the Duration#parse
method. Note that (Thanks to Ole V.V. for this information) the suffixes "D", "H", "M" and "S" for days, hours, minutes and seconds, are accepted in upper or lower case.
Demo:
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();
}
}
A sample run:
8472225000
93784000
7384000
184000
4000
Another way to solve it is by retrieving the value of each part (day, hour, minute, and second) and adding them to Duration.ZERO
:
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;
}
Learn more about the the modern date-time API* from Trail: Date Time.
Explanation of the regex:
(?:
: Start of non-capturing group
(?:
: Start of non-capturing group
(?:
: Start of non-capturing group
0*
: Any number of zeros
(\\d+)d\\s
: One or more digits (group#1) followed by d
and a whitespace.
)?
: End of non-capturing group. The ?
makes it optional.
0*
: Any number of zeros
(\\d+)h\\s
: One or more digits (group#2) followed by h
and a whitespace.
)?
: End of non-capturing group. The ?
makes it optional.
0*
: Any number of zeros
(\\d+)m\\s
: One or more digits (group#3) followed by m
and a whitespace.
)?
: End of non-capturing group. The ?
makes it optional.
0*
: Any number of zeros
(\\d+)s
: One or more digits (group#4) followed by s
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.