2010-03-25 16 views
185

necesito para comparar dos Date s (por ejemplo date1 y date2) y llegar a un boolean sameDay lo cual es cierto de los dos Date s comparten el mismo día y falso si no lo sonjava.util.Dates para ver si están en el mismo día

¿Cómo puedo hacer esto? Parece que hay un torbellino de confusión aquí ... y me gustaría evitar tirar de otras dependencias más allá del JDK si es posible.

para aclarar: si date1 y date2 comparten el mismo año, mes y día, a continuación, sameDay es cierto, de lo contrario es falso. Me doy cuenta de que esto requiere conocimiento de una zona horaria ... sería agradable pasar en una zona horaria, pero puedo vivir con GMT o con la hora local, siempre que sepa cuál es el comportamiento.

de nuevo, para aclarar:

date1 = 2008 Jun 03 12:56:03 
date2 = 2008 Jun 03 12:59:44 
    => sameDate = true 

date1 = 2009 Jun 03 12:56:03 
date2 = 2008 Jun 03 12:59:44 
    => sameDate = false 

date1 = 2008 Aug 03 12:00:00 
date2 = 2008 Jun 03 12:00:00 
    => sameDate = false 
+0

sólo para aclarar - quieres saber si dos objetos Date caen en el mismo día de la semana? –

+0

¿Desea comparar la fecha completa (día, mes, año) o solo el día del mes? – XpiritO

+1

@Rob: no, el mismo día/mes/año ... Lo aclararé. –

Respuesta

319
Calendar cal1 = Calendar.getInstance(); 
Calendar cal2 = Calendar.getInstance(); 
cal1.setTime(date1); 
cal2.setTime(date2); 
boolean sameDay = cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && 
        cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR); 

Tenga en cuenta que "el mismo día" no es tan simple un concepto como suena cuando diferentes zonas horarias pueden estar involucrados. El código anterior para ambas fechas calculará el día relativo a la zona horaria utilizada por la computadora en la que se está ejecutando. Si esto no es lo que necesita, debe pasar la (s) zona (s) horaria (s) correspondiente (s) a las llamadas Calendar.getInstance(), después de que haya decidido qué quiere decir exactamente con "el mismo día".

Y sí, el LocalDate de Joda Time lo haría todo mucho más limpio y fácil (aunque las mismas dificultades que implican las zonas horarias estarían presentes).

+0

Gracias, parece que va a hacer lo que quiero.En mi caso, estoy comparando fechas sucesivas en una serie, por lo que parece que podría usar instancias de Calendar en lugar de instancias de Date en mi serie. –

+1

@ Jason Eso puede ser o no una buena idea. El principal problema con Calendar es que es una clase muy pesada con mucho estado interno, parte del cual se usa en su implementación equals(). Si no copias las fechas para la igualdad y no las pones en HashMaps, estarás bien. –

+0

genial, gracias, solo estoy usando la lógica compare-current-and-previous-day que se pregunta aquí. las funciones "igual" y "código hash" nunca deberían ser llamadas. –

128

Puedo utilizar los "bienes comunes de Apache Lang" paquete para hacer esto (es decir org.apache.commons.lang.time.DateUtils)

boolean samedate = DateUtils.isSameDay(date1, date2); //Takes either Calendar or Date objects 
+0

Esto usa una dependencia externa ... pero es bueno saberlo para el futuro. –

+13

Solo copie el código fuente y llámelo un día :) –

+7

+1 para usar apache.common.lang – Sorter

281

¿Qué tal:

SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd"); 
return fmt.format(date1).equals(fmt.format(date2)); 

También puede establezca la zona horaria en SimpleDateFormat, si es necesario.

+2

(en realidad estoy usando SimpleDateFormat de todos modos en mi caso, por lo que parece algo apropiado.) –

+4

Estoy realmente sorprendido de ver esto, pero incluso desde el punto de vista del rendimiento, este método 'SimpleDateFormat' es en realidad más rápido que el otro mencionado aquí usando' Calendar's. En promedio, toma la mitad del tiempo que el método 'Calendario '. (Al menos en mi sistema). ¡Prestigio! –

+0

La mayor parte del costo de esta respuesta se encuentra en la creación de SimpleDateFormat. Ponlo en un campo threadLocal en un singleton si quieres un mejor rendimiento. – Thierry

17

Puede evitar dependencias externas y el impacto en el rendimiento de la utilización de Calendario mediante el cálculo de la Julian Day Number para cada una de las fechas y luego comparar estas:

public static boolean isSameDay(Date date1, Date date2) { 

    // Strip out the time part of each date. 
    long julianDayNumber1 = date1.getTime()/MILLIS_PER_DAY; 
    long julianDayNumber2 = date2.getTime()/MILLIS_PER_DAY; 

    // If they now are equal then it is the same day. 
    return julianDayNumber1 == julianDayNumber2; 
} 
+2

Pero ten cuidado de que esto [no tenga en cuenta] (http://www.xmission.com/~goodhill/dates/deltaDates.html) cambios en la duración del día debido a los ahorros de luz diurna. Pero luego, las 'fechas 'directas no encapsulan la noción de zonas horarias, por lo que no hay forma de arreglar esto de manera no arbitraria. – AntoineJ

+2

Esta es, por cierto, la solución más rápida, muchas gracias, exactamente lo que estaba buscando; ya que tengo que verificar muchas fechas ... – Ridcully

+1

Nitpick: date1.getTime() no devuelve el número del día juliano, pero milisegundos desde 1970-01-01. Gran diferencia. –

-4

se puede aplicar la misma lógica que la solución SimpleDateFormat sin depender de SimpleDateFormat

date1.getFullYear()*10000 + date1.getMonth()*100 + date1.getDate() == 
date2.getFullYear()*10000 + date2.getMonth()*100 + date2.getDate() 
+6

Estos métodos están en desuso en java.util.Date. Deberías usar Calendar para hacer esto. También es getYear, not getFullYear – Kris

1

, además de la solución Binil Thomas

public static boolean isOnSameDay(Timestamp... dates) { 
    SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd"); 
    String date1 = fmt.format(dates[0]); 
    for (Timestamp date : dates) { 
     if (!fmt.format(date).equals(date1)) { 
      return false; 
     } 
    } 
    return true; 
} 

uso

isOnSameDay(date1,date2,date3 ...); 
//or 
    isOnSameDay(mydates); 
0
public static boolean validSearchRange(String start, String end){ 
    SimpleDateFormat dateFormat = new SimpleDateFormat(clientDateFormat); 
    try { 
     Date start_date = dateFormat.parse(start); 
     Date end_date = dateFormat.parse(end); 
     return !start_date.after(end_date); 
    } catch (ParseException e) { 
     e.printStackTrace(); 
    } 
    return false; 
} 
14

Joda-Time

En cuanto a la adición de una dependencia, me temo que el java.util.Date & .calendar realmente son tan malos que el primero que hago a cualquier proyecto nuevo es agregar la biblioteca Joda-Time. En Java 8 puedes usar el nuevo paquete java.time, inspirado en Joda-Time.

El núcleo de Joda-Time es la clase DateTime. A diferencia de java.util.Date, entiende su zona horaria asignada (DateTimeZone). Al convertir desde j.u.Date, asigne una zona.

DateTimeZone zone = DateTimeZone.forID("America/Montreal"); 
DateTime dateTimeQuébec = new DateTime(date , zone); 

LocalDate

Una forma de verificar si dos pares fecha-hora de la tierra en la misma fecha es la de convertir a LocalDate objetos.

Esa conversión depende de la zona horaria asignada. Para comparar objetos LocalDate, deben haberse convertido con la misma zona.

Aquí hay un pequeño método de utilidad.

static public Boolean sameDate (DateTime dt1 , DateTime dt2) 
{ 
    LocalDate ld1 = new LocalDate(dt1); 
    // LocalDate determination depends on the time zone. 
    // So be sure the date-time values are adjusted to the same time zone. 
    LocalDate ld2 = new LocalDate(dt2.withZone(dt1.getZone())); 
    Boolean match = ld1.equals(ld2); 
    return match; 
} 

Mejor sería otro argumento, que especifica la zona horaria en lugar de asumir zona horaria del primer objeto DateTime se debe utilizar.

static public Boolean sameDate (DateTimeZone zone , DateTime dt1 , DateTime dt2) 
{ 
    LocalDate ld1 = new LocalDate(dt1.withZone(zone)); 
    // LocalDate determination depends on the time zone. 
    // So be sure the date-time values are adjusted to the same time zone. 
    LocalDate ld2 = new LocalDate(dt2.withZone(zone)); 
    return ld1.equals(ld2); 
} 

Cadena Representación

Otro enfoque es crear una cadena que representa la parte de fecha de cada fecha y hora, y luego comparar cadenas.

Nuevamente, la zona horaria asignada es crucial.

DateTimeFormatter formatter = ISODateTimeFormat.date(); // Static method. 
String s1 = formatter.print(dateTime1); 
String s2 = formatter.print(dateTime2.withZone(dt1.getZone()) ); 
Boolean match = s1.equals(s2); 
return match; 

espacio de tiempo

La solución generalizada es definir un espacio de tiempo, a continuación, preguntar si el lapso contiene su objetivo. Este código de ejemplo está en Joda-Time 2.4. Tenga en cuenta que las clases relacionadas con "medianoche" están en desuso. En su lugar, use el método withTimeAtStartOfDay. Joda-Time ofrece tres clases para representar un lapso de tiempo de varias maneras: intervalo, período y duración.

Usando el enfoque "Medio abierto" donde el inicio del tramo es inclusivo y el final exclusivo.

La zona horaria del destino puede ser diferente a la zona horaria del intervalo.

DateTimeZone timeZone = DateTimeZone.forID("Europe/Paris"); 
DateTime target = new DateTime(2012, 3, 4, 5, 6, 7, timeZone); 
DateTime start = DateTime.now(timeZone).withTimeAtStartOfDay(); 
DateTime stop = start.plusDays(1).withTimeAtStartOfDay(); 
Interval interval = new Interval(start, stop); 
boolean containsTarget = interval.contains(target); 

java.time

Java 8 y posterior viene con el marco java.time. Inspirado por Joda-Time, definido por JSR 310, y extendido por el proyecto ThreeTen-Extra. Ver Tutorial.

Los fabricantes de Joda-Time nos han indicado a todos que pasen a java.time tan pronto como sea conveniente. Mientras tanto, Joda-Time continúa como un proyecto activamente mantenido. Pero espere que el trabajo futuro ocurra solo en java.time y ThreeTen-Extra en lugar de Joda-Time.

Para resumir java.time en pocas palabras ... Un Instant es un momento en la línea de tiempo en UTC. Aplique una zona horaria (ZoneId) para obtener un objeto ZonedDateTime. Para salir de la línea de tiempo, para obtener la vaga idea indefinida de una fecha y hora, use las clases "locales": LocalDateTime, LocalDate, LocalTime.

La lógica discutida en la sección Joda-Time de esta respuesta se aplica a java.time.

La antigua clase java.util.Date tiene un nuevo método toInstant para la conversión a java.time.

Instant instant = yourJavaUtilDate.toInstant(); // Convert into java.time type. 

La determinación de una fecha requiere una zona horaria.

ZoneId zoneId = ZoneId.of("America/Montreal"); 

Aplicamos ese objeto de zona horaria a la Instant para obtener un ZonedDateTime. De eso extraemos un valor solo de fecha (a LocalDate) ya que nuestro objetivo es comparar fechas (no horas, minutos, etc.).

ZonedDateTime zdt1 = ZonedDateTime.ofInstant(instant , zoneId); 
LocalDate localDate1 = LocalDate.from(zdt1); 

hacer lo mismo con la segunda java.util.Date objeto que necesitamos para la comparación. Usaré el momento actual en su lugar.

ZonedDateTime zdt2 = ZonedDateTime.now(zoneId); 
LocalDate localDate2 = LocalDate.from(zdt2); 

utilizan el método especial isEqual para poner a prueba para el mismo valor de fecha.

Boolean sameDate = localDate1.isEqual(localDate2); 
+0

java.time: O puede hacer 'LocalDate localDate = LocalDate.fromDateFields (yourJavaUtilDate);' – CyberMew

+1

@CyberMew Er? No hay 'fromDateFields()' en [mi clase 'LocalDate'] (http://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html). –

+1

Lo siento, debería haber sido más claro. El comentario es relevante para la clase Joda-Time [LocalDate] (http://joda-time.sourceforge.net/apidocs/org/joda/time/LocalDate.html). – CyberMew

3

Java 8

Si está utilizando Java 8 en su proyecto y comparar java.sql.Timestamp, podría utilizar la clase LocalDate:

sameDate = date1.toLocalDateTime().toLocalDate().equals(date2.toLocalDateTime().toLocalDate()); 

Si está utilizando java.util.Date, tienen una mira la respuesta de Istvan que es menos ambigua.

+0

Usar Java 8 es una buena idea. ¿Estás asumiendo que 'date1' y' date2' son 'java.sql.Timestamp'? De acuerdo con la pregunta que son 'Fecha', yo entendería' java.util.Date'. Además, su código utiliza la configuración de zona horaria de la computadora, que para muchos fines estará bien; Aún así, preferiría hacer explícito este hecho en el código. –

+0

@ OleV.V. gracias por tu comentario, mi respuesta original fue de hecho sobre 'java.sql.Timestamp'. Como dijiste, generalmente es mejor establecer explícitamente la zona horaria. – amanteaux

4

Convertir fechas en Java 8 java.time.LocalDate as seen here.

LocalDate localDate1 = date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); 
LocalDate localDate2 = date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); 

// compare dates 
assertTrue("Not on the same day", localDate1.equals(localDate2)); 
+0

Esta es mi respuesta favorita. Si desea controlar la zona horaria utilizada en lugar de confiar en la configuración de la computadora, es fácil de instalar, por ejemplo 'ZoneId.of (" América/Phoenix ")' o 'ZoneId.of (" Europa/Budapest ")' en lugar del sistema predeterminado. –

5
private boolean isSameDay(Date date1, Date date2) { 
     Calendar calendar1 = Calendar.getInstance(); 
     calendar1.setTime(date1); 
     Calendar calendar2 = Calendar.getInstance(); 
     calendar2.setTime(date2); 
     boolean sameYear = calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR); 
     boolean sameMonth = calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH); 
     boolean sameDay = calendar1.get(Calendar.DAY_OF_MONTH) == calendar2.get(Calendar.DAY_OF_MONTH); 
     return (sameDay && sameMonth && sameYear); 
    } 
Cuestiones relacionadas