web-dev-qa-db-fra.com

Comparer deux fichiers Java.util.Dates pour voir s'ils se trouvent dans le même jour

J'ai besoin de comparer deux Dates (par exemple date1 et date2) et de créer un boolean sameDay qui est vrai des deux Dates partagé le même jour, et faux s'ils ne le sont pas.

Comment puis-je faire ceci? Il semble y avoir un brouhaha de confusion ici ... et j'aimerais éviter, dans la mesure du possible, de créer d'autres dépendances au-delà du JDK.

pour clarifier: si date1 et date2 partagent la même année, le même mois et le même jour, alors sameDay est vrai, sinon il est faux. Je réalise que cela nécessite la connaissance d'un fuseau horaire ... il serait agréable de passer dans un fuseau horaire mais je peux vivre avec l'heure GMT ou l'heure locale tant que je sais quel est le comportement.

encore une fois, pour clarifier:

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
224
Jason S
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
cal1.setTime(date1);
cal2.setTime(date2);
boolean sameDay = cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) &&
                  cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR);

Notez que le "même jour" n’est pas un concept aussi simple que cela en a l'air lorsque différents fuseaux horaires peuvent être impliqués. Le code ci-dessus calculera, pour les deux dates, le jour par rapport au fuseau horaire utilisé par l'ordinateur sur lequel il est exécuté. Si ce n'est pas ce dont vous avez besoin, vous devez passer le ou les fuseaux horaires pertinents aux appels Calendar.getInstance(), une fois que vous avez décidé de ce que vous entendez par "le même jour".

Et oui, le LocalDate de Joda Time rendrait le tout beaucoup plus propre et plus facile (bien que les mêmes difficultés impliquant des fuseaux horaires soient présentes).

387
Michael Borgwardt

Que diriez-vous:

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

Vous pouvez également définir le fuseau horaire sur SimpleDateFormat, si nécessaire.

318
Binil Thomas

J'utilise le paquet "Apache commons lang" pour faire cela (à savoir org.Apache.commons.lang.time.DateUtils )

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

Vous pouvez éviter les dépendances externes et l'impact négatif de l'utilisation de Calendar en calculant le nombre de jours du calendrier Julien pour chacune des dates, puis en les comparant:

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

Joda-Time

En ce qui concerne l'ajout d'une dépendance, je crains que les fichiers Java.util.Date & .Calendar ne soient vraiment si mauvais que la première chose que je fais à tout nouveau projet consiste à ajouter la bibliothèque Joda-Time. Dans Java 8, vous pouvez utiliser le nouveau package Java.time, inspiré de Joda-Time.

Le noyau de Joda-Time est la classe DateTime . Contrairement à Java.util.Date, il comprend le fuseau horaire qui lui est attribué ( DateTimeZone ). Lors de la conversion de j.u.Date, attribuez une zone.

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

LocalDate

Un moyen de vérifier si deux dates-heure atterrissent à la même date consiste à convertir en LocalDate objets.

Cette conversion dépend du fuseau horaire attribué. Pour comparer des objets LocalDate, ils doivent avoir été convertis avec la même zone.

Voici une petite méthode d'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;
}

Mieux vaut un autre argument, spécifiant le fuseau horaire plutôt que de supposer que le fuseau horaire du premier objet DateTime doit être utilisé.

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

Représentation de chaîne

Une autre approche consiste à créer une représentation sous forme de chaîne de la partie date de chaque date-heure, puis à comparer les chaînes.

Encore une fois, le fuseau horaire attribué est crucial.

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;

Durée du temps

La solution généralisée consiste à définir un intervalle de temps, puis à demander si cet intervalle contient votre cible. Cet exemple de code est dans Joda-Time 2.4. Notez que les classes liées à "minuit" sont obsolètes. Utilisez plutôt la méthode withTimeAtStartOfDay. Joda-Time propose trois classes pour représenter une période de temps de différentes manières: intervalle, période et durée.

Utilisation de l'approche "Half-Open" où le début de la plage est inclusif et la fin exclusive.

Le fuseau horaire de la cible peut être différent du fuseau horaire de l'intervalle.

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 et versions ultérieures sont livrés avec le framework Java.time . Inspiré de Joda-Time, défini par la JSR 310 et étendu par le projet ThreeTen-Extra. Voir Tutoriel .

Les fabricants de Joda-Time nous ont tous demandé de passer à Java.time dès que possible. En attendant, Joda-Time reste un projet activement maintenu. Mais attendez-vous à ce que les travaux futurs se produisent uniquement dans Java.time et ThreeTen-Extra plutôt que dans Joda-Time.

Pour résumer Java.time en quelques mots… Un Instant est un moment sur la timeline en UTC. Appliquez un fuseau horaire (ZoneId) pour obtenir un objet ZonedDateTime. Pour sortir de la chronologie, pour avoir une idée vague et indéfinie d'une date-heure, utilisez les classes "locales": LocalDateTime, LocalDate, LocalTime.

La logique présentée dans la section Joda-Time de cette réponse s’applique à Java.time.

L'ancienne classe Java.util.Date a une nouvelle méthode toInstant pour la conversion en Java.time.

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

Déterminer une date nécessite un fuseau horaire.

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

Nous appliquons cet objet de fuseau horaire à Instant pour obtenir un ZonedDateTime. À partir de cela, nous extrayons une valeur de date uniquement (LocalDate), car notre objectif est de comparer les dates (et non les heures, les minutes, etc.).

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

Faites la même chose pour le deuxième objet Java.util.Date dont nous avons besoin pour la comparaison. Je vais simplement utiliser le moment actuel à la place.

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

Utilisez la méthode spéciale isEqual pour tester la même valeur de date.

Boolean sameDate = localDate1.isEqual( localDate2 );
18
Basil Bourque

Convertissez les dates en Java 8 Java.time.LocalDate comme indiqué ici .

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));
6
Istvan
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);
    }
5
evya

POUR Android UTILISATEURS:

Vous pouvez utiliser DateUtils.isToday(dateMilliseconds) pour vérifier si la date donnée est le jour actuel ou non.

Référence de l'API: https://developer.Android.com/reference/Android/text/format/DateUtils.html#isToday (long)

4
Hemant Kaushik

Java 8

Si vous utilisez Java 8 dans votre projet et comparez Java.sql.Timestamp, vous pouvez utiliser la classe LocalDate:

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

Si vous utilisez Java.util.Date, jetez un oeil à la réponse de Istvan qui est moins ambiguë.

4
amanteaux

en plus de la solution 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;
}

usage

    isOnSameDay(date1,date2,date3 ...);
//or 
    isOnSameDay(mydates);
1
Fareed Alnamrouti

Pour les développeurs Kotlin, il s'agit de la version permettant de comparer les chaînes formatées:

val sdf = SimpleDateFormat("yyMMdd")
if (sdf.format(date1) == sdf.format(date2)) {
    // same day
}

Ce n'est pas la meilleure façon, mais c'est court et efficace.

0
Micer
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;
}
0
jadeoti