De fato, Date
não serve para isso. Mas antes acho interessante explicar de forma mais detalhada a diferença entre datas/horas e durações:
- um horário representa um momento específico do dia. Ex: a reunião será às duas horas da tarde (diz exatamente em qual momento do dia será a reunião)
- uma duração representa uma quantidade de tempo. Ex: a reunião durou duas horas (eu não disse que horas ela começou ou terminou, só disse quanto tempo ela durou)
O que pode confundir é que tanto horários quanto durações usam as mesmas palavras (horas, minutos e segundos), e muitas vezes são escritos do mesmo jeito (“11:00” pode ser tanto 11 da manhã quanto uma duração de 11 horas). Mas cada um representa um conceito diferente.
Sendo assim, Date
serve para trabalhar com datas/horas, mas não com durações (como você mesmo percebeu).
Java >= 8
Se já estiver usando o Java >= 8, uma alternativa é usar a classe java.time.Duration
, que serve justamente para trabalhar com durações. Para gerar um Duration
a partir de uma string, seria algo do tipo:
String tempo = "30:45:12"; // 30 horas, 45 minutos e 12 segundos
String[] partes = tempo.split(":");
Duration duracao = Duration
// primeiro pega a quantidade de horas
.ofHours(Long.parseLong(partes[0]))
// depois soma a quantidade de minutos
.plusMinutes(Long.parseLong(partes[1]))
// depois soma a quantidade de segundos
.plusSeconds(Long.parseLong(partes[2]));
A partir daí você pode somar durações, por exemplo:
// calcula as durações
Duration duracao1 = ...
Duration duracao2 = ...
// soma, guarda o resultado em "total"
Duration total = duracao1.plus(duracao2);
Ou, se tiver uma lista com várias, você pode ir acumulando no total. E depois você pode, por exemplo, usar total.getSeconds()
, que retorna a duração total em segundos, para calcular a média:
List<String> listaTempos = Arrays.asList("135:50:47", "12:10:00", "43:37:20");
Duration total = Duration.ZERO;
for (String tempo : listaTempos) {
String[] partes = tempo.split(":");
total = total
// somar horas
.plusHours(Long.parseLong(partes[0]))
// somar minutos
.plusMinutes(Long.parseLong(partes[1]))
// somar segundos
.plusSeconds(Long.parseLong(partes[2]));
}
// tempo médio em nanossegundos
long mediaNanos = total.toNanos() / listaTempos.size();
Duration media = Duration.ofNanos(mediaNanos);
System.out.println("Média: " + media);
Ao imprimir o Duration
diretamente, o resultado será mostrado no formato ISO 8601 (no caso acima, será PT63H52M42.333333333S
, que representa “63 horas, 52 minutos e 42,333333333 segundos”).
Se quiser imprimir em um formato mais amigável, a partir do Java 9 pode usar os métodos toXXXPart
, que já trazem os valores devidamente quebrados:
String formatado = String.format("%02d:%02d:%02d", (media.toDaysPart() * 24) + media.toHoursPart(),
media.toMinutesPart(), media.toSecondsPart());
System.out.println(formatado);
Para versões anteriores (Java < 8), o jeito é fazer o cálculo na mão:
List<String> listaTempos = Arrays.asList("135:50:47", "12:10:00", "43:37:20");
long totalSegundos = 0;
for (String tempo : listaTempos) {
String[] partes = tempo.split(":");
long horas = Long.parseLong(partes[0]);
long minutos = Long.parseLong(partes[1]);
long segundos = Long.parseLong(partes[2]);
totalSegundos += segundos + (minutos * 60) + (horas * 3600);
}
long mediaNanos = (totalSegundos * 1000000000) / listaTempos.size();
long mediaSegundos = mediaNanos / 1000000000;
long nanos = mediaNanos % 1000000000;
long horas = mediaSegundos / 3600;
mediaSegundos %= 3600;
long minutos = mediaSegundos / 60;
mediaSegundos %= 60;
String formatado = String.format("%02d:%02d:%02d.%d", horas, minutos, mediaSegundos, nanos);
System.out.println(formatado); // 63:52:42.333333333