Does anyone know of a Java library that can pretty print a number in milliseconds in the same way that C# does?
E.g., 123456 ms as a long would be printed as 4d1h3m5s.
Does anyone know of a Java library that can pretty print a number in milliseconds in the same way that C# does?
E.g., 123456 ms as a long would be printed as 4d1h3m5s.
Joda Time has a pretty good way to do this using a PeriodFormatterBuilder.
Quick Win: PeriodFormat.getDefault().print(duration.toPeriod());
e.g.
//import org.joda.time.format.PeriodFormatter;
//import org.joda.time.format.PeriodFormatterBuilder;
//import org.joda.time.Duration;
Duration duration = new Duration(123456); // in milliseconds
PeriodFormatter formatter = new PeriodFormatterBuilder()
.appendDays()
.appendSuffix("d")
.appendHours()
.appendSuffix("h")
.appendMinutes()
.appendSuffix("m")
.appendSeconds()
.appendSuffix("s")
.toFormatter();
String formatted = formatter.print(duration.toPeriod());
System.out.println(formatted);
I've built a simple solution, using Java 8's Duration.toString()
and a bit of regex:
public static String humanReadableFormat(Duration duration) {
return duration.toString()
.substring(2)
.replaceAll("(\\d[HMS])(?!$)", "$1 ")
.toLowerCase();
}
The result will look like:
- 5h
- 7h 15m
- 6h 50m 15s
- 2h 5s
- 0.1s
If you don't want spaces between, just remove replaceAll
.
JodaTime has a Period
class that can represent such quantities, and can be rendered (via IsoPeriodFormat
) in ISO8601 format, e.g. PT4D1H3M5S
, e.g.
Period period = new Period(millis);
String formatted = ISOPeriodFormat.standard().print(period);
If that format isn't the one you want, then PeriodFormatterBuilder
lets you assemble arbitrary layouts, including your C#-style 4d1h3m5s
.
With Java 8 you can also use the toString()
method of java.time.Duration
to format it without external libraries using ISO 8601 seconds based representation such as PT8H6M12.345S.
Apache commons-lang provides a useful class to get this done as well DurationFormatUtils
e.g.
DurationFormatUtils.formatDurationHMS( 15362 * 1000 ) )
=> 4:16:02.000 (H:m:s.millis)
DurationFormatUtils.formatDurationISO( 15362 * 1000 ) )
=> P0Y0M0DT4H16M2.000S, cf. ISO8601
Here's how you can do it using pure JDK code:
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
long diffTime = 215081000L;
Duration duration = DatatypeFactory.newInstance().newDuration(diffTime);
System.out.printf("%02d:%02d:%02d", duration.getDays() * 24 + duration.getHours(), duration.getMinutes(), duration.getSeconds());
I realize this might not fit your use case exactly, but PrettyTime might be useful here.
PrettyTime p = new PrettyTime();
System.out.println(p.format(new Date()));
//prints: “right now”
System.out.println(p.format(new Date(1000*60*10)));
//prints: “10 minutes from now”
An alternative to the builder-approach of Joda-Time would be a pattern-based solution. This is offered by my library Time4J. Example using the class Duration.Formatter (added some spaces for more readability - removing the spaces will yield the wished C#-style):
IsoUnit unit = ClockUnit.MILLIS;
Duration<IsoUnit> dur = Duration.of(123456, unit).with(Duration.STD_PERIOD);
String s = Duration.Formatter.ofPattern("D'd' h'h' m'm' s.fff's'").format(dur);
System.out.println(s); // output: 0d 0h 2m 3.456s
Another way is using the class net.time4j.PrettyTime
(which is also good for localized output and printing relative times):
s = PrettyTime.of(Locale.ENGLISH).print(dur, TextWidth.NARROW);
System.out.println(s); // output: 2m 3s 456ms
Java 9
Duration d1 = Duration.ofDays(0);
d1 = d1.plusHours(47);
d1 = d1.plusMinutes(124);
d1 = d1.plusSeconds(124);
System.out.println(String.format("%s d %sh %sm %ss",
d1.toDaysPart(),
d1.toHoursPart(),
d1.toMinutesPart(),
d1.toSecondsPart()));
2 d 1h 6m 4s
A Java 8 version based on user678573's answer:
private static String humanReadableFormat(Duration duration) {
return String.format("%s days and %sh %sm %ss", duration.toDays(),
duration.toHours() - TimeUnit.DAYS.toHours(duration.toDays()),
duration.toMinutes() - TimeUnit.HOURS.toMinutes(duration.toHours()),
duration.getSeconds() - TimeUnit.MINUTES.toSeconds(duration.toMinutes()));
}
... since there is no PeriodFormatter in Java 8 and no methods like getHours, getMinutes, ...
I'd be happy to see a better version for Java 8.