Java: come posso verificare se una data è all’interno di un determinato intervallo?

Ho una serie di intervalli con date di inizio e date di fine. Voglio verificare se una data è all’interno di tale intervallo.

Date.before () e Date.after () sembrano essere un po ‘scomodi da usare. Quello di cui ho veramente bisogno è qualcosa di simile a questo pseudocodice:

boolean isWithinRange(Date testDate) { return testDate >= startDate && testDate <= endDate; } 

Non sono sicuro se è pertinente, ma le date che sto prelevando dal database hanno data e ora.

 boolean isWithinRange(Date testDate) { return !(testDate.before(startDate) || testDate.after(endDate)); } 

Non sembra così imbarazzante per me. Nota che l’ho scritto in quel modo invece di

 return testDate.after(startDate) && testDate.before(endDate); 

quindi funzionerebbe anche se testDate fosse esattamente uguale a uno dei casi finali.

tl; dr

 ZoneId z = ZoneId.of( "America/Montreal" ); // A date only has meaning within a specific time zone. For any given moment, the date varies around the globe by zone. LocalDate ld = givenJavaUtilDate.toInstant() // Convert from legacy class `Date` to modern class `Instant` using new methods added to old classs. .atZone( z ) // Adjust into the time zone in order to determine date. .toLocalDate(); // Extract date-only value. LocalDate today = LocalDate.now( z ); // Get today's date for specific time zone. LocalDate kwanzaaStart = today.withMonth( Month.DECEMBER ).withDayOfMonth( 26 ); // Kwanzaa starts on Boxing Day, day after Christmas. LocalDate kwanzaaStop = kwanzaaStart.plusWeeks( 1 ); // Kwanzaa lasts one week. Boolean isDateInKwanzaaThisYear = ( ( ! today.isBefore( kwanzaaStart ) ) // Short way to say "is equal to or is after". && today.isBefore( kwanzaaStop ) // Half-Open span of time, beginning inclusive, ending is *exclusive*. ) 

Mezzo aperto

Il lavoro di data-ora impiega comunemente l’approccio “semiaperto” per definire un intervallo di tempo. L’inizio è inclusivo mentre il finale è esclusivo . Quindi una settimana che inizia il lunedì arriva fino a, ma non include, il lunedì successivo.

java.time

Java 8 e versioni successive sono dotati del framework java.time integrato. Sostituisce le vecchie classi fastidiose tra cui java.util.Date/.Calendar e SimpleDateFormat. Ispirato alla fortunata libreria Joda-Time. Definito da JSR 310. Ampliato dal progetto ThreeTen-Extra.

Un Instant è un momento sulla timeline in UTC con risoluzione di nanosecondi.

Instant

Converti gli oggetti java.util.Date in oggetti istantanei.

 Instant start = myJUDateStart.toInstant(); Instant stop = … 

Se si ottengono oggetti java.sql.Timestamp tramite JDBC da un database, convertire in java.time.Instant in modo simile. Un java.sql.Timestamp è già in UTC quindi non è necessario preoccuparsi dei fusi orari.

 Instant start = mySqlTimestamp.toInstant() ; Instant stop = … 

Ottieni il momento attuale per il confronto.

 Instant now = Instant.now(); 

Confrontare usando i metodi isBefore, isAfter e equals.

 Boolean containsNow = ( ! now.isBefore( start ) ) && ( now.isBefore( stop ) ) ; 

LocalDate

Forse vuoi lavorare solo con la data, non con l’ora del giorno.

La class LocalDate rappresenta un valore di sola data, senza ora del giorno e senza fuso orario.

 LocalDate start = LocalDate.of( 2016 , 1 , 1 ) ; LocalDate stop = LocalDate.of( 2016 , 1 , 23 ) ; 

Per ottenere la data corrente, specificare un fuso orario. Per un dato momento, la data odierna varia a seconda del fuso orario. Ad esempio, un nuovo giorno sorge prima a Parigi che a Montréal.

 LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) ); 

Possiamo usare isEqual , isBefore e isAfter per confrontare i metodi. Nel lavoro in data-ora usiamo comunemente l’approccio Half-Open in cui l’inizio di un intervallo di tempo è inclusivo mentre il finale è esclusivo .

 Boolean containsToday = ( ! today.isBefore( start ) ) && ( today.isBefore( stop ) ) ; 

Interval

Se si è scelto di aggiungere la libreria ThreeTen-Extra al progetto, è ansible utilizzare la class Interval per definire un intervallo di tempo. Questa class offre metodi per verificare se l’intervallo contiene , si contrae , si chiude o si sovrappone ad altre date / intervalli di tempo.

La class Interval funziona su oggetti Instant . La class Instant rappresenta un momento sulla timeline in UTC con una risoluzione di nanosecondi (fino a nove (9) cifre di una frazione decimale).

Possiamo regolare il LocalDate in un momento specifico, il primo momento della giornata, specificando un fuso orario per ottenere un ZonedDateTime . Da lì possiamo tornare a UTC estraendo un Instant .

 ZoneId z = ZoneId.of( "America/Montreal" ); Interval interval = Interval.of( start.atStartOfDay( z ).toInstant() , stop.atStartOfDay( z ).toInstant() ); Instant now = Instant.now(); Boolean containsNow = interval.contains( now ); 

A proposito di java.time

Il framework java.time è integrato in Java 8 e versioni successive. Queste classi soppiantano le fastidiose vecchie lezioni di data e ora come java.util.Date , Calendar e SimpleDateFormat .

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

Per saperne di più, consultare l’ esercitazione Oracle . E cerca Stack Overflow per molti esempi e spiegazioni. La specifica è JSR 310 .

Dove ottenere le classi java.time?

  • Java SE 8 e SE 9 e versioni successive
    • Built-in.
    • Parte dell’API Java standard con un’implementazione in bundle.
    • Java 9 aggiunge alcune funzionalità e correzioni minori.
  • Java SE 6 e SE 7
    • Gran parte della funzionalità java.time è back-porting su Java 6 e 7 in ThreeTen-Backport .
  • android
    • Il progetto ThreeTenABP adatta ThreeTen-Backport (menzionato sopra) per Android in particolare.
    • Vedi Come usare ….

Il progetto ThreeTen-Extra estende java.time con classi aggiuntive. Questo progetto è un terreno di prova per possibili aggiunte future a java.time. Puoi trovare alcune classi utili come Interval , YearWeek , YearQuarter e altro .

Questo è il modo corretto. I calendari funzionano allo stesso modo. Il meglio che potrei offrirti (basato sul tuo esempio) è questo:

 boolean isWithinRange(Date testDate) { return testDate.getTime() >= startDate.getTime() && testDate.getTime() < = endDate.getTime(); } 

Date.getTime () restituisce il numero di millisecondi dal 1/1/1970 00:00:00 GMT ed è lungo, quindi è facilmente confrontabile.

Prendi in considerazione l’utilizzo di Joda Time . Amo questa libreria e vorrei che sostituisse l’orribile pasticcio attuale delle classi Java Date e Calendar esistenti. La gestione della data è stata eseguita correttamente.

EDIT: Non è più il 2009, e Java 8 è uscito da anni. Utilizza le classi java.time integrate in Java 8 che sono basate su Joda Time, come menzionato da Basil Bourque. In questo caso vorrai la class Period, ed ecco il tutorial di Oracle su come usarlo.

Un modo semplice è convertire le date in millisecondi dopo il 1 gennaio 1970 (utilizzare Date.getTime ()) e quindi confrontare questi valori.

Non importa quale data sia diversa.

 Math.abs(date1.getTime() - date2.getTime()) == Math.abs(date1.getTime() - dateBetween.getTime()) + Math.abs(dateBetween.getTime() - date2.getTime()); 

puoi usare così

 Interval interval = new Interval(date1.getTime(),date2.getTime()); Interval interval2 = new Interval(date3.getTime(), date4.getTime()); Interval overlap = interval.overlap(interval2); boolean isOverlap = overlap == null ? false : true 

Questo è stato più chiaro per me,

 // declare calendar outside the scope of isWithinRange() so that we initialize it only once private Calendar calendar = Calendar.getInstance(); public boolean isWithinRange(Date date, Date startDate, Date endDate) { calendar.setTime(startDate); int startDayOfYear = calendar.get(Calendar.DAY_OF_YEAR); // first day is 1, last day is 365 int startYear = calendar.get(Calendar.YEAR); calendar.setTime(endDate); int endDayOfYear = calendar.get(Calendar.DAY_OF_YEAR); int endYear = calendar.get(Calendar.YEAR); calendar.setTime(date); int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR); int year = calendar.get(Calendar.YEAR); return (year > startYear && year < endYear) // year is within the range || (year == startYear && dayOfYear >= startDayOfYear) // year is same as start year, check day as well || (year == endYear && dayOfYear < endDayOfYear); // year is same as end year, check day as well } 

Non vedo la ragione per farlo in java quando puoi farlo con una semplice istruzione sql.

Come in questa Domanda / Risposta:

Query Postgresql tra intervalli di date

 SELECT user_id FROM user_logs WHERE login_date >= '2014-02-01' AND login_date < '2014-03-01' 

Basta adattarsi alle tue esigenze e finito. Qualcosa di simile a:

  SELECT testdate FROM dates WHERE testdate BETWEEN startdate AND duedate 

la tua logica funzionerebbe bene. Come hai detto, le date che ottengono dal database sono nel timestamp, devi solo convertire prima il timestamp e poi usare questa logica.

Inoltre, non dimenticare di verificare le date nulle.

qui m condivido un po ‘per convertire da Timestamp fino ad oggi.

public static Date convertTimeStamptoDate (String val) genera Exception {

  DateFormat df = null; Date date = null; try { df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); date = df.parse(val); // System.out.println("Date Converted.."); return date; } catch (Exception ex) { System.out.println(ex); return convertDate2(val); } finally { df = null; date = null; } } 
  public class TestDate { public static void main(String[] args) { // TODO Auto-generated method stub String fromDate = "18-FEB-2018"; String toDate = "20-FEB-2018"; String requestDate = "19/02/2018"; System.out.println(checkBetween(requestDate,fromDate, toDate)); } public static boolean checkBetween(String dateToCheck, String startDate, String endDate) { boolean res = false; SimpleDateFormat fmt1 = new SimpleDateFormat("dd-MMM-yyyy"); //22-05-2013 SimpleDateFormat fmt2 = new SimpleDateFormat("dd/MM/yyyy"); //22-05-2013 try { Date requestDate = fmt2.parse(dateToCheck); Date fromDate = fmt1.parse(startDate); Date toDate = fmt1.parse(endDate); res = requestDate.compareTo(fromDate) >= 0 && requestDate.compareTo(toDate) < =0; }catch(ParseException pex){ pex.printStackTrace(); } return res; } }