1
votes

Existe-t-il une meilleure façon de comparer les dates

J'essaye de comparer deux dates. Les dates sont importées d'une base de données sous forme de chaînes et peuvent ou non être nulles

C'est mon code

private String compareDates(String date1, String date2)
    {
        String earliestDate = null;
//        date2 is null and date1 is null
//            earliest = “not seen yet”
        if (date2 == null && date1 == null)
        {
            earliestDate = "not seen yet";
        }
//        date2 is null and date1 is not null
//            earliest = date1
        if (date2 == null && date1 != null)
        {
            earliestDate = date1;
        }
//        date2 is not null and date1 is null
//            earliest = date2
        if (date2 != null && date1 == null)
        {
            earliestDate = date2;
        }
//        date2 is not null and date1 is not null
//            compare dates
        if (date2 != null && date1 != null)
        {
            LocalDate LDdate1 = LocalDate.parse(date1);
            LocalDate LDdate2 = LocalDate.parse(date2);
            if (LDdate1.isBefore(LDdate2) || LDdate1.isEqual(LDdate2))
            {
                earliestDate = LDdate1.toString();
            }
            else
            {
                earliestDate = LDdate2.toString();
            }
        }
        return earliestDate;
    }

Ce code me donne la sortie correcte, qui est la date la plus ancienne, ou "pas encore vu" si les deux dates sont nulles, mais je me suis demandé s'il y avait une manière meilleure / plus efficace de faire les choses.

J'imagine que l'utilisation d'une instruction switch est une option, mais est-ce que ce serait mieux simplement une manière différente de le faire?

Les données de la base de données ne contiennent qu'environ 200 dates, donc elles ne traitent pas beaucoup de données, c'est juste que je suis intéressé à écrire un meilleur code


4 commentaires

Que devrait être "la sortie correcte"?


Au lieu d'utiliser une variable earliestDate , vous pouvez simplement return la valeur que vous souhaitez renvoyer dès que vous avez décidé de ce que c'est. Ensuite, certaines des conditions if suivantes deviennent inutiles.


Quelques idées: vous pouvez changer toutes les instructions sauf la première if en else if car une seule de ces instructions est censée être saisie. Et si vous avez fait cela, vous pouvez changer le dernier if (date2 != null && date1 != null) en un simple else car tous vos cas précédents traitaient déjà l'une des dates étant null . Et vous pouvez supprimer la variable locale String earliestDate et simplement retourner directement (par exemple: return date1 au lieu de easliestDate = date1 .


@ sp00m la sortie correcte est celle des dates qui est la plus ancienne ou "pas encore vue" si les deux dates sont nulles. J'ai édité la question en conséquence.


6 Réponses :


0
votes

Que diriez-vous de ce qui suit?

private String compareDates(String date1, String date2) {
    String earliestDate;
    if (date1 == null) {
        if (date2 == null) {
            earliestDate = "not seen yet";
        }
        else {
            earliestDate = date2;
        }
    }
    else {
        if (date2 == null) {
            earliestDate = date1;
        }
        else {
            LocalDate LDdate1 = LocalDate.parse(date1);
            LocalDate LDdate2 = LocalDate.parse(date2);
            if (LDdate1.isAfter(LDdate2)) {
                earliestDate = date2;
            }
            else {
                earliestDate = date1;
            }
        }
    }
    return earliestDate;
}


4 commentaires

Merci. c'est exactement ce que je cherchais mais je ne pouvais pas décider où allaient tous les ifs et les autres. Est-ce que l'un ou l'autre est meilleur en termes d'efficacité?


@ 3rdRockSoftware dans votre code, chaque condition if est vérifiée.


J'ai compris. La vôtre est donc meilleure car il y a moins de déclarations à vérifier. Merci encore


@ 3rdRockSoftware Je suggère que vous ne voulez pas du moyen le plus efficace. Vous voulez la manière la plus lisible et la plus maintenable.



1
votes

Vous pouvez en réduire un si une condition comme celle-ci:

private String compareDates(String date1, String date2) {
    String earliestDate = "not seen yet";
    if (!StringUtils.isEmpty(date2) && !StringUtils.isEmpty(date1)) {
        LocalDate LDdate1 = LocalDate.parse(date1);
        LocalDate LDdate2 = LocalDate.parse(date2);
        if (LDdate1.isBefore(LDdate2) || LDdate1.isEqual(LDdate2)) {
            earliestDate = LDdate1.toString();
        }
        else {
            earliestDate = LDdate2.toString();
        }
    } else if (!StringUtils.isEmpty(date2) && StringUtils.isEmpty(date1)) {
        earliestDate = LDdate2;
    } else if (StringUtils.isEmpty(date2) && !StringUtils.isEmpty(date1)) {
        earliestDate = LDdate1;
    }
    return earliestDate;
} 


0 commentaires

1
votes

Vous pouvez utiliser un Comparator personnalisé, qui permet de spécifier la logique de comparaison de manière déclarative :

private String compareDates(String date1, String date2) {

    Comparator<String> c = Comparator.nullsLast(
                           Comparator.comparing(LocalDate::parse));

    int result = c.compare(date1, date2);

    return result == 0 && date1 == null ?
           "not seen yet"               :
           result <= 0                  ?
           date1                        :
           date2;
}


0 commentaires

1
votes

Il existe d'autres options qu'un tas d'énoncés if similaires.

  1. Comparator

    return Stream.of(date1, date2)
        .filter(Objects::nonNull)
        .reduce((a, b) -> LocalDate.parse(a).compareTo(LocalDate.parse(b)) <= 0 ? a : b)
        .orElse("not seen yet");
    
  2. Stream::reduce aide d'un Comparator

    if (date1 == null && date2 == null) {
        return "not seen yet";
    }
    Comparator<String> c = Comparator.nullsLast((String a, String b) -> LocalDate.parse(a).compareTo(LocalDate.parse(b)));
    return c.compare(date1, date2) <= 0 ? date1 : date2;
    

Pour moi, les deux options sont mieux lisibles que ce que vous avez maintenant, mais j'opterais pour l'option 1. On peut trouver l'utilisation de flux un peu exagérée, ce qui, dans une certaine mesure, est vrai.


0 commentaires

1
votes

Si les dates sont au format local standard et ordonnées AAAA MM JJ comme

Runtime String: 61ms
Runtime Parsing: 7361ms

pourquoi s'embêter du tout? Faites simplement une comparaison de chaînes. Environ 100 fois plus rapide et aussi plus facile.

    private static String compareDatesParse(String date1, String date2) {
        String earliestDate;
        if (date1 == null) {
            if (date2 == null) {
                earliestDate = "not seen yet";
            }
            else {
                earliestDate = date2;
            }
        }
        else {
            if (date2 == null) {
                earliestDate = date1;
            }
            else {
                LocalDate LDdate1 = LocalDate.parse(date1);
                LocalDate LDdate2 = LocalDate.parse(date2);
                if (LDdate1.isAfter(LDdate2)) {
                    earliestDate = date2;
                }
                else {
                    earliestDate = date1;
                }
            }
        }
        return earliestDate;
    }

    public static void testDateComp(){
        String[] dates = {"2020-10-30", "2020-10-29", "1990-10-30", "2021-06-01", null};
        String result = null;
        int loops = 400000;
        long start, end = 0;
        // System.out.println("Runs: " + (dates.length*dates.length*loops));


        start = System.currentTimeMillis();
        for (int i = 0; i < loops; i++) {
            for (String date1:dates) {
                for (String date2:dates) {
                    result = compareDatesStr(date1, date2);
                }
            }
        }
        end = System.currentTimeMillis();
        System.out.println("Runtime String: " + (end - start)+ "ms");

        start = System.currentTimeMillis();
        for (int i = 0; i < loops; i++) {
            for (String date1:dates) {
                for (String date2:dates) {
                    result = compareDatesParse(date1, date2);
                }
            }
        }
        end = System.currentTimeMillis();
        System.out.println("Runtime Parsing: " + (end - start) + "ms");
    }

Quelques comparaisons de performances non scientifiques:

    public static String compareDatesStr(String date1, String date2) {
        if (date1 == null)
            if (date2 == null)
                return "not seen yet";
            else
                return date2;
        else if (date2 == null)
            return date1;
        else
            return date1.compareTo(date2) > 0 ? date2 : date1;
    }

Exécutions de méthode 10MM:

"2018-01-24"


1 commentaires

Merci supernova, il ne m'était pas venu à l'esprit que les cordes étaient comparables. Cela semble être la voie à suivre.



0
votes

Les dates sont importées d'une base de données sous forme de chaînes ...

Premier point: ne faites pas ça. Récupérez vos dates en tant LocalDate dans votre base de données et gérez-les comme tels dans votre programme. Pour savoir comment récupérer un LocalDate partir d'une base de données SQL, consultez le lien en bas.

Ensuite, j'utiliserais un pipeline de flux pour trouver le premier:

    // Some example dates
    LocalDate date1 = null;
    LocalDate date2 = LocalDate.of(2020, Month.OCTOBER, 24);
    
    String earlierDate = Stream.of(date1, date2)
            .filter(Objects::nonNull)
            .min(LocalDate::compareTo)
            .map(LocalDate::toString)
            .orElse("Not seen yet");
    System.out.println(earlierDate);

Production:

2020-10-24

Lien: Question Insérez et récupérez des objets java.time.LocalDate vers / depuis une base de données SQL telle que H2


0 commentaires