web-dev-qa-db-fra.com

Java: comment vérifier si une date est comprise dans une certaine plage?

J'ai une série de plages avec des dates de début et de fin. Je veux vérifier si une date est dans cette plage.

Date.before () et Date.after () semblent être un peu difficiles à utiliser. Ce dont j'ai vraiment besoin, c'est quelque chose comme ce pseudocode:

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

Je ne sais pas si c'est pertinent, mais les dates que je tire de la base de données ont des horodatages. 

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

Cela ne me semble pas si gênant. Notez que je l’ai écrit de cette façon au lieu de 

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

donc cela fonctionnerait même si testDate était exactement égal à l'un des cas finaux.

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

À moitié ouvert

Le travail date-heure utilise couramment l’approche «semi-ouverte» pour définir une période. Le début est inclusif tandis que la fin est exclusif. Ainsi, une semaine commençant un lundi va jusqu'au lundi suivant, sans l'inclure. 

Java.time

Java 8 et versions ultérieures sont livrés avec le framework Java.time intégré. Fournit les anciennes classes problématiques, notamment Java.util.Date/.Calendar et SimpleDateFormat. Inspiré par la bibliothèque à succès Joda-Time. Défini par JSR 310. Étendu par le projet ThreeTen-Extra.

Un Instant est un moment sur la ligne de temps dans UTC avec une résolution en nanosecondes. 

Instant

Convertissez vos objets Java.util.Date en objets Instant. 

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

Si vous obtenez des objets Java.sql.Timestamp via JDBC à partir d'une base de données, convertissez-le en Java.time.Instant de manière similaire. Un horodatage Java.sql est déjà en UTC, vous n'avez donc pas à vous soucier des fuseaux horaires.

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

Obtenez le moment actuel pour la comparaison. 

Instant now = Instant.now();

Comparez en utilisant les méthodes isBefore, isAfter et égal. 

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

LocalDate

Peut-être que vous voulez travailler uniquement avec la date, pas l'heure.

La classe LocalDate représente une valeur de date seulement, sans heure et sans fuseau horaire.

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

Pour obtenir la date actuelle, spécifiez un fuseau horaire. À tout moment, la date du jour varie selon le fuseau horaire. Par exemple, un nouveau jour se lève plus tôt à Paris qu’à Montréal.

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

Nous pouvons utiliser les méthodes isEqual, isBefore et isAfter pour comparer. Dans le travail date-heure, nous utilisons couramment l'approche semi-ouverte dans laquelle le début d'un intervalle de temps est inclusif alors que la fin est exclusif.

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

Interval

Si vous choisissez d'ajouter la bibliothèque ThreeTen-Extra à votre projet, vous pouvez utiliser la classe Interval pour définir une durée. Cette classe propose des méthodes pour tester si l’intervalle contient , bute , entoure , ou chevauche autres dates/intervalles.

La classe Interval fonctionne sur les objets Instant. La classe Instant représente un moment sur la ligne temporelle en UTC avec une résolution de nanosecondes (jusqu'à neuf (9) chiffres d'une fraction décimale). 

Nous pouvons ajuster la LocalDate à un moment spécifique, le premier moment de la journée, en spécifiant un fuseau horaire pour obtenir une ZonedDateTime. De là, nous pouvons revenir à UTC en extrayant une 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 );

À propos de Java.time

Le cadre Java.time est intégré à Java 8 et versions ultérieures. Ces classes supplantent les anciennes classes gênantes héritées _ date-heure telles que Java.util.Date , Calendar _, & SimpleDateFormat .

Le projet Joda-Time , désormais en mode maintenance , conseille de migrer vers les classes Java.time .

Pour en savoir plus, consultez le Tutoriel Oracle . Et recherchez Stack Overflow pour de nombreux exemples et explications. La spécification est JSR 310 .

Où obtenir les classes Java.time? 

  • Java SE 8 et SE 9 et versions ultérieures
    • Intégré. 
    • Une partie de l'API Java standard avec une implémentation fournie.
    • Java 9 ajoute quelques fonctionnalités et corrections mineures.
  • Java SE 6 et SE 7
    • Une grande partie de la fonctionnalité Java.time est rétroportée vers Java 6 et 7 dans ThreeTen-Backport .
  • Android

Le projet ThreeTen-Extra étend Java.time avec des classes supplémentaires. Ce projet est un terrain d’essai pour d’éventuels ajouts à Java.time. Vous pouvez y trouver des classes utiles telles que Interval _, YearWeek , YearQuarter _ et plus _.

20
Basil Bourque

C'est la bonne façon. Les calendriers fonctionnent de la même manière. Le mieux que je puisse vous offrir (d'après votre exemple) est le suivant:

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

Date.getTime () renvoie le nombre de millisecondes écoulées depuis le 01/01/1970 00:00:00 GMT. Il est long et facilement comparable.

12
MBCook

Pensez à utiliser Joda Time . J'adore cette bibliothèque et j'aimerais qu'elle remplace les horribles désordres actuels que sont les classes Java Date et Calendar existantes. C'est la manipulation de la date bien faite.

EDIT: Ce n'est plus 2009, et Java 8 existe depuis des lustres. Utilisez les classes Java 8 construites en Java.time qui sont basées sur Joda Time, comme le dit Basil Bourque ci-dessous. Dans ce cas, vous voudrez utiliser la classe Period, et voici le tutoriel d'Oracle sur la façon de l'utiliser.

9
Ben Hardy

Une méthode simple consiste à convertir les dates en millisecondes après le 1er janvier 1970 (utilisez Date.getTime ()), puis à comparer ces valeurs.

3
Rahul

tu peux utiliser comme ça 

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

Peu importe quelle date est la limite.

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

Je ne vois pas la raison de le faire en Java lorsque vous pouvez le faire avec une simple instruction SQL.

Comme dans cette question/réponse:

Requête Postgresql entre les périodes

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

Adaptez-vous simplement à vos besoins et finissez… .. Quelque chose comme:

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

C'était plus clair pour moi,

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

}
0