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.)
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.)
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.
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);
}
FYI, Just wrote this for hour+ periods, only uses java.time.*
, pretty simple to understand and customize for any need;
This version works with strings like; 3d12h
, 2y
, 9m10d
, etc.
import java.time.Duration;
import java.time.Instant;
import java.time.Period;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Locale;
private static final Pattern periodPattern = Pattern.compile("([0-9]+)([hdwmy])");
public static Long parsePeriod(String period){
if(period == null) return null;
period = period.toLowerCase(Locale.ENGLISH);
Matcher matcher = periodPattern.matcher(period);
Instant instant=Instant.EPOCH;
while(matcher.find()){
int num = Integer.parseInt(matcher.group(1));
String typ = matcher.group(2);
switch (typ) {
case "h":
instant=instant.plus(Duration.ofHours(num));
break;
case "d":
instant=instant.plus(Duration.ofDays(num));
break;
case "w":
instant=instant.plus(Period.ofWeeks(num));
break;
case "m":
instant=instant.plus(Period.ofMonths(num));
break;
case "y":
instant=instant.plus(Period.ofYears(num));
break;
}
}
return instant.toEpochMilli();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With