wake-up-neo.com

Java: Wie überprüfe ich, ob ein Datum in einem bestimmten Bereich liegt?

Ich habe eine Reihe von Bereichen mit Start- und Enddaten. Ich möchte prüfen, ob ein Datum in diesem Bereich liegt.

Date.before () und Date.after () scheinen ein wenig umständlich zu sein. Was ich wirklich brauche, ist so etwas wie dieser Pseudocode:

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

Ich bin nicht sicher, ob es relevant ist, aber die Daten, die ich aus der Datenbank abriehe, haben Zeitstempel. 

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

Scheint mir nicht so unbeholfen. Beachten Sie, dass ich es anders als geschrieben habe 

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

es würde also funktionieren, wenn testDate genau einem Endfall entspricht.

104
Paul Tomblin

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

Bei der Datum-Uhrzeit-Arbeit wird im Allgemeinen der "Halboffen" -Ansatz zum Definieren einer Zeitspanne verwendet. Der Anfang ist inklusive, während das Ende exklusiv ist. Eine Woche, die an einem Montag beginnt, läuft also bis zum folgenden Montag. 

Java.time

Java 8 und höher ist mit dem Java.time -Framework integriert. Supplants der alten störenden Klassen 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 Zeitleiste in UTC mit einer Auflösung von Nanosekunden. 

Instant

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

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

Wenn Sie Java.sql.Timestamp-Objekte aus einer Datenbank über JDBC abrufen, müssen Sie in Java.time.Instant konvertieren. Ein Java.sql.Timestamp befindet sich bereits in UTC, sodass Sie sich keine Sorgen um 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 arbeiten, nicht mit der Uhrzeit.

Die LocalDate-Klasse stellt einen Datumswert dar, ohne Uhrzeit und ohne Zeitzone.

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

Geben Sie eine Zeitzone an, um das aktuelle Datum abzurufen. Das heutige Datum variiert für jeden Moment je nach Zeitzone. Zum Beispiel bricht in Paris ein neuer Tag früher an als in Montréal.

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

Wir können zum Vergleichen die Methoden isEqual, isBefore und isAfter verwenden. In der Datum-Zeit-Arbeit verwenden wir üblicherweise den Half-Open-Ansatz, bei dem der Beginn einer Zeitspanne inklusive ist, während das Ende exklusiv ist.

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

Interval

Wenn Sie sich entschieden haben, Ihrem Projekt die Bibliothek ThreeTen-Extra hinzuzufügen, können Sie die Klasse Interval verwenden, um eine Zeitspanne zu definieren. Diese Klasse bietet Methoden zum Testen, ob das Intervall enthält , abfällt , umschließt oder überlappt andere Datumszeiten/Intervalle.

Die Interval-Klasse funktioniert für Instant-Objekte. Die Klasse Instant repräsentiert einen Moment auf der Zeitleiste in UTC mit einer Auflösung von Nanosekunden (bis zu neun (9) Ziffern eines Dezimalbruchs). 

Wir können die LocalDate in einen bestimmten Moment, den ersten Moment des Tages, einpassen, indem wir eine Zeitzone angeben, um eine ZonedDateTime zu erhalten. Von dort können wir durch Extrahieren einer Instant zu UTC zurückkehren.

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 Klassen ersetzen die störenden alten Legacy Datum-Uhrzeit-Klassen, wie Java.util.Date , Calendar , & SimpleDateFormat .

Das Projekt Joda-Time , jetzt im Wartungsmodus , empfiehlt die Migration zu den Klassen Java.time .

Weitere Informationen finden Sie unter Oracle Tutorial . In Stack Overflow finden Sie viele Beispiele und Erklärungen. Die Spezifikation lautet JSR 310 .

Wo erhalten Sie die Java.time-Klassen? 

  • Java SE 8 und SE 9 und höher
    • Eingebaut. 
    • Teil der Standard-Java-API mit einer mitgelieferten Implementierung.
    • Java 9 fügt einige kleinere Funktionen und Korrekturen hinzu.
  • Java SE 6 und SE 7
    • Ein Großteil der Java.time-Funktionalität wird in ThreeTen-Backport auf Java 6 & 7 zurückportiert.
  • Android

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

20
Basil Bourque

Das ist der richtige Weg. Kalender funktionieren auf dieselbe Weise. Das Beste, was ich Ihnen anbieten könnte (basierend auf Ihrem Beispiel), 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 lang, daher vergleichbar.

12
MBCook

Verwenden Sie Joda Time . Ich liebe diese Bibliothek und wünschte, sie würde das derzeitige schreckliche Chaos der vorhandenen Java-Date- und -Kalender-Klassen ersetzen. Es ist Datumsverarbeitung richtig gemacht.

BEARBEITEN: Es ist kein 2009 mehr und Java 8 ist schon lange auf dem Markt. Verwenden Sie in Java.time integrierte Java 8-Klassen, die auf Joda Time basieren, wie Basil Bourque unten erwähnt. In diesem Fall sollten Sie die Period-Klasse verwenden, und das Oracle-Tutorial erläutert, wie Sie es verwenden.

9
Ben Hardy

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

3
Rahul

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
0
Koray Peker

Ist es egal, welche Datumsgrenze welche ist.

Math.abs(date1.getTime() - date2.getTime()) == 
    Math.abs(date1.getTime() - dateBetween.getTime()) + Math.abs(dateBetween.getTime() - date2.getTime());
0
Radu
  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;
   }
 }
0
rashedmedisys

Ich sehe keinen Grund dafür in Java, wenn Sie es mit einer einfachen SQL-Anweisung 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 sich einfach an Ihre Bedürfnisse an und fertig.

 SELECT 
   testdate
 FROM 
   dates
 WHERE 
  testdate BETWEEN startdate AND duedate
0
nyx00

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

}