Java 8: Diferença entre dois LocalDateTime em várias unidades

266

Estou tentando calcular a diferença entre dois LocalDateTime.

A saída precisa estar no formato y years m months d days h hours m minutes s seconds. Aqui está o que eu escrevi:

import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneId;

public class Main {

    static final int MINUTES_PER_HOUR = 60;
    static final int SECONDS_PER_MINUTE = 60;
    static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;

    public static void main(String[] args) {
        LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 9, 19, 46, 45);
        LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);

        Period period = getPeriod(fromDateTime, toDateTime);
        long time[] = getTime(fromDateTime, toDateTime);

        System.out.println(period.getYears() + " years " + 
                period.getMonths() + " months " + 
                period.getDays() + " days " +
                time[0] + " hours " +
                time[1] + " minutes " +
                time[2] + " seconds.");


    }

    private static Period getPeriod(LocalDateTime dob, LocalDateTime now) {
        return Period.between(dob.toLocalDate(), now.toLocalDate());
    }

    private static long[] getTime(LocalDateTime dob, LocalDateTime now) {
        LocalDateTime today = LocalDateTime.of(now.getYear(),
                now.getMonthValue(), now.getDayOfMonth(), dob.getHour(), dob.getMinute(), dob.getSecond());
        Duration duration = Duration.between(today, now);

        long seconds = duration.getSeconds();

        long hours = seconds / SECONDS_PER_HOUR;
        long minutes = ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
        long secs = (seconds % SECONDS_PER_MINUTE);

        return new long[]{hours, minutes, secs};
    }
}

A saída que estou recebendo é 29 years 8 months 24 days 12 hours 0 minutes 50 seconds. Eu verifiquei meu resultado neste site (com valores 12/16/1984 07:45:55e 09/09/2014 19:46:45). A captura de tela a seguir mostra a saída:

Epoch Converter

Tenho certeza de que os campos após o valor do mês estão incorretos no meu código. Qualquer sugestão seria muito útil.

Atualizar

Testei meu resultado em outro site e o resultado obtido é diferente. Aqui está: Calcule a duração entre duas datas (resultado: 29 anos, 8 meses, 24 dias, 12 horas, 0 minutos e 50 segundos).

Atualizar

Como obtive dois resultados diferentes de dois sites diferentes, estou me perguntando se o algoritmo do meu cálculo é legítimo ou não. Se eu usar os seguintes dois LocalDateTimeobjetos:

LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 40, 45);
LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);

Então a saída está chegando: 29 years 8 months 25 days -1 hours -5 minutes -10 seconds.

A partir deste link deve ser 29 years 8 months 24 days 22 hours, 54 minutes and 50 seconds. Portanto, o algoritmo também precisa lidar com os números negativos.

Observe que a pergunta não é sobre qual site me deu o resultado, preciso conhecer o algoritmo certo e ter os resultados certos.

Tapas Bose
fonte
Apenas um palpite, mas pode Period.between()aplicar alguns arredondamentos?
Thomas
3
Acabei de olhar o código mais uma vez e parece que o site está errado (tente se calcular). Se você omitir a data, ou seja, diferenças de ano, mês e dia, receberá a hora de início 7:45:55e a hora de término 19:46:45(ou 7:46:45PM). Portanto, a diferença entre essas duas vezes é de 12 horas, 0 minutos e 50 segundos e nunca 23 horas, 34 minutos e 12 segundos. Portanto, seu cálculo atual parece estar correto, pelo menos na parte do tempo.
Thomas
1
Fenômeno interessante nesse site: adicione 10 anos à data de início e a diferença de horas muda de 23 para 8 - certamente um sinal de erro.
Thomas
8
Observe que, como LocalDateTimenão possui fuso horário, pode não haver uma resposta única. Mesmo se você presumir que os fusos horários de início e término são os mesmos, em determinadas zonas como 09-09-2014 será no horário de verão ou no horário de verão e em outros não. Isso pode prejudicar as coisas em uma hora. Portanto, calcular a diferença para o segundo não faz sentido, a menos que isso seja resolvido.
Stuart Marks
2
Você entende que o uso LocalDateTimegera resultados irreais, pois essa classe propositalmente não possui qualquer conceito de fuso horário ou deslocamento do UTC? Para valores realistas, atribua um fuso horário via ZoneIda ser usado ZonedDateTime.
Basil Bourque

Respostas:

163

Infelizmente, não parece haver uma classe de período que abranja também o tempo; portanto, você pode ter que fazer os cálculos por conta própria.

Felizmente, as classes de data e hora têm muitos métodos de utilidade que simplificam isso até certo ponto. Aqui está uma maneira de calcular a diferença, embora não seja necessariamente a mais rápida:

LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 40, 45);

LocalDateTime tempDateTime = LocalDateTime.from( fromDateTime );

long years = tempDateTime.until( toDateTime, ChronoUnit.YEARS );
tempDateTime = tempDateTime.plusYears( years );

long months = tempDateTime.until( toDateTime, ChronoUnit.MONTHS );
tempDateTime = tempDateTime.plusMonths( months );

long days = tempDateTime.until( toDateTime, ChronoUnit.DAYS );
tempDateTime = tempDateTime.plusDays( days );


long hours = tempDateTime.until( toDateTime, ChronoUnit.HOURS );
tempDateTime = tempDateTime.plusHours( hours );

long minutes = tempDateTime.until( toDateTime, ChronoUnit.MINUTES );
tempDateTime = tempDateTime.plusMinutes( minutes );

long seconds = tempDateTime.until( toDateTime, ChronoUnit.SECONDS );

System.out.println( years + " years " + 
        months + " months " + 
        days + " days " +
        hours + " hours " +
        minutes + " minutes " +
        seconds + " seconds.");

//prints: 29 years 8 months 24 days 22 hours 54 minutes 50 seconds.

A idéia básica é a seguinte: crie uma data de início temporária e obtenha os anos completos até o fim. Em seguida, ajuste essa data pelo número de anos para que a data de início seja inferior a um ano a partir do final. Repita isso para cada unidade de tempo em ordem decrescente.

Por fim, um aviso de isenção de responsabilidade : não levei em conta fusos horários diferentes (as duas datas devem estar no mesmo fuso horário) e também não testei / verifiquei como o horário de verão ou outras alterações em um calendário (como o fuso horário em Samoa) afeta esse cálculo. Portanto, use com cuidado.

Thomas
fonte
1
Você tem a mesma idéia básica, portanto, meu voto positivo, mas tente usar a mesma entrada, caso contrário, o resultado diferente é confuso.
Meno Hochschild
@MenoHochschild é a mesma entrada, extraída da atualização em que o OP tem problemas com tempos negativos. ;)
Thomas
1
Bom algoritmo, mas tipo errado (consulte o aviso de isenção de responsabilidade de Thomas). Antes de fazer seu cálculo, você deve converter suas variáveis ​​LocalDateTime em ZonedDateTime usando o fuso horário padrão, por exemplo (ou qualquer fuso horário necessário): ZonedDateTime fromZonedDateTime = fromDateTime.atZone (ZoneId.systemDefault ());
Tristan
2
@ Thomas Seu exemplo também está usando o Java 8 - e a pergunta está marcada como java-8. De fato, seu exemplo é até mesmo usando ChronoUnit:), mas fazendo o trabalho "manualmente".
Eugene Beresovsky
3
@EugeneBeresovsky oh sim, você está certo. Perdi totalmente isso;) - Além disso, você ainda teria que subtrair as unidades maiores do intervalo, pois, por exemplo long minutes = ChronoUnit.MINUTES.between(fromDate, toDate);, retornaria um número maior que 59 por qualquer intervalo de pelo menos 1 hora - e não é isso que o OP deseja. Levando isso em consideração, você não seria capaz de fazer apenas 6 chamadas ChronoUnit#between()e concluir.
Thomas
503

Encontrei a melhor maneira de fazer isso com o ChronoUnit.

long minutes = ChronoUnit.MINUTES.between(fromDate, toDate);
long hours = ChronoUnit.HOURS.between(fromDate, toDate);

Documentação adicional está aqui: https://docs.oracle.com/javase/tutorial/datetime/iso/period.html

satnam
fonte
8
Não vejo uma melhoria real. Comparado com a resposta de Thomas aceita, você substitui tempDateTime.until( toDateTime, ChronoUnit.YEARS)por ChronoUnit.YEARS.between(fromDate, toDate). Mas as linhas adicionais importantes, como tempDateTime.plusYears( years )etc., estão completamente ausentes na sua resposta, de modo que não ajuda o OP. O algoritmo completo é importante!
Meno Hochschild
9
Eu gosto mais disso, pois é mais sucinto e mais legível de leitura. Essa é a melhor maneira de encontrar a diferença entre duas datas.
Somaiah Kumbera
7
@SomaiahKumbera Não, você perde completamente o ponto crítico. O PO não quer uma duração em apenas uma unidade, mas em várias unidades , e, portanto, essa resposta não é de todo uma resposta real. A preocupação do OP simplesmente não é abordada. Por favor, tenha a gentileza de ler novamente a pergunta. (Muitos promotores parecem ter entendido mal a questão).
Meno Hochschild 8/16
125
@MenoHochschild, acho que você é quem perdeu o ponto crítico. O OP obteve sua resposta há mais de um ano. As 36 mil pessoas que estão vendo essa pergunta não se importam com a questão específica do OP. Eles foram liderados aqui pelo google e minha resposta forneceu o que eles estavam procurando - uma solução limpa e simples para obter a diferença entre duas datas.
satnam
10
Eu precisava da diferença de segundos entre dois horários e comecei a implementar minha própria solução. Logo parece complexo e eu peguei no google. A resposta satnam pode não responder à pergunta do OP, mas com certeza me ajudou muito e aposto que muitas outras pessoas como eu.
Julian
43

Aqui está um único exemplo usando Duration e TimeUnit para obter o formato 'hh: mm: ss'.

Duration dur = Duration.between(localDateTimeIni, localDateTimeEnd);
long millis = dur.toMillis();

String.format("%02d:%02d:%02d", 
        TimeUnit.MILLISECONDS.toHours(millis),
        TimeUnit.MILLISECONDS.toMinutes(millis) - 
        TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
        TimeUnit.MILLISECONDS.toSeconds(millis) - 
        TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
Junior Batista
fonte
2
Na verdade, é possível fazê-lo como este: String.format("%02d:%02d:%02d",dur.toHoursPart(), dur.toMinutesPart(), dur.toSecondsPart());. Os métodos de peça fornecem os números certos para criar uma string. Eu acho que é mais legível.
Daantie 13/03/19
Nota lateral ao meu comentário anterior: os métodos de peça estão disponíveis apenas no JDK 9 ou superior.
Daantie 14/03/19
40

Deveria ser mais simples!

Duration.between(startLocalDateTime, endLocalDateTime).toMillis();
Zon
fonte
1
Acredito que essa seja realmente a solução semanticamente correta a partir do Java 8. E antes dessa versão, o JodaTime faz o mesmo.
Vrakfall 24/01/19
9

TL; DR

Duration duration = Duration.between(start, end);
duration = duration.minusDays(duration.toDaysPart()); // essentially "duration (mod 1 day)"
Period period = Period.between(start.toLocalDate(), end.toLocalDate());

e, em seguida, usar os métodos period.getYears(), period.getMonths(), period.getDays(), duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart().


Resposta expandida

Responderei à pergunta original, ou seja, como obter a diferença horária entre dois LocalDateTimesem anos, meses, dias, horas e minutos, de modo que a "soma" (veja a nota abaixo) de todos os valores para as diferentes unidades seja igual ao total diferença temporal e de tal modo que o valor em cada unidade é menor do que o lado maior da unidade, ou seja minutes < 60, hours < 24e assim por diante.

Dado dois LocalDateTimes starte end, por exemplo

LocalDateTime start = LocalDateTime.of(2019, 11, 29, 17, 15);
LocalDateTime end = LocalDateTime.of(2020, 11, 30, 18, 44);

podemos representar o intervalo de tempo absoluto entre os dois com um - Durationtalvez usando Duration.between(start, end). Mas a maior unidade que podemos extrair de um Durationé de dias (como uma unidade temporal equivalente a 24h) - veja a nota abaixo para uma explicação. Para usar unidades maiores (meses, anos), podemos representá-lo Durationcom um par de ( Period, Duration), em que Periodmede a diferença até uma precisão de dias e Durationrepresenta o restante:

Duration duration = Duration.between(start, end);
duration = duration.minusDays(duration.toDaysPart()); // essentially "duration (mod 1 day)"
Period period = Period.between(start.toLocalDate(), end.toLocalDate());

Agora podemos simplesmente usar os métodos definidos Periode Durationextrair as unidades individuais:

System.out.printf("%d years, %d months, %d days, %d hours, %d minutes, %d seconds",
        period.getYears(), period.getMonths(), period.getDays(), duration.toHoursPart(),
        duration.toMinutesPart(), duration.toSecondsPart());
1 years, 0 months, 1 days, 1 hours, 29 minutes, 0 seconds

ou, usando o formato padrão:

System.out.println(period + " + " + duration);
P1Y1D + PT1H29M

Nota sobre anos, meses e dias

Observe que, na java.timeconcepção, "unidades" como "mês" ou "ano" não representam um valor temporal absoluto fixo - elas dependem de data e calendário, como o exemplo a seguir ilustra:

LocalDateTime
        start1 = LocalDateTime.of(2020, 1, 1, 0, 0),
        end1 = LocalDateTime.of(2021, 1, 1, 0, 0),
        start2 = LocalDateTime.of(2021, 1, 1, 0, 0),
        end2 = LocalDateTime.of(2022, 1, 1, 0, 0);
System.out.println(Period.between(start1.toLocalDate(), end1.toLocalDate()));
System.out.println(Duration.between(start1, end1).toDays());
System.out.println(Period.between(start2.toLocalDate(), end2.toLocalDate()));
System.out.println(Duration.between(start2, end2).toDays());
P1Y
366
P1Y
365
Anakhand
fonte
5

Há algum problema no código Tapas Bose e no código Thomas. Se a diferença de tempo for negativa, o array obtém os valores negativos. Por exemplo, se

LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 46, 45);
LocalDateTime fromDateTime = LocalDateTime.of(2014, 9, 9, 7, 46, 45);

retorna 0 anos 0 meses 1 dias -1 horas 0 minutos 0 segundos.

Eu acho que a saída correta é: 0 anos 0 meses 0 dias 23 horas 0 minutos 0 segundos.

Proponho separar as instâncias LocalDateTime nas instâncias LocalDate e LocalTime. Depois disso, podemos obter as instâncias de período e duração do Java 8. A instância Duration é separada no número de dias e no valor do horário do dia (<24h) com a correção subsequente do valor do período. Quando o segundo valor LocalTime está antes do valor firstLocalTime, é necessário reduzir o período por um dia.

Aqui está minha maneira de calcular a diferença LocalDateTime:

private void getChronoUnitForSecondAfterFirst(LocalDateTime firstLocalDateTime, LocalDateTime secondLocalDateTime, long[] chronoUnits) {
    /*Separate LocaldateTime on LocalDate and LocalTime*/
    LocalDate firstLocalDate = firstLocalDateTime.toLocalDate();
    LocalTime firstLocalTime = firstLocalDateTime.toLocalTime();

    LocalDate secondLocalDate = secondLocalDateTime.toLocalDate();
    LocalTime secondLocalTime = secondLocalDateTime.toLocalTime();

    /*Calculate the time difference*/
    Duration duration = Duration.between(firstLocalDateTime, secondLocalDateTime);
    long durationDays = duration.toDays();
    Duration throughoutTheDayDuration = duration.minusDays(durationDays);
    Logger.getLogger(PeriodDuration.class.getName()).log(Level.INFO,
            "Duration is: " + duration + " this is " + durationDays
            + " days and " + throughoutTheDayDuration + " time.");

    Period period = Period.between(firstLocalDate, secondLocalDate);

    /*Correct the date difference*/
    if (secondLocalTime.isBefore(firstLocalTime)) {
        period = period.minusDays(1);
        Logger.getLogger(PeriodDuration.class.getName()).log(Level.INFO,
                "minus 1 day");
    }

    Logger.getLogger(PeriodDuration.class.getName()).log(Level.INFO,
            "Period between " + firstLocalDateTime + " and "
            + secondLocalDateTime + " is: " + period + " and duration is: "
            + throughoutTheDayDuration
            + "\n-----------------------------------------------------------------");

    /*Calculate chrono unit values and  write it in array*/
    chronoUnits[0] = period.getYears();
    chronoUnits[1] = period.getMonths();
    chronoUnits[2] = period.getDays();
    chronoUnits[3] = throughoutTheDayDuration.toHours();
    chronoUnits[4] = throughoutTheDayDuration.toMinutes() % 60;
    chronoUnits[5] = throughoutTheDayDuration.getSeconds() % 60;
}

O método acima pode ser usado para calcular a diferença de qualquer valor local de data e hora, por exemplo:

public long[] getChronoUnits(String firstLocalDateTimeString, String secondLocalDateTimeString) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    LocalDateTime firstLocalDateTime = LocalDateTime.parse(firstLocalDateTimeString, formatter);
    LocalDateTime secondLocalDateTime = LocalDateTime.parse(secondLocalDateTimeString, formatter);

    long[] chronoUnits = new long[6];
    if (secondLocalDateTime.isAfter(firstLocalDateTime)) {
        getChronoUnitForSecondAfterFirst(firstLocalDateTime, secondLocalDateTime, chronoUnits);
    } else {
        getChronoUnitForSecondAfterFirst(secondLocalDateTime, firstLocalDateTime, chronoUnits);
    }
    return chronoUnits;
}

É conveniente escrever um teste de unidade para o método acima (ambos são membros da classe PeriodDuration). Aqui está o código:

@RunWith(Parameterized.class)
public class PeriodDurationTest {

private final String firstLocalDateTimeString;
private final String secondLocalDateTimeString;
private final long[] chronoUnits;

public PeriodDurationTest(String firstLocalDateTimeString, String secondLocalDateTimeString, long[] chronoUnits) {
    this.firstLocalDateTimeString = firstLocalDateTimeString;
    this.secondLocalDateTimeString = secondLocalDateTimeString;
    this.chronoUnits = chronoUnits;
}

@Parameters
public static Collection<Object[]> periodValues() {
    long[] chronoUnits0 = {0, 0, 0, 0, 0, 0};
    long[] chronoUnits1 = {0, 0, 0, 1, 0, 0};
    long[] chronoUnits2 = {0, 0, 0, 23, 0, 0};
    long[] chronoUnits3 = {0, 0, 0, 1, 0, 0};
    long[] chronoUnits4 = {0, 0, 0, 23, 0, 0};
    long[] chronoUnits5 = {0, 0, 1, 23, 0, 0};
    long[] chronoUnits6 = {29, 8, 24, 12, 0, 50};
    long[] chronoUnits7 = {29, 8, 24, 12, 0, 50};
    return Arrays.asList(new Object[][]{
        {"2015-09-09 21:46:44", "2015-09-09 21:46:44", chronoUnits0},
        {"2015-09-09 21:46:44", "2015-09-09 22:46:44", chronoUnits1},
        {"2015-09-09 21:46:44", "2015-09-10 20:46:44", chronoUnits2},
        {"2015-09-09 21:46:44", "2015-09-09 20:46:44", chronoUnits3},
        {"2015-09-10 20:46:44", "2015-09-09 21:46:44", chronoUnits4},
        {"2015-09-11 20:46:44", "2015-09-09 21:46:44", chronoUnits5},
        {"1984-12-16 07:45:55", "2014-09-09 19:46:45", chronoUnits6},
        {"2014-09-09 19:46:45", "1984-12-16 07:45:55", chronoUnits6}
    });
}

@Test
public void testGetChronoUnits() {
    PeriodDuration instance = new PeriodDuration();
    long[] expResult = this.chronoUnits;
    long[] result = instance.getChronoUnits(this.firstLocalDateTimeString, this.secondLocalDateTimeString);
    assertArrayEquals(expResult, result);
}

}

Todos os testes são bem-sucedidos, independentemente do valor do primeiro LocalDateTime ser anterior e para qualquer valor LocalTime.

Gennady Kolomoets
fonte
Não consigo reproduzir sua afirmação de que o código Thomas usando sua entrada acima produz sinais mistos. Minha saída é: "0 anos 0 meses 0 dias 23 horas 0 minutos 0 segundos.". E eu testei agora.
Meno Hochschild
Obrigado pelo comentário. Eu testei completamente o código Thomas, de fato, ele está funcionando corretamente! A mágica é feita por LocalDateTime até o método de correção de unidades de cronômetro. Valores negativos no código Thomas aparecem se o primeiro DateTime for posterior ao segundo. Mas isso pode ser facilmente corrigido, por exemplo, como fiz no código acima. Obrigado novamente.
Gennady Kolomoets
Bem, o código Thomas e minha biblioteca Time4J, usando o mesmo algoritmo para cálculo de durações, podem produzir sinais negativos, mas apenas por toda a duração. Esse é o ponto crucial! O sinal refere-se a toda a duração e, portanto, descreve se o início é posterior ao final e nunca está relacionado a componentes de duração única. Sinais mistos não são possíveis aqui e impediriam essa interpretação do início em relação ao fim (o exemplo contrário é o período de tempo de Joda ou java.time.Periodonde os usuários podem aplicar / produzir esses sinais mistos devido a diferentes designs internos).
Meno Hochschild
5

E a versão do @Thomas no Groovy with leva as unidades desejadas em uma lista em vez de codificar os valores. Essa implementação (que pode ser facilmente transportada para Java - tornei explícita a declaração da função) torna a abordagem de Thomas mais reutilizável.

def fromDateTime = LocalDateTime.of(1968, 6, 14, 0, 13, 0)
def toDateTime = LocalDateTime.now()
def listOfUnits = [
    ChronoUnit.YEARS, ChronoUnit.MONTHS, ChronoUnit.DAYS,
    ChronoUnit.HOURS, ChronoUnit.MINUTES, ChronoUnit.SECONDS,
    ChronoUnit.MILLIS]

println calcDurationInTextualForm(listOfUnits, fromDateTime, toDateTime)    

String calcDurationInTextualForm(List<ChronoUnit> listOfUnits, LocalDateTime ts, LocalDateTime to)
{
    def result = []

    listOfUnits.each { chronoUnit ->
        long amount = ts.until(to, chronoUnit)
        ts = ts.plus(amount, chronoUnit)

        if (amount) {
            result << "$amount ${chronoUnit.toString()}"
        }
    }

    result.join(', ')
}

No momento da redação deste texto, o código acima retorna 47 Years, 8 Months, 9 Days, 22 Hours, 52 Minutes, 7 Seconds, 140 Millis. E, para a entrada @Gennady Kolomoets, o código retorna 23 Hours.

Quando você fornece uma lista de unidades, ela deve ser classificada por tamanho das unidades (maior primeiro):

def listOfUnits = [ChronoUnit.WEEKS, ChronoUnit.DAYS, ChronoUnit.HOURS]
// returns 2495 Weeks, 3 Days, 8 Hours
ChrLipp
fonte
4

Aqui está uma resposta muito simples para sua pergunta. Funciona.

import java.time.*;
import java.util.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

public class MyClass {
public static void main(String args[]) {
    DateTimeFormatter T = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
    Scanner h = new Scanner(System.in);

    System.out.print("Enter date of birth[dd/mm/yyyy hh:mm]: ");
    String b = h.nextLine();

    LocalDateTime bd = LocalDateTime.parse(b,T);
    LocalDateTime cd = LocalDateTime.now();

    long minutes = ChronoUnit.MINUTES.between(bd, cd);
    long hours = ChronoUnit.HOURS.between(bd, cd);

    System.out.print("Age is: "+hours+ " hours, or " +minutes+ " minutes old");
}
}
SavedBeau
fonte
1
Devo mencionar que isso não é exato. tente com isso. diz 1 minuto de diferença. LocalDateTime bd = LocalDateTime.of (2019, 11, 26, 15, 03, 55); LocalDateTime cd = LocalDateTime.of (2019, 11, 26, 15, 04, 45);
precisa
Eu entrei em um horário na noite passada e cheguei Age is: 0 years,0 months, 1 days, -10 hours, -48 minutes old. Eu não acho que isso é o que foi desejado.
Ole VV
@ OleV.V. Corrigido esse problema
SavedBeau
1

Joda-Time

Como muitas das respostas exigiam suporte à API 26 e minha API mínima era 23, resolvi-a pelo código abaixo:

import org.joda.time.Days

LocalDate startDate = Something
LocalDate endDate = Something
// The difference would be exclusive of both dates, 
// so in most of use cases we may need to increment it by 1
Days.daysBetween(startDate, endDate).days
Kushal
fonte
1
O projeto Joda-Time está no modo de manutenção, tendo seu criador Stephen Colebourne criado as classes java.time definidas no JSR 310. A maior parte da funcionalidade java.time é portada para Java 6 e 7 no ThreeTen- Projeto de backport . Mais adaptado para o Android inicial no projeto ThreeTenABP .
Basil Bourque
1

Depois de mais de cinco anos, respondo minha pergunta. Penso que o problema com duração negativa pode ser resolvido com uma simples correção:

LocalDateTime fromDateTime = LocalDateTime.of(2014, 9, 9, 7, 46, 45);
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 46, 45);

Period period = Period.between(fromDateTime.toLocalDate(), toDateTime.toLocalDate());
Duration duration = Duration.between(fromDateTime.toLocalTime(), toDateTime.toLocalTime());

if (duration.isNegative()) {
    period = period.minusDays(1);
    duration = duration.plusDays(1);
}
long seconds = duration.getSeconds();
long hours = seconds / SECONDS_PER_HOUR;
long minutes = ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
long secs = (seconds % SECONDS_PER_MINUTE);
long time[] = {hours, minutes, secs};
System.out.println(period.getYears() + " years "
            + period.getMonths() + " months "
            + period.getDays() + " days "
            + time[0] + " hours "
            + time[1] + " minutes "
            + time[2] + " seconds.");

Nota: O site https://www.epochconverter.com/date-difference agora calcula corretamente a diferença horária.

Obrigado a todos por sua discussão e sugestões.

Gennady Kolomoets
fonte
Obrigado pela resposta. Para as horas e menores você pode se beneficiar da toHours, toMinutese toSecondsmétodos de Duration. Desde o Java 9 ainda mais a partir toMinutesPart()e toSecondsPart(). E não vejo o sentido de agrupar as horas, os minutos e os segundos em uma matriz apenas para eliminá-los novamente. Geralmente uma boa resposta, no entanto.
Ole VV
Depois de mais de cinco anos, respondo minha pergunta. A pergunta foi publicada a partir de uma conta com um nome, título e localidade diferentes, não parece haver muita semelhança? Não que isso tenha alguma importância, apenas imaginando.
Ole VV
"Depois de mais de cinco anos, respondo minha pergunta" Acho que fui o OP :)
Tapas Bose