Java: Wie überprüfe ich, ob ein Date innerhalb eines bestimmten Bereichs liegt?

Ich habe eine Reihe von Bereichen mit Startdaten und Endterminen. Ich möchte überprüfen, ob ein Datum in diesem Bereich liegt.

Date.before () und Date.after () scheinen etwas unhandlich zu sein. Was ich wirklich brauche, ist so etwas wie dieser Pseudocode:

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

Nicht sicher, ob es relevant ist, aber die Daten, die ich aus der database ziehe, haben Zeitstempel.

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

Scheint mir nicht unangenehm. Beachten Sie, dass ich es auf diese Weise geschrieben habe statt

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

Es würde also funktionieren, selbst wenn testDate genau einem der Endfälle entspricht.

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 classes. .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*. ) 

Halb offen

Datum-Uhrzeit-Arbeit verwendet häufig den “halboffenen” Ansatz zum Definieren einer Zeitspanne. Der Anfang ist inklusive, während das Ende exklusiv ist . So läuft eine Woche, die an einem Montag beginnt, am folgenden Montag auf, aber schließt nicht ein.

java.time

Java 8 und höher wird mit dem eingebauten java.time- Framework geliefert . Ergänzt die alten problematischen classn einschließlich java.util.Date/.Calendar und SimpleDateFormat. Inspiriert von der erfolgreichen Joda-Time-Bibliothek. Definiert von JSR 310. Erweitert um das ThreeTen-Extra-Projekt.

Ein Instant ist ein Moment auf der Timeline in UTC mit Nanosekundenauflösung.

Instant

Konvertieren Sie Ihre java.util.Date-Objekte in Instant-Objekte.

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

Wenn Sie java.sql.Timestamp-Objekte über JDBC von einer database abrufen , konvertieren Sie sie auf ähnliche Weise in java.time.Instant . Ein java.sql.Timestamp befindet sich bereits in UTC, sodass Sie sich keine Gedanken über Zeitzonen machen müssen.

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

Holen Sie sich den aktuellen Moment zum Vergleich.

 Instant now = Instant.now(); 

Vergleichen Sie mit den Methoden isBefore, isAfter und equals.

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

LocalDate

Vielleicht möchten Sie nur mit dem Datum und nicht mit der Uhrzeit arbeiten.

Die LocalDate class stellt einen Nur-Datum-Wert ohne Uhrzeit und ohne Zeitzone dar.

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

Geben Sie eine Zeitzone an, um das aktuelle Datum abzurufen. Für einen bestimmten Zeitpunkt variiert das heutige Datum je nach Zeitzone. Zum Beispiel dämmert früher in Paris ein neuer Tag als in Montréal.

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

Wir können die Methoden isEqual , isBefore und isAfter zum Vergleich verwenden. In der Date-Time-Arbeit verwenden wir häufig den Half-Open-Ansatz, bei dem der Beginn einer Zeitspanne eingeschlossen ist, während das Ende exklusiv ist .

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

Interval

Wenn Sie die ThreeTen-Extra- Bibliothek zu Ihrem Projekt hinzufügen, können Sie mit der Interval class eine Zeitspanne definieren. Diese class bietet Methoden an, um zu testen, ob das Intervall andere Datumsangaben / Intervalle enthält , berührt , umschließt oder überlappt .

Die Interval class arbeitet mit Instant Objekten. Die Instant class repräsentiert einen Moment auf der Timeline in UTC mit einer Auflösung von Nanosekunden (bis zu neun (9) Ziffern eines Dezimalbruchteils).

Wir können das LocalDate auf einen bestimmten Moment einstellen, den ersten Moment des Tages, indem ZonedDateTime eine Zeitzone ZonedDateTime , um eine ZonedDateTime . Von dort können wir zurück zu UTC gelangen, indem wir einen Instant extrahieren.

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

Über java.time

Das Framework java.time ist in Java 8 und höher integriert. Diese classn ersetzen die problematischen alten Legacy- Date-Time-classn wie java.util.Date , Calendar und SimpleDateFormat .

Das Joda-Time- Projekt, das sich jetzt im Wartungsmodus befindet , empfiehlt die Migration in die java.time- classn.

Weitere Informationen finden Sie im Oracle-Lernprogramm . Und suchen Sie nach Stack Overflow für viele Beispiele und Erklärungen. Spezifikation ist JSR 310 .

Wo erhalten Sie die java.time classn?

  • Java SE 8 und SE 9 und später
    • Eingebaut.
    • Teil der Standard-Java-API mit einer gebündelten Implementierung.
    • Java 9 fügt einige kleinere functionen und Korrekturen hinzu.
  • Java SE 6 und SE 7
    • Ein großer Teil der java.time-functionalität wird in ThreeTen-Backport zurück zu Java 6 & 7 portiert .
  • Android
    • Das ThreeTenABP- Projekt passt ThreeTen-Backport (oben erwähnt) speziell für Android an.
    • Siehe Verwendung von ….

Das ThreeTen-Extra- Projekt erweitert java.time um zusätzliche classn. Dieses Projekt ist ein Testfeld für mögliche zukünftige Erweiterungen von java.time. Sie können hier einige nützliche classn wie Interval , YearWeek , YearQuarter und mehr finden .

Das ist der richtige Weg. Kalender funktionieren auf die gleiche Weise. Das Beste, was ich Ihnen (basierend auf Ihrem Beispiel) anbieten konnte, ist folgendes:

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

Date.getTime () gibt die Anzahl der Millisekunden seit dem 1.1.1970 00:00:00 GMT zurück und ist so lang, dass es leicht vergleichbar ist.

Erwägen Sie die Verwendung von Joda Time . Ich liebe diese Bibliothek und wünsche mir, dass sie das derzeitige schreckliche Durcheinander ersetzen würde, das die vorhandenen Java-Datums- und -Kalenderklassen sind. Es ist die richtige Datumsverarbeitung.

EDIT: Es ist nicht mehr 2009, und Java 8 ist seit Ewigkeiten draußen. Verwenden Sie Java 8’s eingebaute java.time classn, die auf Joda Time basieren, wie Basil Bourque unten erwähnt. In diesem Fall möchten Sie die Period-class, und hier ist Oracle’s Tutorial, wie man es benutzt.

Eine einfache Möglichkeit besteht darin, die Datumsangaben nach dem 1. Januar 1970 in Millisekunden zu konvertieren (verwenden Sie Date.getTime ()) und dann diese Werte zu vergleichen.

Es ist mir egal, welche Datumsgrenze welche ist.

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

Sie können so verwenden

 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 

Das war mir klarer,

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

Ich sehe nicht den Grund dafür in Java, wenn Sie es mit einer einfachen SQL-statement tun können.

Wie in dieser Frage / Antwort:

Postgresql-Abfrage zwischen Datumsbereichen

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

Passen Sie einfach auf Ihre Bedürfnisse und fertig. Etwas wie:

  SELECT testdate FROM dates WHERE testdate BETWEEN startdate AND duedate 

Deine Logik würde gut funktionieren. Wie du bereits erwähnt hast, sind die Daten, die du von der database bekommst, im Zeitstempel. Du musst nur den Zeitstempel in das Datum umwandeln und dann diese Logik verwenden.

Vergessen Sie auch nicht, nach Null-Daten zu suchen.

Hier teilen Sie ein bisschen, um vom Zeitstempel zum Datum zu konvertieren.

public static Date convertTimeStamptoDate (Zeichenfolge val) throws 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; } }