Usually I wouldn't recommend Joda-Time (as it's being replaced by the new Java API's), but it's the only API I know with a good formatter/parser for periods.
You can use the PeriodFormatterBuilder
class and use appendSuffix
method to define the suffixes for singular and plural values for each field:
import org.joda.time.Period;
import org.joda.time.format.PeriodFormatter;
import org.joda.time.format.PeriodFormatterBuilder;
// method to parse the period
public void getPeriod(String input) {
PeriodFormatter formatter = new PeriodFormatterBuilder()
// hours (singular and plural suffixes)
.appendHours().appendSuffix("hour", "hours")
// minutes
.appendMinutes().appendSuffix("min", "mins")
// seconds
.appendSeconds().appendSuffix("sec", "secs")
// create formatter
.toFormatter();
// remove spaces and change "hr" to "hour"
Period p = formatter.parsePeriod(input.replaceAll(" ", "").replaceAll("hr", "hour"));
double hours = p.getHours();
hours += p.getMinutes() / 60d;
hours += p.getSeconds() / 3600d;
System.out.println(hours);
}
// tests
getPeriod("1 hour 30 mins 20 secs");
getPeriod("2 hrs 10 mins");
getPeriod("45 mins");
Output:
1.5055555555555555
2.1666666666666665
0.75
Another way of creating the PeriodFormatter
is using appendSuffix
with regular expressions. It's useful when you have lots of different options for the suffix (like hour
and hr
for the hours field):
PeriodFormatter formatter = new PeriodFormatterBuilder()
// hours (all possible suffixes for singular and plural)
.appendHours()
.appendSuffix(
// regular expressions for singular and plural
new String[] { "^1$", ".*", "^1$", ".*" },
// possible suffixes for singular and plural
new String[] { " hour", " hours", " hr", " hrs" })
// optional space (if there are more fields)
.appendSeparatorIfFieldsBefore(" ")
// minutes
.appendMinutes().appendSuffix(" min", " mins")
// optional space (if there are more fields)
.appendSeparatorIfFieldsBefore(" ")
// seconds
.appendSeconds().appendSuffix(" sec", " secs")
// create formatter
.toFormatter();
Note that I've also added appendSeparatorIfFieldsBefore(" ")
to indicate that it has a space before the next field.
The good thing about this version is that you don't need to pre-process the input:
// no need to call replaceAll (take input just as it is)
Period p = formatter.parsePeriod(input);
The output is the same as above.
Java 8 date-time API
As stated in @assylian's answer, you can use the java.time.Duration
class:
public void getDuration(String input) {
// replace hour/min/secs strings for H, M and S
String adjusted = input.replaceAll("\\s*(hour|hr)s?\\s*", "H");
adjusted = adjusted.replaceAll("\\s*mins?\\s*", "M");
adjusted = adjusted.replaceAll("\\s*secs?\\s*", "S");
Duration d = Duration.parse("PT" + adjusted);
double hours = d.toMillis() / 3600000d;
System.out.println(hours);
}
//tests
getDuration("1 hour 30 mins 20 secs");
getDuration("2 hrs 10 mins");
getDuration("45 mins");
The output is the same.
PS: if your Java version is <= 7, you can use the ThreeTen Backport. The class name and methods are the same, the only difference is the package name: org.threeten.bp
instead of java.time
.