Reputation: 18898
How do I convert a duration to a set of temporal units? I have a duration, and I want to divide that into for instance whole years, whole days and fractional seconds.
I have found PeriodFormatterBuilder for JodaTime, but it seems to facilitate printing as well as division into units, i would just like the division.
Upvotes: 3
Views: 6869
Reputation: 44061
I am not sure if you speak about the new java.time
-package of Java-8 or about Joda-Time so I try to present solutions for both libraries.
Most important aspect however is that you cannot divide a Duration
defined in seconds into years, months etc. in a self-consistent manner because month-based units vary in length of seconds and days. At least not possible without any trick.
Best you can do in this case is to use a reference timestamp in order to recalculate the duration you have. That means you add your duration to the reference timestamp and then evaluate the new duration between the old reference timestamp and the result in years, months, days etc. This is also called normalization and has nothing to do with printing/formatting.
Duration dur = Duration.ofSeconds(5000001); // example
LocalDateTime ref = LocalDateTime.now(); // reference timestamp
LocalDateTime end = ref.plus(dur);
System.out.println(ref);
System.out.println(end);
// normalize first the calendrical part
LocalDateTime ldt = ref;
long years = ChronoUnit.YEARS.between(ldt, end);
// find the months part
ldt = ldt.plus(years, ChronoUnit.YEARS);
long months = ChronoUnit.MONTHS.between(ldt, end);
// find the days part
ldt = ldt.plus(months, ChronoUnit.MONTHS);
long days = ChronoUnit.DAYS.between(ldt, end);
// find the hours part
ldt = ldt.plus(days, ChronoUnit.DAYS);
long hours = ChronoUnit.HOURS.between(ldt, end);
// find the minutes part
ldt = ldt.plus(hours, ChronoUnit.HOURS);
long minutes = ChronoUnit.MINUTES.between(ldt, end);
// find the seconds part
ldt = ldt.plus(minutes, ChronoUnit.MINUTES);
long seconds = ChronoUnit.SECONDS.between(ldt, end);
// print the new normalized duration in ISO-8601-format
System.out.println(
String.format("P%1$dY%2$dM%3$dDT%4$dH%5$dM%6$dS", years, months, days, hours, minutes, seconds));
// example output
// 2015-03-17T12:54:07.943
// 2015-05-14T09:47:28.943
// P0Y1M26DT20H53M21S
Compared with old JDK pre 8 this can be considered as much better because at least elementary methods for calculation of a duration in one given unit are offered. But a general duration type for handling all units spanning from years to seconds is completely missing. And the best duration formatter I could find is just java.util.Formatter
.
That is the second-best Java library when duration handling is needed, in most details better than Java-8 on this area. Joda-Time indeed offers a duration type spanning from years to seconds (and millis) called Period
. See here the much simpler solution:
Duration dur = new Duration(5000001 * 1000L); // in milliseconds
LocalDateTime ref = new LocalDateTime(); // reference timestamp
LocalDateTime end = ref.plus(dur);
// construct normalized duration
PeriodType type = PeriodType.yearMonthDayTime().withMillisRemoved();
Period p = new Period(ref, end, type);
// print the new normalized duration
System.out.println(p); // P1M26DT20H53M21S
Small note: I have left out fractional seconds (in Joda-Time limited to milliseconds, in Java-8 up to nanoseconds) in given examples. It is easy to enhance the examples if you really have need for this precision.
Upvotes: 3