Confronto di due java.util.Dates per vedere se sono nello stesso giorno

Ho bisogno di confrontare due Date s (ad esempio, date2 e date2 ) e date2 trovato un valore boolean sameDay che è vero per le due Date che condividono lo stesso giorno, e false se non lo sono.

Come posso fare questo? Sembra che ci sia un vortice di confusione qui … e vorrei evitare di inserire altre dipendenze oltre il JDK se ansible.

per chiarire: se date1 e date2 condividono lo stesso anno, mese e giorno, allora sameDay è vero, altrimenti è falso. Mi rendo conto che ciò richiede la conoscenza di un fuso orario … sarebbe bello passare in un fuso orario, ma posso vivere con GMT o ora locale purché conosca il comportamento.

di nuovo, per chiarire:

 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 

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

Si noti che “lo stesso giorno” non è un concetto così semplice come sembra quando possono essere coinvolti diversi fusi orari. Il codice sopra per entrambe le date calcola il giorno relativo al fuso orario utilizzato dal computer su cui è in esecuzione. Se questo non è ciò di cui hai bisogno, devi passare il fuso orario pertinente alle chiamate di Calendar.getInstance() , dopo aver deciso cosa intendi esattamente con “lo stesso giorno”.

E sì, il LocalDate Joda Time renderebbe il tutto molto più pulito e semplice (anche se sarebbero presenti le stesse difficoltà che coinvolgono i fusi orari).

Che ne dite di:

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

È anche ansible impostare il fuso orario su SimpleDateFormat, se necessario.

Io uso il pacchetto “apache commons lang” per fare questo (vale a dire org.apache.commons.lang.time.DateUtils)

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

È ansible evitare le dipendenze esterne e l’impatto sulle prestazioni dell’utilizzo di Calendar calcolando il numero del giorno giuliano per ciascuna data e confrontandole:

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

Joda-Time

Per quanto riguarda l’aggiunta di una dipendenza, temo che java.util.Date e .Calendar siano davvero così dannosi che la prima cosa che faccio a qualsiasi nuovo progetto è aggiungere la libreria Joda-Time. In Java 8 è ansible utilizzare il nuovo pacchetto java.time, ispirato a Joda-Time.

Il nucleo di Joda-Time è la class DateTime . A differenza di java.util.Date, comprende il fuso orario assegnato ( DateTimeZone ). Quando si esegue la conversione da juDate, assegnare una zona.

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

LocalDate

Un modo per verificare se due date-ora vengono LocalDate alla stessa data per la conversione in oggetti LocalDate .

Quella conversione dipende dal fuso orario assegnato. Per confrontare LocalDate oggetti LocalDate , devono essere stati convertiti con la stessa zona.

Ecco un piccolo metodo di utilità.

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

Meglio sarebbe un altro argomento, specificando il fuso orario piuttosto che assumendo che il primo fuso orario dell’object DateTime debba essere usato.

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

Rappresentazione di stringa

Un altro approccio consiste nel creare una rappresentazione di stringa della porzione di data di ciascuna data-ora, quindi confrontare le stringhe.

Ancora una volta, il fuso orario assegnato è cruciale.

 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; 

Lasso di tempo

La soluzione generalizzata è definire un intervallo di tempo, quindi chiedere se lo span contiene il tuo objective. Questo codice di esempio è in Joda-Time 2.4. Si noti che le classi correlate a “mezzanotte” sono deprecate. Utilizzare invece il metodo withTimeAtStartOfDay . Joda-Time offre tre classi per rappresentare un intervallo di tempo in vari modi: Intervallo, Periodo e Durata.

Usando l’approccio “Semiaperto” dove l’inizio dello span è inclusivo e il finale esclusivo.

Il fuso orario del target può essere diverso dal fuso orario dell’intervallo.

 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 e versioni successive sono dotati del framework java.time . Ispirato a Joda-Time, definito da JSR 310 e ampliato dal progetto ThreeTen-Extra. Vedi Tutorial .

I creatori di Joda-Time ci hanno incaricato di passare a java.time non appena ansible. Nel frattempo, Joda-Time continua come un progetto triggersmente mantenuto. Ma aspettatevi che il lavoro futuro si verifichi solo in java.time e ThreeTen-Extra piuttosto che in Joda-Time.

Per riassumere java.time in poche parole … Un Instant è un momento sulla timeline in UTC. Applicare un fuso orario ( ZoneId ) per ottenere un object ZonedDateTime . Per uscire dalla timeline, per ottenere la vaga idea indefinita di una data-ora, utilizzare le classi “local”: LocalDateTime , LocalDate , LocalTime .

La logica discussa nella sezione Joda-Time di questa risposta si applica a java.time.

La vecchia class java.util.Date ha un nuovo metodo toInstant per la conversione in java.time.

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

Determinare una data richiede un fuso orario.

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

Applichiamo quell’object del fuso orario a Instant per ottenere un ZonedDateTime . Da ciò estraiamo un valore di sola data (un LocalDate ) in quanto il nostro objective è confrontare le date (non ore, minuti, ecc.).

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

Fai lo stesso con il secondo object java.util.Date cui abbiamo bisogno per il confronto. Invece userò il momento attuale.

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

Utilizzare il metodo isEqual speciale per verificare lo stesso valore di data.

 Boolean sameDate = localDate1.isEqual( localDate2 ); 

Converti le date in Java 8 java.time.LocalDate come si vede qui .

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

Java 8

Se stai usando Java 8 nel tuo progetto e confronti java.sql.Timestamp , potresti usare la class LocalDate :

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

Se stai usando java.util.Date , dai un’occhiata alla risposta di Istvan che è meno ambigua.

PER GLI UTENTI ANDROID:

È ansible utilizzare DateUtils.isToday(dateMilliseconds) per verificare se la data data è giorno corrente o meno.

Riferimento API: https://developer.android.com/reference/android/text/format/DateUtils.html#isToday(long)

oltre alla soluzione di 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); 
 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; } 

è ansible applicare la stessa logica della soluzione SimpleDateFormat senza fare affidamento su SimpleDateFormat

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