Numero di giorni tra due date in Joda-Time


336

Come trovo la differenza in Giorni tra due istanze di Joda-Time DateTime ? Con "differenza in giorni" intendo se l'inizio è lunedì e la fine è martedì mi aspetto un valore di ritorno di 1 indipendentemente dall'ora / minuto / secondi delle date di inizio e fine.

Days.daysBetween(start, end).getDays() mi dà 0 se inizio è la sera e termina la mattina.

Ho anche lo stesso problema con altri campi di date, quindi speravo che ci fosse un modo generico per "ignorare" i campi di minore importanza.

In altre parole, i mesi tra febbraio e 4 marzo sarebbero anche 1, così come le ore tra le 14:45 e le 15:12. Tuttavia, la differenza oraria tra le 14:01 e le 14:55 sarebbe 0.

Risposte:


393

Stranamente, la risposta withTimeAtStartOfDay è sbagliata, ma solo occasionalmente. Tu vuoi:

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

Si scopre che "mezzanotte / inizio del giorno" a volte significa 01:00 (in alcuni luoghi l'ora legale si verifica in questo modo), che Days.daysB Between non gestisce correttamente.

// 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

Passare da un LocalDatelato evita l'intero problema.


Puoi fornire un caso di esempio con dati specifici in cui ritieni che Days.daysBetweennon siano corretti?
Basil Bourque,

Quando dici di usare Instant, non stai solo parlando start.toInstant(), vero?
Patrick M,

@PatrickM Sì, lo ero. Riflettendoci, non è chiaro esattamente quali vincoli si intende imporre, quindi rimuoverò quest'ultima frase. Grazie!
Alice Purcell,

@chrispy daysB Between doc dice che restituisce il numero di TUTTI i giorni. Nel mio caso 2 giorni e 1 ora dovrebbero restituirmi 3 giorni. Nel tuo esempio restituisce 2 giorni. C'è un modo per raggiungere questo obiettivo?
Sujit Joshi,

@SujitJoshi Temo di non capire la tua domanda. Suggerisco di pubblicare una domanda Stack Overflow completa e incollare un link qui per me :)
Alice Purcell,

186

Days Classe

L'uso della Daysclasse con il withTimeAtStartOfDaymetodo dovrebbe funzionare:

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

1
Grazie! Stavo cercando di ottenere il comportamento di android.text.format.DateUtils.getRelativeTimeSpanString () con joda e questo è stato davvero utile.
gosho_ot_pochivka,

1
Signore, con riferimento a questo post il metodo toDateMidnight()dal tipo DateTime è obsoleto.
Aniket Kulkarni l'

2
Ora dovresti usare .withTimeAtStartOfDay () invece di .toDateMidnight ()
bgolson,

2
cosa succede se endè prima di start, restituisce giorni negativi?
ahyhy

7
@akhyar: perché non lo provi?
Michael Borgwardt,

86

puoi usare LocalDate:

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

Signore, con riferimento a questo post il metodo toDateMidnight()dal tipo DateTime è obsoleto.
Aniket Kulkarni l'

Perché usare new LocalDate(date)over date.toLocalDate()?
SARose il

9

tl; dr

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

…o…

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

java.time

Cordiali saluti, il progetto Joda-Time è ora in modalità di manutenzione , con il team che consiglia la migrazione alle classi java.time .

L'equivalente di Joda-Time DateTimeè ZonedDateTime.

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

Apparentemente vuoi contare i giorni per data, il che significa che vuoi ignorare l'ora del giorno. Ad esempio, iniziare un minuto prima di mezzanotte e terminare un minuto dopo la mezzanotte dovrebbe tradursi in un solo giorno. Per questo comportamento, estrarre un LocalDatedal tuo ZonedDateTime. La LocalDateclasse rappresenta un valore di sola data senza ora del giorno e senza fuso orario.

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

Utilizzare l' ChronoUnitenum per calcolare i giorni trascorsi o altre unità.

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

Troncare

Per quanto riguarda la tua domanda su un modo più generale di fare questo conteggio in cui sei interessato al delta di ore come ora piuttosto che ore complete come intervalli di tempo di sessanta minuti, usa il truncatedTometodo.

Ecco il tuo esempio da 14:45 a 15:12 nello stesso giorno.

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

1

Questo non funziona per giorni. Utilizzare toLocalDate () in questo caso.


Informazioni su java.time

Il framework java.time è integrato in Java 8 e versioni successive. Queste classi soppiantare la vecchia fastidiosi legacy classi data-time come java.util.Date, Calendar, e SimpleDateFormat.

Il progetto Joda-Time , ora in modalità manutenzione , consiglia la migrazione alle classi java.time .

Per saperne di più, consulta il tutorial Oracle . E cerca Stack Overflow per molti esempi e spiegazioni. La specifica è JSR 310 .

Puoi scambiare oggetti java.time direttamente con il tuo database. Utilizzare un driver JDBC conforme a JDBC 4.2 o successivo. Nessuna necessità di stringhe, nessuna necessità di java.sql.*classi.

Dove ottenere le classi java.time?

Il progetto ThreeTen-Extra estende java.time con classi aggiuntive. Questo progetto è un banco di prova per possibili aggiunte future a java.time. Si possono trovare alcune classi utili, come per esempio Interval, YearWeek, YearQuartere altro .

Il progetto ThreeTen-Extra estende java.time con classi aggiuntive. Questo progetto è un banco di prova per possibili aggiunte future a java.time. Si possono trovare alcune classi utili, come per esempio Interval, YearWeek, YearQuartere altro .


Il tuo TL; DR per giorni che usano il troncato cade in preda al bug dettagliato nella risposta accettata, vale a dire è off-by-one quando l'inizio del giorno è all'01: 00. L'ho aggiornato per usare la risposta corretta che hai dato più in basso, usando toLocalDate.
Alice Purcell,

2

La risposta accettata crea due LocalDateoggetti, che sono piuttosto costosi se stai leggendo molti dati. Io lo uso questo:

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

Chiamando getMillis()si utilizzano variabili già esistenti.
MILLISECONDS.toDays()quindi, utilizza un semplice calcolo aritmetico, non crea alcun oggetto.


1
Questa risposta funziona solo se la tua definizione di "giorni" è esattamente di 24 ore, indipendentemente da fusi orari e date. In tal caso, utilizzare questo approccio. Altrimenti, guarda le altre risposte che riguardano i fusi orari.
Basil Bourque,

@BasilBourque, hai ragione, comunque, sceglierei una soluzione basata sul calcolo aritmetico piuttosto che costruire oggetti costosi per ogni chiamata di metodo, ci sono molti gusti là fuori per tali calcoli, se stai leggendo un input da una pagina web, potrebbe essere ok, ma se stai elaborando un file di registro con centinaia di migliaia di righe, questo lo rende molto lento
JBoy

1
Java ottimizzerà l'assegnazione degli oggetti se il tuo ciclo è attivo. Vedi docs.oracle.com/javase/7/docs/technotes/guides/vm/…
Alice Purcell,

1

java.time.Period

Usa la java.time.Periodclasse per contare i giorni .

Poiché Java 8 calcola la differenza è più intuitivo utilizzando LocalDate, LocalDateTimeper rappresentare le due date

    LocalDate now = LocalDate.now();
    LocalDate inputDate = LocalDate.of(2018, 11, 28);

    Period period = Period.between( inputDate, now);
    int diff = period.getDays();
    System.out.println("diff = " + diff);

0
DateTime  dt  = new DateTime(laterDate);        

DateTime newDate = dt.minus( new  DateTime ( previousDate ).getMillis());

System.out.println("No of days : " + newDate.getDayOfYear() - 1 );    

-11
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 domanda è specificamente alla ricerca di joda-time.
Kapad,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.