Parsing time strings like "1h 30min"
Anyone know of a Java library that can parse time strings such as "30min" or "2h 15min" or "2d 15h 30min" as milliseconds (or some kind of Duration object). Can Joda-Time do something like this?
(I have an ugly long method to maintain that does such parsing and would like to get rid of it / replace it with something that does a better job.)
Solution 1:
You'll probably have to tweak this a bit for your own format, but try something along these lines:
PeriodFormatter formatter = new PeriodFormatterBuilder()
.appendDays().appendSuffix("d ")
.appendHours().appendSuffix("h ")
.appendMinutes().appendSuffix("min")
.toFormatter();
Period p = formatter.parsePeriod("2d 5h 30min");
note that there is a appendSuffix
that takes a variants
parameter if you need to make it more flexible.
Update: Joda Time has since added Period.toStandardDuration()
, and from there you can use getStandardSeconds()
to get the elapsed time in seconds as a long
.
If you're using an older version without these methods you can still calculate a timestamp yourself by assuming the standard 24/hr in a day, 60min/hr, etc. (In this case, take advantage of the constants in the DateTimeConstants
class to avoid the need for magic numbers.)
Solution 2:
Duration parsing is now included in Java 8. Use standard ISO 8601 format with Duration.parse
.
Duration d = Duration.parse("PT1H30M")
You can convert this duration to the total length in milliseconds. Beware that Duration
has a resolution of nanoseconds, so you may have data loss going from nanoseconds to milliseconds.
long milliseconds = d.toMillis();
The format is slightly different than what you describe but could be easily translated from one to another.
Solution 3:
I wanted to make the day, hour and minute optional and this seems to work to do that. Note that the appendSuffix() calls do not have a space after the character.
Using Joda 2.3.
PeriodParser parser = new PeriodFormatterBuilder()
.appendDays().appendSuffix("d").appendSeparatorIfFieldsAfter(" ")
.appendHours().appendSuffix("h").appendSeparatorIfFieldsAfter(" ")
.appendMinutes().appendSuffix("min")
.toParser();
The above code passes these tests.
@Test
public void testConvert() {
DurationConverter c = new DurationConverter();
Duration d;
Duration expected;
d = c.convert("1d");
expected = Duration.ZERO
.withDurationAdded(Duration.standardDays(1),1);
assertEquals(d, expected);
d = c.convert("1d 1h 1min");
expected = Duration.ZERO
.withDurationAdded(Duration.standardDays(1),1)
.withDurationAdded(Duration.standardHours(1),1)
.withDurationAdded(Duration.standardMinutes(1),1);
assertEquals(d, expected);
d = c.convert("1h 1min");
expected = Duration.ZERO
.withDurationAdded(Duration.standardHours(1),1)
.withDurationAdded(Duration.standardMinutes(1),1);
assertEquals(d, expected);
d = c.convert("1h");
expected = Duration.ZERO
.withDurationAdded(Duration.standardHours(1),1);
assertEquals(d, expected);
d = c.convert("1min");
expected = Duration.ZERO
.withDurationAdded(Duration.standardMinutes(1),1);
assertEquals(d, expected);
}