2010-09-27 29 views
264

¿Cómo puedo encontrar la diferencia en Días entre dos instancias de Joda-TimeDateTime? Con "diferencia en días" quiero decir que si el inicio es el lunes y finaliza el martes, espero un valor de retorno de 1 independientemente de la hora/minuto/segundo de las fechas de inicio y finalización.Número de días entre dos fechas en Joda-Time

Days.daysBetween(start, end).getDays() me da 0 si el inicio es por la tarde y termina por la mañana.

También estoy teniendo el mismo problema con otros campos de fecha, así que esperaba que hubiera una forma genérica de 'ignorar' los campos de menor importancia.

En otras palabras, los meses entre febrero y 4 de marzo también serían 1, al igual que las horas entre 14:45 y 15:12. Sin embargo la diferencia de hora 14:01-14:55 sería 0.

Respuesta

318

La respuesta withTimeAtStartOfDay es molesta, pero solo ocasionalmente. ¿Quieres:

Days.daysBetween(start.toLocalDate(), end.toLocalDate()).getDays() 

Resulta que "la medianoche/comienzo del día" a veces significa 01 a.m. (horario de verano suceden de esta manera en algunos lugares), que Days.daysBetween no controla correctamente.

// 5am on the 20th to 1pm on the 21st, October 2013, Brazil 
DateTimeZone BRAZIL = DateTimeZone.forID("America/Sao_Paulo"); 
DateTime start = new DateTime(2013, 10, 20, 5, 0, 0, BRAZIL); 
DateTime end = new DateTime(2013, 10, 21, 13, 0, 0, BRAZIL); 
System.out.println(daysBetween(start.withTimeAtStartOfDay(), 
           end.withTimeAtStartOfDay()).getDays()); 
// prints 0 
System.out.println(daysBetween(start.toLocalDate(), 
           end.toLocalDate()).getDays()); 
// prints 1 

Pasando por un LocalDate elude todo el problema.

+0

Puede proporcionar un caso de ejemplo con datos específicos en los que piense ['Days.daysBetween'] (http://www.joda.org/joda-time/apidocs/org/joda/time/Days.html#daysBetween-org .joda.time.ReadableInstant-org.joda.time.ReadableInstant-) es incorrecto? –

+2

@BasilBourque - El ejemplo ya está en mi respuesta. –

+0

Cuando dice usar 'Instant', no solo está hablando de' start.toInstant() ', ¿verdad? –

79

puede utilizar LocalDate:

Days.daysBetween(new LocalDate(start), new LocalDate(end)).getDays() 
+0

Señor, con referencia a esto [publicación] (http://stackoverflow.com/q/17665921/1031945) el método 'toDateMidnight()' del tipo DateTime está en desuso. –

+2

actualizado ........ – Bozho

+0

¿Por qué utilizar 'new LocalDate (date)' over 'date.toLocalDate()'? – SARose

178

Days Clase

Utilización de la clase Days con el método withTimeAtStartOfDay debería funcionar:

Days.daysBetween(start.withTimeAtStartOfDay() , end.withTimeAtStartOfDay()).getDays() 
+1

gracias! Estaba intentando lograr el comportamiento de android.text.format.DateUtils.getRelativeTimeSpanString() con joda y esto fue realmente útil. –

+1

Señor, con referencia a esto [publicación] (http://stackoverflow.com/q/17665921/1031945) el método 'toDateMidnight()' del tipo DateTime está en desuso. –

+2

Ahora debería usar .withTimeAtStartOfDay() en lugar de .toDateMidnight() – bgolson

-10
public static int getDifferenceIndays(long timestamp1, long timestamp2) { 
    final int SECONDS = 60; 
    final int MINUTES = 60; 
    final int HOURS = 24; 
    final int MILLIES = 1000; 
    long temp; 
    if (timestamp1 < timestamp2) { 
     temp = timestamp1; 
     timestamp1 = timestamp2; 
     timestamp2 = temp; 
    } 
    Calendar startDate = Calendar.getInstance(TimeZone.getDefault()); 
    Calendar endDate = Calendar.getInstance(TimeZone.getDefault()); 
    endDate.setTimeInMillis(timestamp1); 
    startDate.setTimeInMillis(timestamp2); 
    if ((timestamp1 - timestamp2) < 1 * HOURS * MINUTES * SECONDS * MILLIES) { 
     int day1 = endDate.get(Calendar.DAY_OF_MONTH); 
     int day2 = startDate.get(Calendar.DAY_OF_MONTH); 
     if (day1 == day2) { 
      return 0; 
     } else { 
      return 1; 
     } 
    } 
    int diffDays = 0; 
    startDate.add(Calendar.DAY_OF_MONTH, diffDays); 
    while (startDate.before(endDate)) { 
     startDate.add(Calendar.DAY_OF_MONTH, 1); 
     diffDays++; 
    } 
    return diffDays; 
} 
+1

la pregunta está específicamente buscando joda-time. – kapad

2

La respuesta aceptada construye dos LocalDate objetos, que son bastante caros si están leyendo gran cantidad de datos. utilizo este:

public static int getDaysBetween(DateTime earlier, DateTime later) 
    { 
    return (int) TimeUnit.MILLISECONDS.toDays(later.getMillis()- earlier.getMillis()); 
    } 

Llamando getMillis() utiliza variables ya existentes.
MILLISECONDS.toDays() luego, utiliza un cálculo aritmético simple, no crea ningún objeto.

+1

Esta respuesta solo funciona si su definición de 'días' es exactamente de 24 horas sin tener en cuenta las zonas horarias y las fechas. Si es así, usa este enfoque. De lo contrario, consulte las otras respuestas que abordan las zonas horarias. –

+0

@BasilBourque, tiene razón, aún así, buscaría una solución basada en el cálculo aritmético en lugar de construir objetos costosos para cada llamada a un método, existen muchos sabores para tales cálculos, si está leyendo una entrada de una página web , podría estar bien, pero si está procesando un archivo de registro con cientos de miles de líneas, esto hace que sea muy lento – JBoy

+1

Java optimizará la asignación de objetos si el ciclo está activo. Ver http://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#escapeAnalysis –

4

tl; dr

java.time.temporal.ChronoUnit.DAYS.between( 
    earlier.truncatedTo(ChronoUnit.DAYS) , 
    later.truncatedTo(ChronoUnit.DAYS) 
) 

... o ...

java.time.temporal.ChronoUnit.HOURS.between( 
    earlier.truncatedTo(ChronoUnit.HOURS) , 
    later.truncatedTo(ChronoUnit.HOURS) 
) 

java.time

FYI, el proyecto se encuentra ahora en Joda-Timemaintenance mode, con el equipo de asesoramiento migración a las clases java.time .

El equivalente de Joda-Time DateTime es ZonedDateTime.

ZoneId z = ZoneId.of("Pacific/Auckland") ; 
ZonedDateTime now = ZonedDateTime.now(z) ; 

Al parecer desea contar los días de las fechas, lo que significa que quiere hacer caso omiso de la hora del día. Por ejemplo, comenzar un minuto antes de la medianoche y finalizar un minuto después de la medianoche debería resultar en un solo día. Para este comportamiento, extraiga un LocalDate de su ZonedDateTime. La clase LocalDate representa un valor de solo fecha sin hora del día y sin zona horaria.

LocalDate localDateStart = zdtStart.toLocalDate() ; 
LocalDate localDateStop = zdtStop.toLocalDate() ; 

Utilice la enumeración ChronoUnit para el cálculo de días transcurridos u otras unidades.

long days = ChronoUnit.DAYS.between(localDateStart , localDateStop) ; 

Truncar

En cuanto a usted preguntando acerca de una forma más general para hacer esto conteo en el que está interesado el delta de horas como hora-de-la-reloj en lugar de horas completas como vanos-de- tiempo de sesenta minutos, use el método truncatedTo.

Aquí está su ejemplo de 14:45 a 15:12 en el mismo día.

ZoneId z = ZoneId.of("America/Montreal"); 
ZonedDateTime start = ZonedDateTime.of(2017 , 1 , 17 , 14 , 45 , 0 , 0 , z); 
ZonedDateTime stop = ZonedDateTime.of(2017 , 1 , 17 , 15 , 12 , 0 , 0 , z); 

long hours = ChronoUnit.HOURS.between(start.truncatedTo(ChronoUnit.HOURS) , stop.truncatedTo(ChronoUnit.HOURS)); 

Para un recuento de días por fechas, truncadas a ChronoUnit.DAYS. Aquí hay un ejemplo que pasa de la medianoche de cinco minutos antes a cinco minutos después, para los días transcurridos de 1.

ZoneId z = ZoneId.of("America/Montreal"); 
ZonedDateTime start = ZonedDateTime.of(2017 , 1 , 17 , 23 , 55 , 0 , 0 , z); 
ZonedDateTime stop = ZonedDateTime.of(2017 , 1 , 18 , 00 , 05 , 0 , 0 , z); 

long days = ChronoUnit.DAYS.between(start.truncatedTo(ChronoUnit.DAYS) , stop.truncatedTo(ChronoUnit.DAYS)); 

Sobre java.time

El marco java.time está incorporado en Java 8 y versiones posteriores. Estas clases suplantan a las viejas y problemáticas clases de fecha y hora legacy, como java.util.Date, Calendar, & SimpleDateFormat.

El proyecto Joda-Time, ahora en maintenance mode, recomienda la migración a las clases java.time.

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

¿Dónde obtener las clases java.time?

El proyecto se extiende ThreeTen-Extra java.time con clases adicionales. Este proyecto es un terreno de prueba para posibles adiciones futuras a java.time. Puede encontrar algunas clases útiles aquí, como Interval, YearWeek, YearQuarter y more.

Cuestiones relacionadas