Format java.time.Duration for String

3

The code below is producing the following output:

Resultado: PT2H30M

I would like it to be:

Resultado: 2:30

Does anyone know how I can do it?

import java.time.Duration;
import java.time.LocalDateTime;

public class TesteDuration {
public static void main(String[] args) {

    LocalDateTime primeiraData = LocalDateTime.of(2017, Month.JANUARY, 10, 14, 00, 00);
    LocalDateTime segundaDate = LocalDateTime.of(2016, Month.JANUARY, 10, 16, 30, 00);

    Duration testeDuration = Duration.between(primeiraData, segundaDate);
    System.out.println("Resultado: " + testeDuration.toString());

}
    
asked by anonymous 22.01.2017 / 17:01

2 answers

3

Another way of doing, complementing diegofm response , is to go subtracting the date one fields to one to remove from it, each component.

For example:

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.temporal.ChronoUnit;

class TesteDurationNovo {
    public static void main(String[] args) {

        LocalDateTime primeiraData = LocalDateTime.of(2017, Month.JANUARY, 10, 14, 00, 00);
        LocalDateTime segundaDate = LocalDateTime.of(2016, Month.JANUARY, 10, 16, 30, 00);

        Duration testeDuration = Duration.between(primeiraData, segundaDate);
        long dias = testeDuration.toDays();
        Duration d2 = testeDuration.minus(dias, ChronoUnit.DAYS);
        long horas = d2.toHours();
        Duration d3 = d2.minus(horas, ChronoUnit.HOURS);
        long minutos = d3.toMinutes();
        Duration d4 = d3.minus(minutos, ChronoUnit.MINUTES);
        long segundos = d4.getSeconds();
        Duration d5 = d4.minus(segundos, ChronoUnit.SECONDS);
        long nanos = d5.toNanos();
        Duration d6 = d5.minus(nanos, ChronoUnit.NANOS);

        System.out.println("Total: " + dias + " dias, " + horas + " horas, " + minutos + " minutos, " + segundos + " segundos, " + nanos + " ns.");
        System.out.println("Resultado: " + testeDuration.toString());
        if (!d6.isZero()) throw new AssertionError(d6.toString());
    }
}

Here's the output:

Total: -365 dias, -21 horas, -30 minutos, 0 segundos, 0 ns.
Resultado: PT-8781H-30M

This means your period is 365 days, 21 hours, and 30 minutes negatives . The period is negative because primeiraData is after segundaDate . This can be fixed if you simply change the dates you assign to each variable, or if you change the order of the parameters in the between(Temporal, Temporal) ", or if you call the abs() of Duration and then store the result in the testeDuration variable %.

It is not possible to subtract months or years in a simple and direct way from Duration because not every month and every year is the same size. That is why there are no methods toMonths() or toYears() .

As for the result of toString() , this PT-8781H-30M only means that the duration is -8781 hours and -30 minutes. The% returned% will always contain the amount of hours, minutes, and seconds of String , which can be the fraction of seconds for cases that include nanoseconds and the amount of hours for all unlimited practical effects.

Since this Duration at the end is just to make sure that if remaining after subtracting all fields is zero. If it were not, it would be because something wrong would be happening in the above process, a fact that would then be denounced by the launch of a Duration .

See here working on ideone.

Oh, and if you change the AssertionError to 2016 instead of 2017, you get this result:

Total: 0 dias, 2 horas, 30 minutos, 0 segundos, 0 ns.
Resultado: PT2H30M

I think this is what you had when you got primeiraData as output.

And if you're sure that your result will be only in hours and minutes, you could do that, similar to diegofm's answer:

System.out.println("Resultado: " + String.format("%d:%02d", horas, minutos));

However, this will not work if you have to consider hours, days, seconds or nanoseconds as well. It also will not work if the period is negative. So you should look for what works best for you by considering the dates and times that your program will have to deal with.

    
22.01.2017 / 18:28
4

By following this answer removed from SOEn, you can use String.format :

LocalDateTime primeiraData = LocalDateTime.of(2017, Month.JANUARY, 10, 14, 00, 00);
LocalDateTime segundaDate = LocalDateTime.of(2017, Month.JANUARY, 10, 16, 30, 00);

Duration testeDuration = Duration.between(primeiraData, segundaDate);
long s = testeDuration.getSeconds();
System.out.println("Resultado: " + String.format("%d:%02d", s / 3600, (s % 3600) / 60));

See working at IDEONE .

Remembering that in your code, you are comparing a time period to different dates, and the best thing to do is compare Period . For comparisons of the same date, the code above works perfectly.

    
22.01.2017 / 17:49