2013-10-19 3 views
23

Voglio trovare la differenza tra due oggetti Calendar in numero di giorni se c'è un cambiamento di data come Se l'orologio ha spuntato 23: 59-0: 00 ci dovrebbe essere una differenza di giorno.Come ottenere il numero di giorni tra due istanze del calendario?

ho scritto questo

public static int daysBetween(Calendar startDate, Calendar endDate) { 
    return Math.abs(startDate.get(Calendar.DAY_OF_MONTH)-endDate.get(Calendar.DAY_OF_MONTH)); 
} 

, ma la sua non funziona in quanto dà unica differenza tra i giorni se non v'è differenza mese il suo valore.

+1

Domande come questo è il motivo per cui hanno scritto tempo Joda. Il calendario Java è così disperato ... Devi usarlo? – iluxa

+5

Causa se è necessario, mi piacerebbe convertire sia per Millis e lavorare con questi, francamente :-) – iluxa

risposta

23

provare il seguente approccio:

public static long daysBetween(Calendar startDate, Calendar endDate) { 
    long end = endDate.getTimeInMillis(); 
    long start = startDate.getTimeInMillis(); 
    return TimeUnit.MILLISECONDS.toDays(Math.abs(end - start)); 
} 
+1

potrebbe incrementare di 1. – CoDe

+11

Questa non è la risposta corretta per la domanda iniziale. Questa risposta è corretta se la differenza di un giorno è definita in 86.400.000 millisecondi (il numero di millis in 24 ore). Tuttavia, la domanda iniziale chiesto 'se non v'è cambio di data, come se l'orologio spuntato da 23: 59-0: 00 ci dovrebbe essere un difference' giorno. Quindi la domanda definisce una differenza 1 giorno per essere quando il giorno di calendario differisce di 1. – stackoverflowuser2010

6

Questa funzione calcola il numero di giorni tra due calendari come il numero di giorni di calendario del mese che sono tra di loro, che è ciò che il PO voleva. Il calcolo viene eseguito contando quanti multipli di 86.400.000 millisecondi si trovano tra i calendari dopo che entrambi sono stati impostati sulla mezzanotte dei rispettivi giorni.

Ad esempio, la mia funzione calcolerà la differenza di 1 giorno tra un calendario l'1 gennaio, le 23:59 e il 2 gennaio, alle 00:01.

import java.util.concurrent.TimeUnit; 

/** 
* Compute the number of calendar days between two Calendar objects. 
* The desired value is the number of days of the month between the 
* two Calendars, not the number of milliseconds' worth of days. 
* @param startCal The earlier calendar 
* @param endCal The later calendar 
* @return the number of calendar days of the month between startCal and endCal 
*/ 
public static long calendarDaysBetween(Calendar startCal, Calendar endCal) { 

    // Create copies so we don't update the original calendars. 

    Calendar start = Calendar.getInstance(); 
    start.setTimeZone(startCal.getTimeZone()); 
    start.setTimeInMillis(startCal.getTimeInMillis()); 

    Calendar end = Calendar.getInstance(); 
    end.setTimeZone(endCal.getTimeZone()); 
    end.setTimeInMillis(endCal.getTimeInMillis()); 

    // Set the copies to be at midnight, but keep the day information. 

    start.set(Calendar.HOUR_OF_DAY, 0); 
    start.set(Calendar.MINUTE, 0); 
    start.set(Calendar.SECOND, 0); 
    start.set(Calendar.MILLISECOND, 0); 

    end.set(Calendar.HOUR_OF_DAY, 0); 
    end.set(Calendar.MINUTE, 0); 
    end.set(Calendar.SECOND, 0); 
    end.set(Calendar.MILLISECOND, 0); 

    // At this point, each calendar is set to midnight on 
    // their respective days. Now use TimeUnit.MILLISECONDS to 
    // compute the number of full days between the two of them. 

    return TimeUnit.MILLISECONDS.toDays(
      Math.abs(end.getTimeInMillis() - start.getTimeInMillis())); 
} 
-4

Calendar day1 = Calendar.getInstance();

Calendar day2 = Calendar.getInstance();

int diff = day1.get (Calendar.DAY_OF_YEAR) - day2.get (Calendar.DAY_OF_YEAR);

+6

Questo codice funziona solo se entrambi i casi sono per lo stesso anno. –

2

UPDATE Il progetto Joda-Time, ora in maintenance mode, consiglia migrazione ai java.time classi. Vedi the Answer di Anees A per l'uso di ChronoUnit e altre classi java.time.

Joda Time

Le vecchie classi java.util.Date/.Calendar sono notoriamente fastidioso e dovrebbero essere evitati.

Utilizzare invece la libreria Joda-Time. A meno che tu non abbia la tecnologia Java 8, nel qual caso usa il suo successore, il framework java.time incorporato (non in Android dal 2015).

Poiché ti interessano solo i "giorni" definiti come date (non i periodi di 24 ore), concentriamoci sulle date. Joda-Time offre la classe LocalDate per rappresentare un valore di sola data senza orario o fuso orario.

Mentre manca un fuso orario, notare che il fuso orario è cruciale nel determinare una data come "oggi". Un nuovo giorno sorge prima ad est che ad ovest. Quindi la data non è la stessa in tutto il mondo in un momento, la data dipende dal tuo fuso orario.

DateTimeZone zone = DateTimeZone.forID ("America/Montreal"); 
LocalDate today = LocalDate.now (zone); 

Contiamo il numero di giorni fino alla prossima settimana, che dovrebbe ovviamente essere sette.

LocalDate weekLater = today.plusWeeks (1); 
int elapsed = Days.daysBetween (today , weekLater).getDays(); 

La getDays sull'estremità estrae una pianura int numero dall'oggetto Days restituito da daysBetween.

Dump alla console.

System.out.println ("today: " + today + " to weekLater: " + weekLater + " is days: " + days); 

oggi: 2015/12/22 a weekLater: 2015/12/29 è giorni: 7

Hai oggetti Calendario. Dobbiamo convertirli in oggetti Joda-Time. Internamente gli oggetti del Calendario hanno un intero long che traccia il numero di millisecondi dall'epoca del primo momento del 1970 in UTC. Possiamo estrarre quel numero e alimentarlo a Joda-Time. Dobbiamo anche assegnare il fuso orario desiderato con il quale intendiamo determinare una data.

long startMillis = myStartCalendar.getTimeInMillis(); 
DateTime startDateTime = new DateTime(startMillis , zone); 

long stopMillis = myStopCalendar.getTimeInMillis(); 
DateTime stopDateTime = new DateTime(stopMillis , zone); 

Convertire da oggetti DateTime a LocalDate.

LocalDate start = startDateTime.toLocalDate(); 
LocalDate stop = stopDateTime.toLocalDate(); 

Ora eseguire lo stesso calcolo precedente che abbiamo visto in precedenza.

int elapsed = Days.daysBetween (start , stop).getDays(); 
10

In Java 8 e versioni successive, potremmo semplicemente utilizzare le java.time classi.

hoursBetween = ChronoUnit.HOURS.between(calendarObj.toInstant(), calendarObj.toInstant()); 

daysBetween = ChronoUnit.DAYS.between(calendarObj.toInstant(), calendarObj.toInstant()); 
+0

Può essere utilizzato anche prima di Java 8 ... Molte delle funzionalità java.time è di back-porting per Java 6 e Java 7 in [*** ThreeTen-Backport ***] (http://www.threeten.org/threetenbp /) progetto. Inoltre adattato per Android nel progetto [*** ThreeTenABP ***] (https://github.com/JakeWharton/ThreeTenABP). –

0

Ho l'approccio simile (non esattamente lo stesso) sopra indicato da https://stackoverflow.com/a/31800947/3845798.

E ho scritto casi di test intorno all'API, per me è fallito se ho superato 8 marzo 2017 - come data di inizio e 8 aprile 2017 come data di fine.

Ci sono poche date in cui vedrete la differenza entro 1 giorno. Pertanto, ho sorta di apportato alcune piccole modifiche al mio api e la mia api corrente ora sembra qualcosa di simile

public long getDays(long currentTime, long endDateTime) { 

Calendar endDateCalendar; 
Calendar currentDayCalendar; 


//expiration day 
endDateCalendar = Calendar.getInstance(TimeZone.getTimeZone("EST")); 
endDateCalendar.setTimeInMillis(endDateTime); 
endDateCalendar.set(Calendar.MILLISECOND, 0); 
endDateCalendar.set(Calendar.MINUTE, 0); 
endDateCalendar.set(Calendar.HOUR, 0); 
endDateCalendar.set(Calendar.HOUR_OF_DAY, 0); 

//current day 
currentDayCalendar = Calendar.getInstance(TimeZone.getTimeZone("EST")); 
currentDayCalendar.setTimeInMillis(currentTime); 
currentDayCalendar.set(Calendar.MILLISECOND, 0); 
currentDayCalendar.set(Calendar.MINUTE, 0); 
currentDayCalendar.set(Calendar.HOUR,0); 
currentDayCalendar.set(Calendar.HOUR_OF_DAY, 0); 


long remainingDays = (long)Math.ceil((float) (endDateCalendar.getTimeInMillis() - currentDayCalendar.getTimeInMillis())/(24 * 60 * 60 * 1000)); 

return remainingDays;} 

non sto usando TimeUnit.MILLISECONDS.toDays che mi stavano causando alcuni problemi.

0

Estensione a @ JK1 grande risposta:

public static long daysBetween(Calendar startDate, Calendar endDate) { 

    //Make sure we don't change the parameter passed 
    Calendar newStart = Calendar.getInstance(); 
    newStart.setTimeInMillis(startDate.); 
    newStart.set(Calendar.HOUR_OF_DAY, 0) 
    newStart.set(Calendar.MINUTE, 0) 
    newStart.set(Calendar.SECOND, 0) 
    newStart.set(Calendar.MILLISECOND, 0) 

    Calendar newEnd = Calendar.getInstance(); 
    newEnd.setTimeInMillis(startDate.); 
    newEnd.set(Calendar.HOUR_OF_DAY, 0) 
    newEnd.set(Calendar.MINUTE, 0) 
    newEnd.set(Calendar.SECOND, 0) 
    newEnd.set(Calendar.MILLISECOND, 0) 

    long end = newEnd.getTimeInMillis(); 
    long start = newStart.getTimeInMillis(); 
    return TimeUnit.MILLISECONDS.toDays(Math.abs(end - start)); 
}