Acho que primeiro precisamos entender alguns conceitos. Considere as frases abaixo:
- A reunião será às duas horas
- A reunião durou duas horas
No primeiro caso, “duas horas” é um horário: um momento específico do dia. No segundo caso, “duas horas” é uma duração: uma quantidade de tempo (não diz que horas começou, somente quanto tempo durou).
Apesar de “parecidos”, esses conceitos não são a mesma coisa. O que pode confundir é que ambos usam as mesmas palavras (horas, minutos, segundos), mas eles não são a mesma coisa.
Em Java, classes como Instant
, LocalDateTime
, etc, representam datas e horas (pontos específicos na linha do tempo), enquanto um Duration
representa uma duração.
E um DateTimeFormatter
serve para formatar datas e horas, e infelizmente a API não fornece uma maneira de formatar durações.
Dito isso, o que exatamente você quer colocar no formato “dd/MM/yyyy HH:mm:ss”?
Se for a duração, não faz sentido. Você só está pegando a diferença em horas e multiplicando por um número, então o resultado não é uma data.
Só pra constar, se você quiser apenas a diferença em horas, nem precisa de Duration
, daria para usar java.time.temporal.ChronoUnit
:
double sum = ChronoUnit.HOURS.between(iInicial, iFinal) * 6.67;
Mas se você quer formatar o Instant
, aí é um pouco mais chato, pois você precisa entender outros conceitos…
O que é o java.time.Instant
Um Instant
representa um ponto na linha do tempo. Ele é um valor absoluto, que não depende de fusos horários (timezones).
No seu exemplo você usou 2020-12-03T18:00:00.00Z
. Esse “Z” no final indica que esta data e hora está em UTC (que é o padrão a partir do qual todos os fusos horários se baseiam).
Um mesmo Instant
pode corresponder a uma data e hora diferentes, dependendo do timezone. Por exemplo, no horário de Brasília, esse Instant
corresponde a 2020-12-03T15:00
(pois o horário de Brasília está 3 horas atrás do UTC - exceto quando está em horário de verão, quando a diferença passa a ser de 2 horas).
Mas esse mesmo Instant
também corresponde a 2020-12-04T03:00
no fuso horário do Japão (repare que até o dia mudou). Pois quando é 15h em Brasília, em Tóquio já é 3 da manhã do dia seguinte. O instante (o ponto na linha do tempo) é o mesmo, mas a data e hora local mudam.
Ou seja, antes de formatar o Instant
, você tem que definir qual fuso horário será usado, pois dependendo da escolha, a saída será completamente diferente.
Por exemplo, para que o Instant
seja convertido para o horário de Brasília:
Instant iInicial = ... // ler dados, fazer parse, etc
// horário de Brasília
ZoneId timezone = ZoneId.of("America/Sao_Paulo");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/uuuu HH:mm:ss");
System.out.println(formatter.format(iInicial.atZone(timezone)));
Para usar o fuso de Tóquio, bastaria trocar para ZoneId.of("Asia/Tokyo")
. Esses nomes no formato “Continente/Região” são padronizados pela IANA, e você pode consultar todos os disponíveis usando ZoneId.getAvailableZoneIds()
.
Se quiser usar a data e hora em UTC, pode fazer ZoneId timezone = ZoneOffset.UTC
;
E se quiser, também pode usar o timezone default que estiver configurado na JVM, com ZoneId.systemDefault()
- lembrando que esta é uma configuração que depende do ambiente, e que pode inclusive ser mudada em runtime (qualquer aplicação rodando na mesma JVM pode chamar TimeZone.getTimeZone
e bagunçar tudo). Se você já sabe qual timezone vai usar, melhor colocar o nome fixo em vez de depender do default.
Vale lembrar que se for usar o horário de Brasília, verifique se sua JVM está atualizada com as últimas regras do horário de verão (veja este tópico para mais detalhes).