Calcular la diferencia entre dos instancias de fecha Java

433

Estoy usando la java.util.Dateclase de Java en Scala y quiero comparar un Dateobjeto y la hora actual. Sé que puedo calcular el delta usando getTime ():

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

Sin embargo, esto solo me deja con una longrepresentación de milisegundos. ¿Hay alguna forma más simple y agradable de obtener un delta de tiempo?

pr1001
fuente
10
¿Por qué no hay amor por el tiempo joda? Es prácticamente la mejor opción si vas a tratar con fechas en Java.
Doctor Jones
77
Verifique mi elegante solución de 2 líneas, sin usar Joda y dando el resultado en cualquier TimeUnit en stackoverflow.com/a/10650881/82609
Sebastien Lorber el
2
Vergüenza para todos los que recomiendan tiempo Joda, y no recomendar una verdadera respuesta de Java ...
Zizouz212
2
@ Zizouz212 Con respecto a recomendar Joda-Time, las antiguas clases de fecha y hora incluidas con Java son malas, muy malas, mal diseñadas, confusas y problemáticas. Tan malo que Joda-Time se convirtió en un gran éxito como su reemplazo. Tan malo que incluso Sun / Oracle los abandonó y adoptó el paquete java.time como parte de Java 8 y versiones posteriores. Las clases java.time están inspiradas en Joda-Time. Tanto Joda-Time como java.time están dirigidos por el mismo hombre, Stephen Colbourne . Yo diría, “que pena por cualquier persona recomendar el uso de Date, Calendary SimpleDateFormat”.
Basil Bourque
2
Si bien Joda Time fue probablemente una buena respuesta cuando se hizo la pregunta, hoy la mejor respuesta para cualquiera que pueda usar Java 8 es usar java.time.Periody / o Duration. Ver la respuesta de Basil Bourque a continuación .
Ole VV

Respuestas:

198

La DateAPI de JDK está horriblemente rota, lamentablemente. Recomiendo usar la biblioteca Joda Time .

Joda Time tiene un concepto de intervalo de tiempo :

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

EDITAR: Por cierto, Joda tiene dos conceptos: Intervalpara representar un intervalo de tiempo entre dos instantes de tiempo (representa el tiempo entre las 8 a.m. y las 10 a.m.), y Durationeso representa un período de tiempo sin los límites de tiempo reales (por ejemplo, ¡representa dos horas!)

Si solo le interesan las comparaciones de tiempo, la mayoría de las Dateimplementaciones (incluida la JDK) implementa una Comparableinterfaz que le permite utilizar elComparable.compareTo()

notnoop
fuente
por cierto, quieres decir que Comparable.compareTo()no Comparable.compare().
Scott Morrison
Joda-Time tiene tres clases para retratar un lapso de tiempo de varias maneras: intervalo, duración y período. Esta respuesta correcta discute estos dos primeros. Vea mi respuesta para obtener información sobre Period.
Basil Bourque
Java 8 tiene una nueva api de fecha y hora como joda.
tbodt
11
El nuevo java.timepaquete en Java 8 está inspirado en Joda-Time, pero no es un reemplazo directo. Cada uno tiene sus ventajas y desventajas. Afortunadamente no tienes que elegir entre ellos. Use cada uno por sus puntos fuertes siempre que tenga cuidado con sus importdeclaraciones. Consulte esta otra respuesta, por ejemplo, java.time.
Basil Bourque
66
Para su información, el proyecto Joda-Time ahora está en modo de mantenimiento , y el equipo aconseja migrar a las clases java.time . Ver Tutorial de Oracle .
Basil Bourque
550

Dif simple (sin 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);
}

Y luego puedes llamar:

getDateDiff(date1,date2,TimeUnit.MINUTES);

para obtener la diferencia de las 2 fechas en la unidad de minutos.

TimeUnites decir java.util.concurrent.TimeUnit, una enumeración estándar de Java que va de nanos a días.


Dif. Legible por humanos (sin 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

La salida es algo así Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0}, con las unidades ordenadas.

Solo tiene que convertir ese mapa en una cadena fácil de usar.


Advertencia

Los fragmentos de código anteriores calculan una diferencia simple entre 2 instantes. Puede causar problemas durante un cambio de horario de verano, como se explica en esta publicación . Esto significa que si calcula la diferencia entre fechas sin hora, es posible que le falte un día / hora.

En mi opinión, la diferencia de fechas es algo subjetiva, especialmente en días. Puedes:

  • cuente la cantidad de tiempo transcurrido de 24 h: día + 1 - día = 1 día = 24 h

  • cuente la cantidad de tiempo transcurrido, cuidando el horario de verano: día + 1 - día = 1 = 24h (pero usando el horario de medianoche y el horario de verano podría ser 0 día y 23h)

  • cuente el número de day switches, lo que significa día + 1 1pm - día 11am = 1 día, incluso si el tiempo transcurrido es solo 2h (o 1h si hay un horario de verano: p)

Mi respuesta es válida si su definición de fecha difiere en los días que coinciden con el primer caso

Con JodaTime

Si está utilizando JodaTime, puede obtener la diferencia durante 2 instantes (Millones respaldados por ReadableInstant) con:

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

Pero también puede obtener la diferencia para las fechas / horas locales:

// 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()
Sebastien Lorber
fuente
¡Guau, realmente puedes enseñarle a un perro viejo nuevos trucos! Nunca he oído hablar de esto antes, muy útil para traducir las diferencias de fechas en cadenas significativas.
Jeremy Goodell
@SebastienLorber ¿Hay alguna manera en TimeUnit para calcular la diferencia de esta manera? "La alarma está configurada para 3 días, 4 horas y 12 minutos a partir de ahora".
likejudo
cosas brillantes realmente me ahorraron mucho tiempo. Aprecio tu ayuda.
Lyju I Edwinson
Perdí 3 días de mi vida lidiando con fechas de Java y simplemente tiré mucho y lo reemplacé por esto. Gracias.
user1091524
¡Esta es la mejor respuesta que he visto desde que entré en stackoverflow! : D: D: D
Frío
153
int diffInDays = (int)( (newerDate.getTime() - olderDate.getTime()) 
                 / (1000 * 60 * 60 * 24) )

Tenga en cuenta que esto funciona con las fechas UTC, por lo que la diferencia puede ser un día libre si mira las fechas locales. Y lograr que funcione correctamente con las fechas locales requiere un enfoque completamente diferente debido al horario de verano.

Michael Borgwardt
fuente
66
En realidad, esto no funciona correctamente en Android. Existen errores de redondeo. El ejemplo del 19 al 21 de mayo dice 1 día porque lanza 1.99 a 1. Use la ronda antes de lanzar a int.
Pratik Mandrekar
44
Esta es la mejor y más simple respuesta. Al calcular una diferencia entre dos fechas, las zonas horarias locales se restan entre sí ... de modo que la respuesta correcta (como doble) se obtiene simplemente por ((double) (newer.getTime () - older.getTime ()) / (86400.0 * 1000.0); ... como doble, también tiene el día fraccional que se puede convertir fácilmente a HH: MM: ss.
scottb
8
@scottb: el problema con las fechas locales es que puede tener el horario de verano, lo que significa que algunos días tienen 23 o 25 horas, lo que puede desordenar el resultado.
Michael Borgwardt
1
@Steve: son 28 para mí al definirlos como esta nueva Fecha (115, 2, 26); (preste atención al documento de API para los parámetros). ¿Es posible que los esté analizando utilizando el formato de fecha de EE. UU. Y en modo indulgente, de modo que el 26/03/2015 se interprete como el tercer día del 26 ° mes de 2015?
Michael Borgwardt
1
@ Steve: hm, no estoy seguro de por qué obtuve un resultado diferente antes, pero ahora puedo reproducir su error. Las llaves en su código son diferentes a las de mi respuesta, lo que hace (endDate.getTime() - startDate.getTime())que se conviertan en intlugar del resultado final, y obtiene un desbordamiento de enteros.
Michael Borgwardt
54

Usando el marco java.time integrado en 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());

Salida:

ISO-8601: PT24H10M

Minutos: 1450

Para obtener más información, consulte el Tutorial de Oracle y el estándar ISO 8601 .

Vitalii Fedorenko
fuente
55
Esto, o usar en Periodlugar de Durationpara fechas.
Aphex
53

Necesita definir su problema más claramente. Usted podría simplemente tomar el número de milisegundos entre los dos Dateobjetos y se dividen por el número de milisegundos en 24 horas, por ejemplo, pero ...:

  • Esto no tendrá en cuenta las zonas horarias: Datesiempre está en UTC
  • Esto no tendrá en cuenta el horario de verano (donde puede haber días que duran solo 23 horas, por ejemplo)
  • Incluso dentro de UTC, ¿cuántos días hay del 16 de agosto a las 11 p.m. al 18 de agosto a las 2 a.m.? Son solo 27 horas, ¿eso significa un día? ¿O deberían ser tres días porque cubre tres fechas?
Jon Skeet
fuente
1
Pensé java.util. La fecha era solo una pequeña envoltura alrededor de una representación de time-millis, interpretada en la zona horaria local (predeterminada). Imprimir una fecha me da una representación de zona horaria local. ¿Estoy confundido aquí?
Adriaan Koster
46

tl; dr

Convertir sus obsoletos java.util.Dateobjetos para su sustitución, java.time.Instant. Luego calcule el tiempo transcurrido 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

El estándar sensible ISO 8601 define una representación textual concisa de un lapso de tiempo como un número de años, meses, días, horas, etc. El estándar llama a dicho lapso una duración . El formato es PnYnMnDTnHnMnSdonde Psignifica "Período", Tsepara la porción de fecha de la porción de tiempo, y en el medio hay números seguidos de una letra.

Ejemplos:

  • P3Y6M4DT12H30M5S
    tres años, seis meses, cuatro días, doce horas, treinta minutos y cinco segundos
  • PT4H30M
    Cuatro horas y media

java.time

El marco java.time integrado en Java 8 y posterior suplanta a las viejas java.util.Date/ java.util.Calendarclases problemáticas . Las nuevas clases están inspiradas en el exitoso marco Joda-Time , pensado como su sucesor, similar en concepto pero rediseñado. Definido por JSR 310 . Ampliado por el proyecto ThreeTen-Extra . Ver el tutorial .

Momento

La Instantclase representa un momento en la línea de tiempo en UTC con una resolución de nanosegundos (hasta nueve (9) dígitos de una fracción decimal).

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

Lo mejor es evitar las clases heredadas como Date/ Calendar. Pero si debe interactuar con el código antiguo que aún no se ha actualizado a java.time , realice la conversión de un lado a otro. Llame a nuevos métodos de conversión agregados a las clases antiguas. Para pasar de una java.util.Datea una Instant, llame Date::toInstant.

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

Lapso de tiempo

Las clases java.time han dividido esta idea de representar un lapso de tiempo como varios años, meses, días, horas, minutos, segundos en dos mitades:

  • Period por años, meses, días
  • Duration por días, horas, minutos, segundos

Aquí hay un ejemplo.

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

Volcado a la consola.

Tanto Periody Durationutilizar el ISO 8601 estándar para la generación de una representación de cadena de su valor.

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

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

Java 9 agrega métodos para Durationobtener la parte de días, parte de horas, parte de minutos y parte de segundos.

Puede obtener el número total de días u horas o minutos o segundos o milisegundos o nanosegundos en toda la Duración.

long totalHours = duration.toHours();

En Java 9, la Durationclase obtiene nuevos métodos para devolver las distintas partes de días, horas, minutos, segundos, milisegundos / nanosegundos. Llamar a los to…Partmétodos: toDaysPart(), toHoursPart()y así sucesivamente.

ChronoUnit

Si solo le importa una mayor granularidad de tiempo más simple, como "número de días transcurridos", use la ChronoUnitenumeración.

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

Otro ejemplo.

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

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

120


Sobre java.time

El marco java.time está integrado en Java 8 y versiones posteriores. Estas clases suplantar la vieja problemáticos heredados clases de fecha y hora como java.util.Date, Calendar, y SimpleDateFormat.

El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a java.time.

Para obtener más información, consulte el Tutorial de Oracle . Y busque Stack Overflow para obtener muchos ejemplos y explicaciones. La especificación es JSR 310 .

¿Dónde obtener las clases java.time?

  • Java SE 8 y SE 9 y posterior
    • Incorporado.
    • Parte de la API Java estándar con una implementación integrada.
    • Java 9 agrega algunas características menores y correcciones.
  • Java SE 6 y SE 7
    • Gran parte de la funcionalidad java.time se transfiere a Java 6 y 7 en ThreeTen-Backport .
  • Androide

El proyecto ThreeTen-Extra extiende java.time con clases adicionales. Este proyecto es un campo de pruebas para posibles adiciones futuras a java.time. Usted puede encontrar algunas clases útiles aquí, como Interval, YearWeek, YearQuarter, y más .


Joda-Time

ACTUALIZACIÓN: El proyecto Joda-Time ahora está en modo de mantenimiento , con el equipo que aconseja la migración a las clases java.time . Dejo esta sección intacta para la historia.

La biblioteca Joda-Time utiliza ISO 8601 para sus valores predeterminados. Su Periodclase analiza y genera estas cadenas 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 );

Renders:

period: PT4H30M
Albahaca Bourque
fuente
Es curioso que hayas comenzado un muro de texto irrelevante para cuestionar con "tl; dr". La pregunta no es cómo obtener la marca de tiempo de X hace o en X unidades de tiempo, sino cómo obtener el delta entre dos fechas. Eso es.
Buffalo
@Buffalo No entiendo tu comentario. Mi respuesta implica Period, Durationy ChronoUnit, tres clases cuya finalidad es determinar el delta entre los puntos de tiempo. Indique qué partes de mi "muro de texto" son irrelevantes. Y es incorrecto al decir que la Pregunta solicitó un "delta entre fechas": la Pregunta solicitó un delta entre Dateobjetos, que son momentos de fecha y hora, no "fechas" a pesar del desafortunado nombre de esa clase.
Basil Bourque
No hay nada en su comentario que maneje dos objetos java.util.Date existentes. Intenté usar varios fragmentos en mi código y no encontré nada que use un objeto java.util.Date.
Buffalo
@Buffalo Bastante justo, buena crítica. Agregué código en la sección "tl; dr" convirtiendo de a java.util.Datea an Instant(solo llame .toInstant). Y agregué la Momentsección para explicar. Usted mencionó un par de Dateobjetos, pero en realidad la Pregunta usa solo un Dateobjeto existente y luego captura el momento actual, así que hice lo mismo. ¡Gracias por la respuesta! Consejo: Renunciar al uso Date: esas clases heredadas son realmente un desastre horrible.
Basil Bourque
23

Una alternativa un poco más simple:

System.currentTimeMillis() - oldDate.getTime()

En cuanto a "más agradable": bueno, ¿qué necesitas exactamente? El problema con la representación de las duraciones de tiempo como un número de horas y días, etc. es que puede conducir a imprecisiones y expectativas incorrectas debido a la complejidad de las fechas (por ejemplo, los días pueden tener 23 o 25 horas debido al horario de verano).

Michael Borgwardt
fuente
22

El uso del enfoque de milisegundos puede causar problemas en algunas configuraciones regionales.

Tomemos, por ejemplo, la diferencia entre las dos fechas 24/03/2007 y 25/03/2007 debería ser 1 día;

Sin embargo, con la ruta de milisegundos, ¡obtendrá 0 días si ejecuta esto en el 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);  
} 

La mejor manera de implementar esto es 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;  
}  
zasadnyy
fuente
19
¿Podría dar crédito al autor original de este código y la tercera oración, cuya entrada de blog data de 2007 ?
wchargin
¿No es un poco ineficaz?
Gangnus
No funciona correctamente daysBetween (nuevo calendario gregoriano (2014,03,01), nuevo calendario gregoriano (2014,04,02))); devuelve 31, y debería devolver 32: timeanddate.com/date/…
marcolopes
55
@marcolopes: te equivocas, porque los meses naturales están basados ​​en cero. Estoy seguro de que quieres decir marzo / abril, pero lo que estás probando es abril / junio, que es 31. Para estar seguro, escríbelo como -> new GregorianCalendar (2014, Calendar.MARCH, 1) ....
Tío Iroh
@UncleIroh, tienes razón! Extrañé ese hecho importante (los meses calendario están basados ​​en cero). Tengo que revisar esta pregunta nuevamente.
marcolopes
22

Hay muchas maneras de encontrar la diferencia entre fechas y horas. Una de las formas más simples que conozco sería:

      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);

La declaración de impresión es solo un ejemplo: puede formatearla de la manera que desee.

JDGuide
fuente
55
@ manoj kumar bardhan: bienvenido al desbordamiento de pila: como ve, la pregunta y las respuestas tienen años. Su respuesta debería agregar más a la Pregunta / Respuesta que las existentes.
Jayan
3
¿Qué pasa con los días que tienen 23 o 25 horas debido a una transición DST?
Joni
19

Dado que todas las respuestas aquí son correctas, pero usan bibliotecas heredadas de Java o de terceros como joda o similar, simplemente dejaré caer otra forma usando nuevas clases java.time en Java 8 y posteriores. Vea el tutorial de Oracle .

Uso LocalDatey 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 );
ΦXocę 웃 Пepeúpa ツ
fuente
9

Restando las fechas en milisegundos obras (como se describe en otro post), pero usted tiene que utilizar HOUR_OF_DAY y no por hora cuando la limpieza de las partes de la hora de fechas:

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
}
Malcolm Boekhoff
fuente
1
Este es el mejor método para determinar la diferencia entre dos fechas de calendario, sin salir de las bibliotecas estándar. La mayoría de las otras respuestas tratan un día como un período arbitrario de 24 horas. Si alguna vez se restasen los segundos bisiestos en lugar de sumarlos, el cálculo final podría ser de uno por truncamiento, ya que la diferencia absoluta podría ser ligeramente menor que un número entero de múltiplos de MSPERDAY.
JulianSymes
8

Si no desea utilizar JodaTime o similar, la mejor solución es probablemente esta:

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

El número de ms por día no siempre es el mismo (debido al horario de verano y los segundos bisiestos), pero está muy cerca, y al menos las desviaciones debidas al horario de verano se cancelan durante períodos más largos. Por lo tanto, dividir y luego redondear dará un resultado correcto (al menos siempre que el calendario local utilizado no contenga saltos de tiempo extraños que no sean DST y segundos intercalares).

Tenga en cuenta que esto todavía asume eso date1y date2está configurado a la misma hora del día. Para diferentes momentos del día, primero debe definir qué significa "diferencia de fecha", como lo señaló Jon Skeet.

sleske
fuente
La cuestión está en date1.getTime()contra date2.getTime(). Por lo tanto, diferenciar 2016-03-03 a 2016-03-31 calculará 27 días, mientras que usted querría 28 días.
malat
@malat: Lo siento, no puedo seguir. Lo acabo de probar: diferiendo el 03-03-2016 al 31-03-2016 con mi código calcula 28 días. Si calcula algo más en su ejemplo, considere hacer eso como una pregunta separada.
sleske
Además, ¿leíste mi advertencia? "esto todavía supone que date1 y date2 están configuradas a la misma hora del día". ¿Usó quizás diferentes momentos del día en su prueba?
sleske
Ah bien ! Me perdí el truco Math.round(), eso parece seguro en los calendarios del "mundo real". Perdón por el ruido.
malat
8

Eche un vistazo a Joda Time , que es una API de fecha / hora mejorada para Java y debería funcionar bien con Scala.

Rob H
fuente
reemplazado por java.time (JSR-310) en Java 8
malat
5

Permítanme mostrar la diferencia entre Joda Interval y 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 
usuario674158
fuente
5

Si necesita una cadena de retorno con formato como "2 días 03h 42m 07s", intente esto:

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;
}
Ingo
fuente
2
Whoa, ¿por qué rodar el tuyo cuando Joda-Time proporciona la clase Period ya escrita y depurada?
Basil Bourque
8
¿Por qué debería descargar una biblioteca con un tamaño de archivo comprimido de 4,1 MB y agregarla a mi proyecto, cuando solo necesito 32 líneas de código?
Ingo
1
Porque Joda-Time es como las papas fritas: no puedes comer solo una. Usarás Joda-Time por todas partes. Y porque Joda-Time es un código bien probado y usado. Y porque Joda-Time analiza y genera cadenas de duración ISO 8601 estándar que pueden ser útiles para serializar o informar estos valores. Y porque Joda-Time incluye formateadores para imprimir representaciones localizadas de estos valores.
Basil Bourque
No se prueba todo su código. stdlo anterior no está definido.
Basil Bourque
@Basil Bourque: gracias por la pista. He centrado la fuente. Este error vino de la traducción al inglés.
Ingo
5

Nota: startDate y endDates son -> 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();

y fecha de finalización

Similar a los días, también puede obtener horas, minutos y segundos.

period.getStandardHours();
period.getStandardMinutes();
period.getStandardSeconds();
Shravan Ramamurthy
fuente
4

Consulte el ejemplo aquí http://www.roseindia.net/java/beginners/DateDifferent.shtml Este ejemplo le brinda la diferencia en días, horas, minutos, segundos y milisegundos :).

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.");
    }
}
YoK
fuente
3
-1 Eso está mal a menos que las instancias de Fecha se derivaron de tiempos UTC. Ver la respuesta de Jon Skeet.
sleske
4

Use la zona horaria GMT para obtener una instancia del Calendario, establezca la hora utilizando el método establecido de la clase Calendario. La zona horaria GMT tiene un desplazamiento de 0 (no realmente importante) y el indicador de horario de verano está establecido en 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));
Michal
fuente
No olvide poner a cero la parte de milisegundos; de lo contrario, es una buena respuesta en el contexto de las clases antiguas, java.util.Dateetc. El uso del truco para establecer la zona horaria en GMT hace que el código sea insensible a los efectos del horario de verano.
Meno Hochschild
4

El siguiente código puede darle el resultado deseado:

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());
Vishal Ganjare
fuente
3
¿Puedes explicar exactamente qué hace tu código? La pregunta parece ser acerca de un delta de tiempo y, a primera vista, ¿parece que su código devuelve un día delta?
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";
    }
}   
Parth Solanki
fuente
3
int daysDiff = (date1.getTime() - date2.getTime()) / MILLIS_PER_DAY;
Bozho
fuente
55
-1 Eso está mal a menos que las instancias de Fecha se derivaron de tiempos UTC. Ver la respuesta de Jon Skeet.
sleske
55
@sleske no tienes razón. Ya ha perdido la información de la zona horaria al usarla Date, por lo que esta comparación es la mejor que se puede lograr dadas las circunstancias.
Bozho
1
OK, supongo que ambos tenemos razón. Es cierto que depende de dónde provenga la instancia de Date. Aún así, es un error tan común que debería mencionarse.
sleske
Cuando uso su solución, dice: No coinciden los tipos: no se puede convertir de largo a int. Creo que también deberías agregar casting o ¿me estoy perdiendo algo?
Ad Infinitum
3

Lo mejor que puedes hacer es

(Date1-Date2)/86 400 000 

Ese número es el número de milisegundos en un día.

Una fecha-otra fecha te da la diferencia en milisegundos.

Recoge la respuesta en una variable doble .

Revanth Kumar
fuente
¿Si por qué no? No entiendo el punto de la pregunta de alguna manera: OP tiene una diferencia en ms ... y hay una cierta cantidad de ms en un día (OK con ciertos ajustes astronómicos una vez en una luna azul, pero el OP no no digas que debe ser tan preciso como los astrónomos lo necesitan ...)
Mike rodent
3

Aquí hay una solución correcta de Java 7 en O (1) sin ninguna dependencia.

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;
}
suxumuxu
fuente
2

Esa es probablemente la forma más sencilla de hacerlo, tal vez porque he estado codificando en Java (con sus bibliotecas de fecha y hora ciertamente torpes) durante un tiempo, ¡pero ese código me parece "simple y agradable"!

¿Está satisfecho con el resultado que se devuelve en milisegundos, o es parte de su pregunta que preferiría que se devuelva en algún formato alternativo?

Andrzej Doyle
fuente
2

No utiliza la API estándar, no. Puedes rodar el tuyo haciendo algo como esto:

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

O puedes usar Joda :

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

Solo para responder la pregunta inicial:

Ponga el siguiente código en una función 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;

Lo más importante aquí es trabajar con números largos al multiplicar y dividir. Y, por supuesto, el desplazamiento que aplica Java en su cálculo de fechas.

:)

MugiWara No Carlos
fuente
2

Como la pregunta está etiquetada con 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
VasiliNovikov
fuente
2

Después de leer todas las otras respuestas, para mantener el tipo de fecha de Java 7 pero ser más preciso / estándar con el enfoque de 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;
}
gen b.
fuente
1

prueba esto:

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

Puede editar la cadena en el parámetro parse ().

sabbibJAVA
fuente