Calculando a diferença entre duas instâncias de data Java


433

Estou usando a java.util.Dateclasse Java no Scala e quero comparar um Dateobjeto e a hora atual. Eu sei que posso calcular o delta usando getTime ():

(new java.util.Date()).getTime() - oldDate.getTime()

No entanto, isso me deixa com um longmilissegundo de representação. Existe alguma maneira mais simples e agradável de obter um delta de tempo?


10
Por que não amor pelo tempo de joda? É praticamente a melhor opção para lidar com datas em java.
Doctor Jones

7
Por favor, verifique minha solução elegante de 2 liners, sem usar o Joda e fornecer o resultado em qualquer TimeUnit em stackoverflow.com/a/10650881/82609
Sebastien Lorber

2
Que vergonha para todos aqueles que recomendam o tempo de Joda e não recomendam uma resposta Java verdadeira ...
Zizouz212

2
@ Zizouz212 Em relação à recomendação do Joda-Time, as antigas classes de data e hora incluídas no Java são ruins, muito ruins, mal projetadas, confusas e problemáticas. Tão ruim que a Joda-Time se tornou extremamente bem-sucedida como substituta. Tão ruim que até a Sun / Oracle desistiu deles e adotou o pacote java.time como parte do Java 8 e posterior. As classes java.time são inspiradas no Joda-Time. Joda-Time e java.time são liderados pelo mesmo homem, Stephen Colbourne . Eu diria: “Que vergonha alguém recomendando o uso de Date, Calendare SimpleDateFormat”.
Basil Bourque

2
Embora o Joda Time tenha sido provavelmente uma boa resposta quando a pergunta foi feita, hoje a melhor resposta para quem pode usar o Java 8 é usar java.time.Periode / ou Duration. Veja a resposta de Basil Bourque abaixo .
Ole VV

Respostas:


198

DateInfelizmente, a API do JDK está terrivelmente quebrada. Eu recomendo usar a biblioteca Joda Time .

Joda Time tem um conceito de tempo Intervalo :

Interval interval = new Interval(oldTime, new Instant());

EDIT: By the way, Joda tem dois conceitos: Intervalpara representar um intervalo de tempo entre dois instantes de tempo (representam o tempo entre 8:00 e 10:00), e umDuration que representa um período de tempo sem os limites de tempo reais (por exemplo, representa duas horas!)

Se você se preocupa apenas com comparações de tempo, a maioria das Dateimplementações (incluindo a do JDK) implementa a Comparableinterface que permite usar oComparable.compareTo()


btw - você quer dizer Comparable.compareTo(), não Comparable.compare().
Scott Morrison

O Joda-Time possui três classes para retratar um período de várias maneiras: Intervalo, Duração e Período. Esta resposta correta discute os dois primeiros. Veja minha resposta para obter informações sobre o período.
Basil Bourque

O Java 8 tem uma nova API de data e hora, como joda.
tbodt

11
O novo java.timepacote no Java 8 é inspirado no Joda-Time, mas não é um substituto imediato. Cada um tem os seus prós e contras. Felizmente, você não precisa escolher entre eles. Use cada um por seus pontos fortes, desde que tenha cuidado com suas importdeclarações. Veja esta outra resposta, por exemplo, de java.time.
Basil Bourque

6
Para sua informação, o projeto Joda-Time agora está no modo de manutenção , com a equipe aconselhando a migração para as classes java.time . Consulte o Tutorial da Oracle .
Basil Bourque

550

Diferença simples (sem lib)

/**
 * Get a diff between two dates
 * @param date1 the oldest date
 * @param date2 the newest date
 * @param timeUnit the unit in which you want the diff
 * @return the diff value, in the provided unit
 */
public static long getDateDiff(Date date1, Date date2, TimeUnit timeUnit) {
    long diffInMillies = date2.getTime() - date1.getTime();
    return timeUnit.convert(diffInMillies,TimeUnit.MILLISECONDS);
}

E então você pode ligar para:

getDateDiff(date1,date2,TimeUnit.MINUTES);

para obter a diferença das 2 datas em minutos.

TimeUnité java.util.concurrent.TimeUnitum enum Java padrão que vai de nanos a dias.


Dif. Legível por humanos (sem lib)

public static Map<TimeUnit,Long> computeDiff(Date date1, Date date2) {

    long diffInMillies = date2.getTime() - date1.getTime();

    //create the list
    List<TimeUnit> units = new ArrayList<TimeUnit>(EnumSet.allOf(TimeUnit.class));
    Collections.reverse(units);

    //create the result map of TimeUnit and difference
    Map<TimeUnit,Long> result = new LinkedHashMap<TimeUnit,Long>();
    long milliesRest = diffInMillies;

    for ( TimeUnit unit : units ) {

        //calculate difference in millisecond 
        long diff = unit.convert(milliesRest,TimeUnit.MILLISECONDS);
        long diffInMilliesForUnit = unit.toMillis(diff);
        milliesRest = milliesRest - diffInMilliesForUnit;

        //put the result in the map
        result.put(unit,diff);
    }

    return result;
}

http://ideone.com/5dXeu6

A saída é algo como Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0}, com as unidades encomendadas.

Você apenas precisa converter esse mapa em uma sequência amigável.


Atenção

Os trechos de código acima calculam uma diferença simples entre 2 instantes. Isso pode causar problemas durante uma mudança de horário de verão, como explicado neste post . Isso significa que, se você calcular a diferença entre datas sem tempo, poderá ter um dia / hora ausente.

Na minha opinião, a diferença de datas é subjetiva, principalmente em dias. Você pode:

  • conte o número de 24 horas decorridas: dia + 1 - dia = 1 dia = 24h

  • conte o número de tempo decorrido, cuidando do horário de verão: dia + 1 - dia = 1 = 24h (mas usando o horário da meia-noite e o horário de verão, pode ser 0 e 23h)

  • conte o número de day switches, o que significa dia + 13h - dia 11h = 1 dia, mesmo que o tempo decorrido seja de apenas 2h (ou 1h se houver horário de verão: p)

Minha resposta é válida se sua definição de data e dia coincidir com o 1º caso

Com o JodaTime

Se você estiver usando o JodaTime, poderá obter o diff por 2 instantes (datas suportadas por milhões de ReadableInstant) com:

Interval interval = new Interval(oldInstant, new Instant());

Mas você também pode obter o diff para datas / horários locais:

// returns 4 because of the leap year of 366 days
new Period(LocalDate.now(), LocalDate.now().plusDays(365*5), PeriodType.years()).getYears() 

// this time it returns 5
new Period(LocalDate.now(), LocalDate.now().plusDays(365*5+1), PeriodType.years()).getYears() 

// And you can also use these static methods
Years.yearsBetween(LocalDate.now(), LocalDate.now().plusDays(365*5)).getYears()

Uau, você realmente pode ensinar novos truques a um cachorro velho! Nunca ouvi falar disso antes, muito útil para traduzir diferenças de datas em strings significativas.
precisa

@SebastienLorber Existe uma maneira no TimeUnit de calcular a diferença assim? "O alarme está definido para 3 dias, 4 horas e 12 minutos a partir de agora".
precisa saber é

coisas brilhantes realmente pouparam muito do meu tempo. Agradeço sua ajuda.
Lyju I Edwinson

Eu desperdicei três dias da minha vida lidando com datas do Java e joguei muito fora e o substituí por isso. Obrigado.
User1091524

Esta é a melhor resposta que eu vi desde que entrei no stackoverflow! : D: D: D
Cold

153
int diffInDays = (int)( (newerDate.getTime() - olderDate.getTime()) 
                 / (1000 * 60 * 60 * 24) )

Observe que isso funciona com datas UTC; portanto, a diferença pode ser um dia de folga se você observar as datas locais. E fazê-lo funcionar corretamente com datas locais requer uma abordagem completamente diferente devido ao horário de verão.


6
Na verdade, isso não funciona corretamente no Android. Existem erros de arredondamento. O exemplo 19 a 21 de maio diz 1 dia porque lança 1,99 a 1. Use a rodada antes de transmitir para int.
Pratik Mandrekar

4
Esta é a melhor e mais simples resposta. Ao calcular uma diferença entre duas datas, os fusos horários locais subtraem um ao outro ... para que a resposta correta (em dobro) seja dada simplesmente por ((dobro) (newer.getTime () - older.getTime ()) / (86.400,0 * 1000,0); ... como um casal, você tem o dia fracionada bem que facilmente podem ser convertidos em HH: mm: ss.
scottb

8
@ scottb: o problema das datas locais é que você pode ter horário de verão, o que significa que alguns dias têm 23 ou 25 horas, potencialmente atrapalhando o resultado.
Michael Borgwardt

1
@ Steve: são 28 para mim ao defini-los como esta nova data (115, 2, 26); (preste atenção ao documento da API para os parâmetros). É possível que você esteja analisando-os usando o formato de data dos EUA e no modo branda, para que 26/03/2015 seja interpretado como o terceiro dia do 26º mês de 2015?
22815 Michael Borgwardt

1
@ Steve: hm, não sei por que obtive um resultado diferente antes, mas agora posso reproduzir seu erro. As chaves no seu código são diferentes da minha resposta, que faz (endDate.getTime() - startDate.getTime())com que seja convertido em intvez do resultado final, e você está recebendo um estouro inteiro.
22615 Michael Borgwardt

54

Usando a estrutura java.time integrada ao Java 8+:

ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime oldDate = now.minusDays(1).minusMinutes(10);
Duration duration = Duration.between(oldDate, now);
System.out.println("ISO-8601: " + duration);
System.out.println("Minutes: " + duration.toMinutes());

Resultado:

ISO-8601: PT24H10M

Minutos: 1450

Para mais informações, consulte o Tutorial Oracle e o padrão ISO 8601 .


5
Isso ou use em Periodvez de Durationpara datas.
Aphex

53

Você precisa definir seu problema mais claramente. Você pode simplesmente pegar o número de milissegundos entre os dois Dateobjetos e dividir pelo número de milissegundos em 24 horas, por exemplo ... mas:

  • Isso não levará em consideração os fusos horários. Date está sempre no UTC
  • Isso não levará em consideração o horário de verão (onde pode haver dias com apenas 23 horas, por exemplo)
  • Mesmo dentro da UTC, quantos dias existem entre 16 de agosto e 23 de agosto? São apenas 27 horas, então isso significa um dia? Ou deveria ser três dias porque cobre três datas?

1
Eu pensei em java.util. A data era apenas um pequeno invólucro em torno de uma representação em milésimos de tempo, interpretada no fuso horário local (padrão). Imprimir uma data me dá uma representação de fuso horário local. Estou confuso aqui?
Adriaan Koster

46

tl; dr

Converta seus java.util.Dateobjetos obsoletos em sua substituição java.time.Instant,. Em seguida, calcule o tempo decorrido como a Duration.

Duration d = 
    Duration.between(                   // Calculate the span of time between two moments as a number of hours, minutes, and seconds.
        myJavaUtilDate.toInstant() ,    // Convert legacy class to modern class by calling new method added to the old class.
        Instant.now()                   // Capture the current moment in UTC. About two and a half hours later in this example.
    )
;

d.toString (): PT2H34M56S

d.toMinutes (): 154

d.toMinutesPart (): 34

Formato ISO 8601: PnYnMnDTnHnMnS

A norma sensata ISO 8601 define uma representação textual concisa de um período de tempo como um número de anos, meses, dias, horas etc. O padrão exige esse período como uma duração . O formato é PnYnMnDTnHnMnSonde os Pmeios "Período", oT separam a parte da data da parte da hora e entre os números são seguidos por uma letra.

Exemplos:

  • P3Y6M4DT12H30M5S
    três anos, seis meses, quatro dias, doze horas, trinta minutos e cinco segundos
  • PT4H30M
    Quatro horas e meia

java.time

O java.time quadro construído em Java 8 e posterior suplanta as velhas problemáticas java.util.Date/ java.util.Calendarclasses. As novas classes são inspiradas no altamente bem - sucedido framework Joda-Time , pretendido como seu sucessor, similar em conceito, mas re-arquitetado. Definido pelo JSR 310 . Prorrogado pelo projeto ThreeTen-Extra . Veja o tutorial .

Momento

A Instantclasse representa um momento na linha do tempo no UTC com uma resolução de nanossegundos (até nove (9) dígitos de uma fração decimal).

Instant instant = Instant.now() ;  // Capture current moment in UTC.

Melhor evitar as classes herdadas, como Date/ Calendar. Mas se você deve operar com código antigo ainda não atualizado para java.time , converta para frente e para trás. Chame novos métodos de conversão adicionados às classes antigas. Para passar de uma java.util.Datepara uma Instant, ligue Date::toInstant.

Instant instant = myJavaUtilDate.toInstant() ;  // Convert from legacy `java.util.Date` class to modern `java.time.Instant` class.

Período de tempo

As classes java.time dividiram essa ideia de representar um período de tempo como um número de anos, meses, dias, horas, minutos, segundos em duas metades:

  • Period por anos, meses, dias
  • Duration por dias, horas, minutos, segundos

Aqui está um exemplo.

ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime now = ZonedDateTime.now ( zoneId );
ZonedDateTime future = now.plusMinutes ( 63 );
Duration duration = Duration.between ( now , future );

Despejar no console.

Ambos Periode Durationusam o padrão ISO 8601 para gerar uma representação String de seu valor.

System.out.println ( "now: " + now + " to future: " + now + " = " + duration );

agora: 2015-11-26T00: 46: 48.016-05: 00 [América / Montreal] para o futuro: 2015-11-26T00: 46: 48.016-05: 00 [América / Montreal] = PT1H3M

O Java 9 inclui métodos para Durationobter a parte dos dias, parte das horas, parte dos minutos e parte dos segundos.

Você pode obter o número total de dias ou horas ou minutos ou segundos ou milissegundos ou nanossegundos em toda a duração.

long totalHours = duration.toHours();

No Java 9, a Durationclasse obtém novos métodos para retornar as várias partes de dias, horas, minutos, segundos, milissegundos / nanossegundos. Chamar os to…Partmétodos: toDaysPart(), toHoursPart()e assim por diante.

ChronoUnit

Se você se importa apenas com uma granularidade de tempo maior e mais simples, como "número de dias decorridos", use a ChronoUnitenumeração.

long daysElapsed = ChronoUnit.DAYS.between( earlier , later );

Outro exemplo.

Instant now = Instant.now();
Instant later = now.plus( Duration.ofHours( 2 ) );

long minutesElapsed = ChronoUnit.MINUTES.between( now , later );

120


Sobre java.time

A estrutura java.time é integrada ao Java 8 e posterior. Essas classes suplantar os velhos problemáticos legados aulas de data e hora, como java.util.Date, Calendar, e SimpleDateFormat.

O projeto Joda-Time , agora em modo de manutenção , aconselha a migração para java.time.

Para saber mais, consulte o Tutorial do Oracle . E procure Stack Overflow para muitos exemplos e explicações. A especificação é JSR 310 .

Onde obter as classes java.time?

  • Java SE 8 e SE 9 e posterior
    • Construídas em.
    • Parte da API Java padrão com uma implementação em pacote configurável.
    • O Java 9 adiciona alguns recursos e correções menores.
  • Java SE 6 e SE 7
    • Grande parte da funcionalidade java.time é portada para Java 6 e 7 no ThreeTen-Backport .
  • Android
    • O ThreeTenABP projeto adapta ThreeTen-Backport (mencionado acima) para o Android especificamente.
    • Consulte Como usar… .

O projeto ThreeTen-Extra estende o java.time com classes adicionais. Este projeto é um campo de prova para possíveis adições futuras ao java.time. Você pode encontrar algumas classes úteis aqui, como Interval, YearWeek, YearQuarter, e mais .


Joda-Time

ATUALIZAÇÃO: O projeto Joda-Time agora está no modo de manutenção , com a equipe aconselhando a migração para o java.time classes . Deixo esta seção intacta para a história.

A biblioteca Joda-Time usa a ISO 8601 para seus padrões. Sua Periodclasse analisa e gera essas seqüências PnYnMnDTnHnMnS.

DateTime now = DateTime.now(); // Caveat: Ignoring the important issue of time zones.
Period period = new Period( now, now.plusHours( 4 ).plusMinutes( 30));
System.out.println( "period: " + period );

Renderiza:

period: PT4H30M

É engraçado que você tenha começado uma parede de texto irrelevante a ser questionada com "tl; dr". A questão não é sobre como obter o carimbo de data / hora de X atrás ou em X unidades de tempo, mas como obter o delta entre duas datas. É isso aí.
Buffalo

@ Buffalo Não entendo o seu comentário. Minha resposta envolve Period, Duratione ChronoUnit, três classes, cujo propósito é determinar o delta entre pontos de tempo. Por favor, indique quais partes do meu "muro de texto" são irrelevantes. E você está incorreto ao dizer que a pergunta solicitou um "delta entre datas": a pergunta solicitou um delta entre Dateobjetos, que são momentos de data e hora, e não "datas", apesar do nome infeliz dessa classe.
Basil Bourque

Não há nada no seu comentário que lide com dois objetos java.util.Date existentes. Tentei usar vários trechos no meu código e não encontrei nada que usasse um objeto java.util.Date.
Buffalo

@ Fairfalo Fair suficiente, boas críticas. Eu adicionei o código na seção "tl; dr" convertendo de um java.util.Datepara um Instant(apenas chame .toInstant). E eu adicionei a Momentseção para explicar. Você mencionou um par de Dateobjetos, mas, na verdade, a Pergunta usa apenas um único Dateobjeto existente e, em seguida, captura o momento atual, então fiz o mesmo. Obrigado pelo feedback! Dica: Desista de usar Date- Essas classes herdadas são realmente uma bagunça terrível.
Basil Bourque


23

Uma alternativa um pouco mais simples:

System.currentTimeMillis() - oldDate.getTime()

Quanto a "melhor": bem, o que exatamente você precisa? O problema de representar durações de tempo como um número de horas e dias etc. é que isso pode levar a imprecisões e expectativas erradas devido à complexidade das datas (por exemplo, os dias podem ter 23 ou 25 horas devido ao horário de verão).


22

O uso da abordagem em milissegundos pode causar problemas em alguns locais.

Vamos considerar, por exemplo, que a diferença entre as duas datas 24/03/2007 e 25/03/2007 deve ser de 1 dia;

No entanto, usando a rota de milissegundos, você receberá 0 dias, se executar isso no Reino Unido!

/** Manual Method - YIELDS INCORRECT RESULTS - DO NOT USE**/  
/* This method is used to find the no of days between the given dates */  
public long calculateDays(Date dateEarly, Date dateLater) {  
   return (dateLater.getTime() - dateEarly.getTime()) / (24 * 60 * 60 * 1000);  
} 

A melhor maneira de implementar isso é usar java.util.Calendar

/** Using Calendar - THE CORRECT WAY**/  
public static long daysBetween(Calendar startDate, Calendar endDate) {  
  Calendar date = (Calendar) startDate.clone();  
  long daysBetween = 0;  
  while (date.before(endDate)) {  
    date.add(Calendar.DAY_OF_MONTH, 1);  
    daysBetween++;  
  }  
  return daysBetween;  
}  

19
Você poderia creditar o autor original desse código e a terceira frase, cuja entrada no blog é datada de 2007 ?
wchargin

Não é um pouco ineficaz?
Gangnus

Não funciona corretamente. daysBetween (novo calendário gregoriano (2014,03,01), novo calendário gregoriano (2014,04,02)); retorna 31, e ele deve retornar 32: timeanddate.com/date/...
marcolopes

5
@marcolopes - Você está errado - porque os meses do calendário são baseados em zero. Tenho certeza de que você quer dizer março / abril, mas o que você está testando é abril / junho, que é 31. Para ser seguro, escreva como -> new GregorianCalendar (2014, Calendar.MARCH, 1) ....
Tio Iroh

@UncleIroh, você está certo! Perdi esse fato importante (os meses do calendário são baseados em zero). Eu tenho que revisar esta questão novamente.
Marcolopes

22

Há muitas maneiras de encontrar a diferença entre datas e horas. Uma das maneiras mais simples que conheço seria:

      Calendar calendar1 = Calendar.getInstance();
      Calendar calendar2 = Calendar.getInstance();
      calendar1.set(2012, 04, 02);
      calendar2.set(2012, 04, 04);
      long milsecs1= calendar1.getTimeInMillis();
      long milsecs2 = calendar2.getTimeInMillis();
      long diff = milsecs2 - milsecs1;
      long dsecs = diff / 1000;
      long dminutes = diff / (60 * 1000);
      long dhours = diff / (60 * 60 * 1000);
      long ddays = diff / (24 * 60 * 60 * 1000);

      System.out.println("Your Day Difference="+ddays);

A declaração de impressão é apenas um exemplo - você pode formatá-la da maneira que desejar.


5
@ manoj kumar bardhan: bem-vindo ao estouro da pilha: como você vê, as perguntas e as respostas têm anos. Sua resposta deve adicionar mais à pergunta / resposta do que as existentes.
Jayan

3
E os dias que têm 23 ou 25 horas devido a uma transição do horário de verão?
Joni

19

Como todas as respostas aqui estão corretas, mas usam java legado ou bibliotecas de terceiros, como joda ou similar, mostrarei outra maneira de usar as novas classes java.time no Java 8 e posterior. Consulte o Tutorial do Oracle .

Use LocalDatee ChronoUnit:

LocalDate d1 = LocalDate.of(2017, 5, 1);
LocalDate d2 = LocalDate.of(2017, 5, 18);

long days = ChronoUnit.DAYS.between(d1, d2);
System.out.println( days );

9

Subtraindo as datas em milissegundos obras (como descrito em outro post), mas você tem de usar HOUR_OF_DAY e não HOUR ao limpar as partes de tempo das datas:

public static final long MSPERDAY = 60 * 60 * 24 * 1000;
...
final Calendar dateStartCal = Calendar.getInstance();
dateStartCal.setTime(dateStart);
dateStartCal.set(Calendar.HOUR_OF_DAY, 0); // Crucial.
dateStartCal.set(Calendar.MINUTE, 0);
dateStartCal.set(Calendar.SECOND, 0);
dateStartCal.set(Calendar.MILLISECOND, 0);
final Calendar dateEndCal = Calendar.getInstance();
dateEndCal.setTime(dateEnd);
dateEndCal.set(Calendar.HOUR_OF_DAY, 0); // Crucial.
dateEndCal.set(Calendar.MINUTE, 0);
dateEndCal.set(Calendar.SECOND, 0);
dateEndCal.set(Calendar.MILLISECOND, 0);
final long dateDifferenceInDays = ( dateStartCal.getTimeInMillis()
                                  - dateEndCal.getTimeInMillis()
                                  ) / MSPERDAY;
if (dateDifferenceInDays > 15) {
    // Do something if difference > 15 days
}

1
Esse é o melhor método para determinar a diferença entre duas datas do calendário, sem sair das bibliotecas padrão. A maioria das outras respostas trata o dia como um período arbitrário de 24 horas. Se os segundos bissextos forem subtraídos em vez de adicionados, o cálculo final poderá ser um por um devido ao truncamento, pois a diferença absoluta poderá ser um pouco menor que um número inteiro de múltiplos de MSPERDAY.
precisa saber é o seguinte

8

Se você não deseja usar o JodaTime ou similar, a melhor solução é provavelmente a seguinte:

final static long MILLIS_PER_DAY = 24 * 3600 * 1000;
long msDiff= date1.getTime() - date2.getTime();
long daysDiff = Math.round(msDiff / ((double)MILLIS_PER_DAY));

O número de ms por dia nem sempre é o mesmo (devido ao horário de verão e segundos bissextos), mas é muito próximo e pelo menos os desvios devido ao horário de verão são cancelados por períodos mais longos. Portanto, dividir e arredondar fornecerá um resultado correto (pelo menos enquanto o calendário local usado não contiver saltos de tempo estranhos que não sejam o horário de verão e pular segundos).

Observe que isso ainda pressupõe isso date1e date2está definido para a mesma hora do dia. Para diferentes horários do dia, você primeiro precisa definir o que significa "diferença de data", como apontado por Jon Skeet.


A questão está em date1.getTime()vs date2.getTime(). Portanto, a diferença de 03/03/2016 para 31/03/2016 computará 27 dias enquanto você deseja 28 dias.
malat 29/03/19

@malat: Desculpe, não posso seguir. Eu apenas tentei - variando de 03/03/2016 a 31/03/2016 com meu código calcula 28 dias. Se calcular algo mais no seu exemplo, considere fazer isso como uma pergunta separada.
sleske

Além disso, você leu minha advertência? "isto ainda pressupõe que date1 e date2 estão definidas para a mesma hora do dia". Você talvez usou diferentes horas do dia em seu teste?
Sleske

Ah, certo ! Eu errei o truque com Math.round()isso parece seguro nos calendários do 'mundo real'. Desculpe pelo barulho.
malat

8

Dê uma olhada no Joda Time , que é uma API de Data / Hora aprimorada para Java e deve funcionar bem com o Scala.


substituído por java.time (JSR-310) no Java 8
malat 29/03

5

Deixe-me mostrar a diferença entre Joda Interval e Days:

DateTime start = new DateTime(2012, 2, 6, 10, 44, 51, 0);
DateTime end = new DateTime(2012, 2, 6, 11, 39, 47, 1);
Interval interval = new Interval(start, end);
Period period = interval.toPeriod();
System.out.println(period.getYears() + " years, " + period.getMonths() + " months, " + period.getWeeks() + " weeks, " + period.getDays() + " days");
System.out.println(period.getHours() + " hours, " + period.getMinutes() + " minutes, " + period.getSeconds() + " seconds ");
//Result is:
//0 years, 0 months, *1 weeks, 1 days*
//0 hours, 54 minutes, 56 seconds 

//Period can set PeriodType,such as PeriodType.yearMonthDay(),PeriodType.yearDayTime()...
Period p = new Period(start, end, PeriodType.yearMonthDayTime());
System.out.println(p.getYears() + " years, " + p.getMonths() + " months, " + p.getWeeks() + " weeks, " + p.getDays() + "days");
System.out.println(p.getHours() + " hours, " + p.getMinutes() + " minutes, " + p.getSeconds() + " seconds ");
//Result is:
//0 years, 0 months, *0 weeks, 8 days*
//0 hours, 54 minutes, 56 seconds 

5

Se você precisar de uma String de retorno formatada como "2 dias 03h 42m 07s", tente o seguinte:

public String fill2(int value)
{
    String ret = String.valueOf(value);

    if (ret.length() < 2)
        ret = "0" + ret;            
    return ret;
}

public String get_duration(Date date1, Date date2)
{                   
    TimeUnit timeUnit = TimeUnit.SECONDS;

    long diffInMilli = date2.getTime() - date1.getTime();
    long s = timeUnit.convert(diffInMilli, TimeUnit.MILLISECONDS);

    long days = s / (24 * 60 * 60);
    long rest = s - (days * 24 * 60 * 60);
    long hrs = rest / (60 * 60);
    long rest1 = rest - (hrs * 60 * 60);
    long min = rest1 / 60;      
    long sec = s % 60;

    String dates = "";
    if (days > 0) dates = days + " Days ";

    dates += fill2((int) hrs) + "h ";
    dates += fill2((int) min) + "m ";
    dates += fill2((int) sec) + "s ";

    return dates;
}

2
Whoa, por que rolar quando Joda-Time fornece a classe Period já escrita e depurada?
Basil Bourque 23/03

8
Por que devo baixar uma biblioteca com um FileSize compactado de 4,1 MB e adicioná-la ao meu projeto, quando preciso apenas de 32 linhas de código ???
Ingo

1
Porque o Joda-Time é como batatas fritas: você não pode comer apenas um. Você estará usando o Joda-Time em todo o lugar. E porque o Joda-Time é um código bem testado e bem usado. E porque o Joda-Time analisa e gera seqüências de duração ISO 8601 padrão que podem ser úteis para serializar ou relatar esses valores. E porque o Joda-Time inclui formatadores para imprimir representações localizadas desses valores.
Basil Bourque

Nem todo o seu código é testado. stdacima é indefinido.
Basil Bourque

@Basil Bourque: Thx pela dica. Eu corrigi a fonte. Este erro veio da tradução para o inglês.
Ingo

5

Nota: startDate e endDates são -> java.util.Date

import org.joda.time.Duration;
import org.joda.time.Interval;
// Use .getTime() unless it is a joda DateTime object
Interval interval = new Interval(startDate.getTime(), endDate.getTime());
Duration period = interval.toDuration();
//gives the number of days elapsed between start 
period.getStandardDays();

e data final

Semelhante a dias, você também pode obter horas, minutos e segundos

period.getStandardHours();
period.getStandardMinutes();
period.getStandardSeconds();

4

Veja o exemplo aqui http://www.roseindia.net/java/beginners/DateDifferent.shtml Este exemplo fornece diferenças em dias, horas, minutos, segundos e milésimos de segundo :).

import java.util.Calendar;
import java.util.Date;

public class DateDifferent {
    public static void main(String[] args) {
        Date date1 = new Date(2009, 01, 10);
        Date date2 = new Date(2009, 07, 01);
        Calendar calendar1 = Calendar.getInstance();
        Calendar calendar2 = Calendar.getInstance();
        calendar1.setTime(date1);
        calendar2.setTime(date2);
        long milliseconds1 = calendar1.getTimeInMillis();
        long milliseconds2 = calendar2.getTimeInMillis();
        long diff = milliseconds2 - milliseconds1;
        long diffSeconds = diff / 1000;
        long diffMinutes = diff / (60 * 1000);
        long diffHours = diff / (60 * 60 * 1000);
        long diffDays = diff / (24 * 60 * 60 * 1000);
        System.out.println("\nThe Date Different Example");
        System.out.println("Time in milliseconds: " + diff + " milliseconds.");
        System.out.println("Time in seconds: " + diffSeconds + " seconds.");
        System.out.println("Time in minutes: " + diffMinutes + " minutes.");
        System.out.println("Time in hours: " + diffHours + " hours.");
        System.out.println("Time in days: " + diffDays + " days.");
    }
}

3
-1 Isso está errado, a menos que as instâncias de Data sejam derivadas dos horários UTC. Veja a resposta de Jon Skeet.
sleske

4

Use o fuso horário GMT para obter uma instância do calendário, defina o horário usando o método set da classe Calendar. O fuso horário GMT tem 0 deslocamento (não muito importante) e o sinalizador de horário de verão está definido como falso.

    final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

    cal.set(Calendar.YEAR, 2011);
    cal.set(Calendar.MONTH, 9);
    cal.set(Calendar.DAY_OF_MONTH, 29);
    cal.set(Calendar.HOUR, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    final Date startDate = cal.getTime();

    cal.set(Calendar.YEAR, 2011);
    cal.set(Calendar.MONTH, 12);
    cal.set(Calendar.DAY_OF_MONTH, 21);
    cal.set(Calendar.HOUR, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    final Date endDate = cal.getTime();

    System.out.println((endDate.getTime() - startDate.getTime()) % (1000l * 60l * 60l * 24l));

Não se esqueça de zerar a parte de milissegundos; caso contrário, é uma boa resposta no contexto de classes antigas java.util.Dateetc. O uso do hack para definir o fuso horário como GMT torna o código insensível aos efeitos do horário de verão.
Meno Hochschild

4

O código a seguir pode fornecer a saída desejada:

String startDate = "Jan 01 2015";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy");
LocalDate date = LocalDate.parse(startDate, formatter);

String currentDate = "Feb 11 2015";
LocalDate date1 = LocalDate.parse(currentDate, formatter);

System.out.println(date1.toEpochDay() - date.toEpochDay());

3
Você pode explicar exatamente o que seu código faz? A pergunta parece estar perguntando sobre um delta de tempo e, à primeira vista, seu código parece retornar um delta de dia?
GHC

4
public static String getDifferenceBtwTime(Date dateTime) {

    long timeDifferenceMilliseconds = new Date().getTime() - dateTime.getTime();
    long diffSeconds = timeDifferenceMilliseconds / 1000;
    long diffMinutes = timeDifferenceMilliseconds / (60 * 1000);
    long diffHours = timeDifferenceMilliseconds / (60 * 60 * 1000);
    long diffDays = timeDifferenceMilliseconds / (60 * 60 * 1000 * 24);
    long diffWeeks = timeDifferenceMilliseconds / (60 * 60 * 1000 * 24 * 7);
    long diffMonths = (long) (timeDifferenceMilliseconds / (60 * 60 * 1000 * 24 * 30.41666666));
    long diffYears = (long)(timeDifferenceMilliseconds / (1000 * 60 * 60 * 24 * 365));

    if (diffSeconds < 1) {
        return "one sec ago";
    } else if (diffMinutes < 1) {
        return diffSeconds + " seconds ago";
    } else if (diffHours < 1) {
        return diffMinutes + " minutes ago";
    } else if (diffDays < 1) {
        return diffHours + " hours ago";
    } else if (diffWeeks < 1) {
        return diffDays + " days ago";
    } else if (diffMonths < 1) {
        return diffWeeks + " weeks ago";
    } else if (diffYears < 12) {
        return diffMonths + " months ago";
    } else {
        return diffYears + " years ago";
    }
}   

3
int daysDiff = (date1.getTime() - date2.getTime()) / MILLIS_PER_DAY;

5
-1 Isso está errado, a menos que as instâncias de Data sejam derivadas dos horários UTC. Veja a resposta de Jon Skeet.
sleske

5
@sleske você não está certo. Ele já perdeu as informações de fuso horário usando Date, portanto, essa comparação é a melhor que pode ser alcançada, dadas as circunstâncias.
Bozho 30/08/10

1
OK, acho que nós dois estamos certos. É verdade que depende de onde a instância Date vem. Ainda assim, é um erro tão comum que deve ser mencionado.
sleske

Quando uso sua solução, ele diz: Tipo incompatível: não é possível converter de longo para int. Eu acho que você também deve adicionar elenco ou estou perdendo alguma coisa?
Ad Infinitum

3

A melhor coisa a fazer é

(Date1-Date2)/86 400 000 

Esse número é o número de milissegundos em um dia.

Uma data e outra data dão a diferença em milissegundos.

Colete a resposta em uma variável dupla .


Sim, porque não? Eu não entendo o ponto da pergunta de algumas maneiras: o OP tem uma diferença em ms ... e há um certo número de ms em um dia (ok com certos ajustes astronômicos uma vez na lua azul, mas o OP não diz que deve ser tão preciso quanto os astrônomos precisam ...)
mike

3

Aqui está uma solução Java 7 correta em O (1) sem nenhuma dependência.

public static int countDaysBetween(Date date1, Date date2) {

    Calendar c1 = removeTime(from(date1));
    Calendar c2 = removeTime(from(date2));

    if (c1.get(YEAR) == c2.get(YEAR)) {

        return Math.abs(c1.get(DAY_OF_YEAR) - c2.get(DAY_OF_YEAR)) + 1;
    }
    // ensure c1 <= c2
    if (c1.get(YEAR) > c2.get(YEAR)) {
        Calendar c = c1;
        c1 = c2;
        c2 = c;
    }
    int y1 = c1.get(YEAR);
    int y2 = c2.get(YEAR);
    int d1 = c1.get(DAY_OF_YEAR);
    int d2 = c2.get(DAY_OF_YEAR);

    return d2 + ((y2 - y1) * 365) - d1 + countLeapYearsBetween(y1, y2) + 1;
}

private static int countLeapYearsBetween(int y1, int y2) {

    if (y1 < 1 || y2 < 1) {
        throw new IllegalArgumentException("Year must be > 0.");
    }
    // ensure y1 <= y2
    if (y1 > y2) {
        int i = y1;
        y1 = y2;
        y2 = i;
    }

    int diff = 0;

    int firstDivisibleBy4 = y1;
    if (firstDivisibleBy4 % 4 != 0) {
        firstDivisibleBy4 += 4 - (y1 % 4);
    }
    diff = y2 - firstDivisibleBy4 - 1;
    int divisibleBy4 = diff < 0 ? 0 : diff / 4 + 1;

    int firstDivisibleBy100 = y1;
    if (firstDivisibleBy100 % 100 != 0) {
        firstDivisibleBy100 += 100 - (firstDivisibleBy100 % 100);
    }
    diff = y2 - firstDivisibleBy100 - 1;
    int divisibleBy100 = diff < 0 ? 0 : diff / 100 + 1;

    int firstDivisibleBy400 = y1;
    if (firstDivisibleBy400 % 400 != 0) {
        firstDivisibleBy400 += 400 - (y1 % 400);
    }
    diff = y2 - firstDivisibleBy400 - 1;
    int divisibleBy400 = diff < 0 ? 0 : diff / 400 + 1;

    return divisibleBy4 - divisibleBy100 + divisibleBy400;
}


public static Calendar from(Date date) {

    Calendar c = Calendar.getInstance();
    c.setTime(date);

    return c;
}


public static Calendar removeTime(Calendar c) {

    c.set(HOUR_OF_DAY, 0);
    c.set(MINUTE, 0);
    c.set(SECOND, 0);
    c.set(MILLISECOND, 0);

    return c;
}

2

Essa é provavelmente a maneira mais direta de fazer isso - talvez porque eu esteja codificando em Java (com suas bibliotecas de datas e horas reconhecidamente desajeitadas) há algum tempo, mas esse código parece "simples e agradável" para mim!

Você está satisfeito com o resultado ser retornado em milissegundos ou faz parte da sua pergunta que você prefere que ele seja retornado em algum formato alternativo?


2

Não está usando a API padrão, não. Você pode rolar sozinho fazendo algo assim:

class Duration {
    private final TimeUnit unit;
    private final long length;
    // ...
}

Ou você pode usar o Joda :

DateTime a = ..., b = ...;
Duration d = new Duration(a, b);

2

Apenas para responder à pergunta inicial:

Coloque o seguinte código em uma função como Long getAge () {}

Date dahora = new Date();
long MillisToYearsByDiv = 1000l *60l * 60l * 24l * 365l;
long javaOffsetInMillis = 1990l * MillisToYearsByDiv;
long realNowInMillis = dahora.getTime() + javaOffsetInMillis;
long realBirthDayInMillis = this.getFechaNac().getTime() + javaOffsetInMillis;
long ageInMillis = realNowInMillis - realBirthDayInMillis;

return ageInMillis / MillisToYearsByDiv;

O mais importante aqui é trabalhar com números longos ao multiplicar e dividir. E, claro, a compensação que o Java aplica no cálculo de datas.

:)


2

Como a pergunta está marcada com Scala,

import scala.concurrent.duration._
val diff = (System.currentTimeMillis() - oldDate.getTime).milliseconds
val diffSeconds = diff.toSeconds
val diffMinutes = diff.toMinutes
val diffHours = diff.toHours
val diffDays = diff.toDays

2

Depois de pesquisar todas as outras respostas, para manter o tipo Java 7 Date, mas seja mais preciso / padrão com a abordagem do Java 8 diff,

public static long daysBetweenDates(Date d1, Date d2) {
    Instant instant1 = d1.toInstant();
    Instant instant2 = d2.toInstant();
    long diff = ChronoUnit.DAYS.between(instant1, instant2);
    return diff;
}

1

tente isto:

int epoch = (int) (new java.text.SimpleDateFormat("MM/dd/yyyy HH:mm:ss").parse("01/01/1970  00:00:00").getTime() / 1000);

você pode editar a string nos parâmetros dos métodos parse ().

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.