2010-01-14 110 views
13

¿Cómo puedo agregar dos fechas en Java?Suma dos fechas en Java

Ejemplo: La suma de "2010-01-14 19:16:17" "0000-10-03 01:10:05"
resultaría en "2010-11-17 20:26:22" .

Sé cómo hacerlo usando Calendario y agregando campo por campo.

¿Hay alguna otra forma de sumarlas todas (año/mes/día/hora/minuto/segundo) a la vez?

+11

¿Cómo puede la suma de dos fechas del calendario será de ninguna manera significativa? (Si está intentando agregar un intervalo, esta parece una manera extraña de almacenar los datos.) –

+3

año 0000: una fecha extraña. – Bozho

+5

@Diego: Tome este ejemplo: ¿cuál sería la respuesta al "3 de mayo de 2009" + "23 de julio de 1984"? La pregunta no tiene sentido, ni tampoco la respuesta. – skaffman

Respuesta

25

Si está utilizando el objeto Date, que sólo puede hacer:

Date d1 = ... 
Date d2 = ... 

long sum = d1.getTime() + d2.getTime(); 

Date sumDate = new Date(sum); 

El código utiliza el método .getTime() que devuelve el número de milisegundos desde la época. No hace falta decir que la clase Date tiene muchos problemas y debe evitarse cuando sea posible.

¿Desea sumar otros tipos en su lugar?

Actualización: para Calendar, yo haría lo siguiente (basado en javadocs):

Calendar c1 = ... 
Calendar c2 = ... 
long sum = c1.getTimeInMillis() + c2.getTimeInMillis(); 
Calendar sumCalendar = (Calendar)c1.clone(); 
sumCalendar.setTimeInMillis(sum); 

ACTUALIZACIÓN: Como Steve indicó, esto funciona si la fecha que se presenta aquí se supone que la segunda fecha es con respecto a la época de Java. Si desea comenzar con el año "0", entonces necesita dar cuenta de eso (restando su tiempo de época).

+7

Esto es simplemente incorrecto. La época de Java es 1970. Por lo tanto, usar Date para representar una duración de tiempo (como 0000-00-00 00:01 por un minuto) no funcionará. Solo inténtalo y mira. –

+2

Ejemplo: 1970-00-00 00:00 = 0 mseg, por lo que la adición de 1970-00-00 00:00 a 1970-00-00 00:00 usando su algoritmo produce 1970-00-00 00:00, donde como el OP espera que sea 3940-00-00 00:00. –

+1

Guardo la fecha/hora como larga, así que solo tengo que usar +;) No es necesario convertir a Fecha/Calendario y viceversa. –

9

Como siempre, yo recomendaría Joda para el trabajo de fecha/hora, ya que es mucho más potente e intuitivo.

Puede agregar duraciones y períodos a un objeto DateTime trivialmente. Puede agregar minutos/segundos/meses con la misma facilidad.

Sin embargo, no se puede agregar dos fechas directamente, ya que eso realmente no tiene sentido. Esta es una poderosa ilustración de por qué Joda es una ayuda; te impide hacer cosas que realmente no deberías estar haciendo.

+0

+1, buena explicación. –

+0

No me gustan las características fascistas/paternalistas/comunistas de los lenguajes diseñados para evitar que haga lo que ellos piensan que no debo hacer porque muchas veces necesito hacer cosas que creen que no debo hacer. –

+0

Joda es una biblioteca, no es un idioma. –

3

Quiere hacer getTimeInMillis() en ambos calendarios para que tenga dos valores honestos de long que puede sumar. A continuación, puede tomar la suma y guardarla en un nuevo calendario utilizando el método setTimeInMillis() de ese calendario.

Si desea agregar dos Calendar s como se muestra arriba o dos Date s como se muestra en notnoop, la respuesta depende de usted, por supuesto. El efecto es similar, solo depende de lo que quieras hacer con el resultado. Un Date es más que nada bueno para almacenar y/o convertir a una cadena para imprimir o mostrar, mientras que Calendar te permitirá jugar con los valores de tiempo individuales si así lo deseas.

Como han mencionado otros, está cometiendo algunos errores conceptuales al usar un Date o Calendar, que están destinados a almacenar fechas y horas "reales", p. unos en el siglo 20 o 21, como intervalos, es decir, períodos de tiempo. Las clases en la biblioteca estándar de Java no le dan herramientas realmente útiles para manejar esto, por lo que las clases Joda fueron desarrolladas. Todos los chicos geniales en procesamiento de fecha/hora usan eso; pero, por otro lado, eso implica descargar y administrar una biblioteca de terceros.

3

notnoop answer are definitely correct. Sin embargo, si va a hacer un montón de procesamiento de fechas, horas e intervalos, le sugiero que consulte la clase DateUtils en apache commons lang y en la biblioteca joda-time.

JDK7 contará con un mejor soporte para algunas de las funciones que ofrece joda-time. Solo digo ... podría ser una consideración si tu aplicación hace un uso intensivo de estas cosas.

+1

+1 Recomiendo joda-time. ¡Mi impresión es que la API de Hora/Fecha en Java 7 está básicamente muerta! ¿Sabes cuál es el progreso? – notnoop

+0

Creo que JSR310 está muerto. Java 7, sí. Hay una pregunta sobre SO en algún lugar que recientemente me hizo esta misma pregunta (no tengo el enlace a mano, me temo). –

2

Necesitas definir tu EPOCH. La época de Java (como Unix) es el 1 de enero de 1970 GMT/UTC. Supongo que piensas que estás agregando diez meses, 3 días y algunas horas impares desde el 1 de enero de 0000, pero tienes un offset de época hasta 1970. Las matemáticas pueden no funcionar necesariamente.

Use el calendario o Joda (como se menciona). Si simplemente desea agregar un número de segundos y días (& c), puede añadir dicho número de milisegundos a su primer objeto de fecha.

0

Ocasionalmente también soy culpable de esta práctica, almacenando el intervalo de tiempo en un objeto de fecha y usando getTime() como lo sugiere notnoop.

Funciona. Al contrario de cierta opinión, ciertamente funciona. Simplemente ignoro que el intervalo podría ser representativo de una fecha imprevista. Es una manera rápida y sucia de agregar un intervalo, por ejemplo, [6 años, 6 meses, 6 días, 6 horas, 6 minutos, 6 segundos] a una fecha.

+0

bien ... pero todavía está agregando 6m6d6h6s a 1970, no a 0000. – Xailor

6

¡No sume el tiempo en milisegundos de las dos fechas!

Date d1 = new Date(); 
Date d2 = new Date(); 
Date dTotal = new Date(d1.getTime() + d2.getTime()); 
System.out.println(dTotal); // Incorrect! Misses about 1970 years. 

Sólo clonar el Calendar y añadir las partes de fecha y hora, uno por uno.

Calendar c1 = Calendar.getInstance(); 
Calendar c2 = Calendar.getInstance(); 
Calendar cTotal = (Calendar) c1.clone(); 
cTotal.add(Calendar.YEAR, c2.get(Calendar.YEAR)); 
cTotal.add(Calendar.MONTH, c2.get(Calendar.MONTH) + 1); // Months are zero-based! 
cTotal.add(Calendar.DATE, c2.get(Calendar.DATE)); 
cTotal.add(Calendar.HOUR_OF_DAY, c2.get(Calendar.HOUR_OF_DAY)); 
cTotal.add(Calendar.MINUTE, c2.get(Calendar.MINUTE)); 
cTotal.add(Calendar.SECOND, c2.get(Calendar.SECOND)); 
cTotal.add(Calendar.MILLISECOND, c2.get(Calendar.MILLISECOND)); 
System.out.println(cTotal.getTime()); // Correct! 

No hace falta decirlo, JodaTime es más inteligente y más limpio con esto.

+0

no estoy seguro de si la solución de calendario funciona (a pesar de que OP escribió que sabe cómo hacerlo). El problema con el calendario: no hay año 0 (y falta el tratamiento de los años * negativos * cuando ERA == BC) –

1

Utilice el método de agregar la clase calendario para agregar dos fechas en java.

Calendar calendar=Calendar.getInstance(); 

calendar.add(Calendar.Date,23); 

calendar.add(Calendar.Month,13); 

calendar.add(Calendar.Year,15); 

Al utilizar el método de agregar en la clase de Calendario, podemos agregar día, mes, año a la fecha existente.

click here for complete program.

+1

Tenga en cuenta que [se desaconsejan las respuestas con solo el enlace] (http://meta.stackoverflow.com/tags/ link-only-answers/info), las respuestas SO deberían ser el punto final de una búsqueda de una solución (frente a otra escala más de referencias, que tienden a quedarse obsoletas en el tiempo). Considere agregar una sinopsis independiente aquí, manteniendo el enlace como referencia. – kleopatra

4

tl; dr

LocalDateTime later = LocalDateTime.parse ("2010-01-14T19:16:17").plus(Period.parse ("P10M3D")).plus(Duration.parse ("PT1H10M5S")) ; 

ISO 8601

La representación de un lapso de tiempo utilizando el mismo formato que un momento es la creación de confusión. Un lapso no es en absoluto igual a un momento.

En lugar de utilizar el formato YYYY-MM-DD HH-MM-SS durante un lapso de tiempo, sugiero que utilice el formato ISO 8601 estándar de PnYnMnDTnHnMnS. En este formato, el P marca el comienzo (presumiblemente para "Período") y el T separa la parte años-mes-días de la porción horas-minutos-segundos.

Valores de ejemplo:

  • PT1H30M → Una hora y media horas.
  • P3Y6M4DT12H30M5S → Tres años, seis meses, cuatro días, doce horas, treinta minutos y cinco segundos.
  • P10M3DT1H10M5S → La duración de su duda es de 0000-10-03 01:10:05.

java.time

la pregunta y el otro responde utilizan las clases de fecha y hora viejos molestos ahora anticuadas por el marco java.time incorporado en Java 8 y versiones posteriores. Ver Oracle Tutorial. Gran parte de la funcionalidad de java.time ha sido retransportada a Java 6 & 7 en ThreeTen-Backport y adaptada a Android en ThreeTenABP.

Las clases java.time usan formatos ISO 8601 de forma predeterminada al analizar y generar cadenas que representan valores de fecha y hora.

La pregunta no proporciona ninguna información de zona horaria, así que aquí usamos la clase LocalDateTime. Si conocemos una compensación desde UTC, usaríamos la clase OffsetDateTime, y si aún mejor conociéramos una zona horaria, usaríamos la clase ZonedDateTime.

Los intervalos de tiempo en java.time se dividen entre un par de clases. Los años-meses-días están representados por la clase Period, y las horas-minutos-segundos se manejan por la clase Duration.

Combinando estos tiempos, de hecho podemos realizar operaciones matemáticas de fecha y hora. Aquí agregamos un lapso de tiempo a una fecha de inicio para obtener una fecha-hora resultante. Y lo hacemos en muy pocas líneas de código. El resultado es de hecho el esperado por la Pregunta.

Convertimos las cadenas de entrada al formato canónico ISO 8601 reemplazando el espacio en el medio con un T.

LocalDateTime ldt = LocalDateTime.parse ("2010-01-14 19:16:17".replace (" " , "T")); 
//"0000-10-03 01:10:05" 
Period period = Period.parse ("P10M3D"); 
Duration duration = Duration.parse ("PT1H10M5S"); 
LocalDateTime result = ldt.plus (period).plus (duration); 

Comparar con el resultado esperado en la pregunta.

LocalDateTime expectation = LocalDateTime.parse ("2010-11-17 20:26:22".replace (" " , "T")); 
Boolean isSame = result.equals (expectation); 

Volcar a la consola.

System.out.println ("ldt: " + ldt + " + period: " + period + " + duration: " + duration + " is result: " + result + " compared to expectation: " + expectation + " is the same: " + isSame); 

ldt: 2010-01-14T19: 16: 17 + período: P10M3D + Duración: PT1H10M5S es resultado: 2010-11-17T20: 26: 22 en comparación con la expectativa: 2010-11-17T20: 26:22 es la misma: la verdadera

0

Mi solución para agregar una hora de una fecha:

private Date getMergedDateTime(Date p_date, Date p_time) 
{ 
    SimpleDateFormat sdfDate = new SimpleDateFormat("dd.MM.yyyy"); 
    SimpleDateFormat sdfTime = new SimpleDateFormat("HH:mm"); 

    Date merged = null; 
    try { 
     merged = new SimpleDateFormat("dd.MM.yyyy HH:mm").parse(sdfDate.format(p_date.getTime()) +" " + sdfTime.format(p_time.getTime())); 
    } catch (ParseException e) { 
     e.printStackTrace(); 
    } 

    return merged; 
} 
+1

Creo que está un poco equivocado en eso, el OP desea aumentar los valores de fecha y hora para crear uno nuevo, no tomar la fecha de 1 objeto Fecha y la hora de otro objeto Fecha. Mejore aumentando los ticks si le gusta – Icepickle

+0

Estas clases ahora son heredadas, suplantadas por las clases java.time. Y esta respuesta no responde a la pregunta, como lo señala Icepickle. –