Wie lassen sich deutsche Datum-Strings vergleichen und wahlweise auf- oder absteigend sortieren?

Das deutsche Datumsformat scheint für eine Sortierung denkbar ungeeignet, da die Reihenfolge der Notation zuerst die Tage, dann die Monate und erst zum Schluss die Jahre berücksichtigt. Die Sortierung anhand zweier aufeinanderfolgender Werte von links nach rechts muss somit fehlschlagen. Das Interface Comparator macht es glücklicherweise sehr einfach, eigene Kriterien für einen Vergleich und somit auch für eine Sortierung zu schreiben. Hierzu muss seine Methode compare() konkretisiert werden.

In der main-Methode des Beispiels wird ein String-Array mit vier beliebigen Daten zuerst unsortiert und dann sortiert ausgegeben. Schließlich werden vier Mal je zwei Werte miteinander verglichen.
Den Vergleich selbst führt die Klasse DateComparator durch, die die Schnittstelle Comparator implementiert. Das Interface deklariert eine Methode compare(String arg0, String arg1) , die die beiden zu vergleichenden Objekte als Parameter entgegen nimmt. In dieser Methode muss der Vergleich der beiden Objekte so durchgeführt werden, dass bei aufsteigender Sortierung im Falle eines größeren ersten Wertes ein positiver und im Falle eines größeren zweiten Wertes ein negativer int -Wert zurück gegeben wird. Bei Gleichheit wird 0 zurück gegeben. Durch das Umkehren des Rückgabe-Vorzeichens kann somit auch das Ergebnis des Vergleichs umgekehrt werden.

Das Problem beim Vergleich von deutschen Datumswerten wird durch Umorganisieren der Datumsanteile gelöst. Hierzu werden die Anteile für Tag, Monat und Jahr jedes Einzeldatums gesondert in einem Array abgelegt. Die drei Elemente werden anschließend dergestalt neu angeordnet, dass von links nach rechts, das Jahr, der Monat und der Tag in einem String erscheinen. Die beiden zu vergleichenden, umgestellten Datumsstrings werden schließlich der Methode String.compareTo() übergeben, die einen lexikalischen Vergleich durchführt.

import java.util.Arrays;
import java.util.Comparator;

public class DatumsVergleich {

    public static void main(String[] args) {
        String[] daten = { "16.05.1703", "08.12.1925", "08.06.1925",
                "12.02.1031" };
        System.out.println("Vorher:");
        for (String s : daten) {
            System.out.println(s);
        }
        System.out.println("\nNachher:");
        Arrays.sort(daten, new DateComparator(false));
        for (String s : daten) {
            System.out.println(s);
        }
        
        DateComparator dc = new DateComparator();
        System.out.println("Vergleich von " + daten[0] + " und " + daten[1]
                + ": " + dc.compare(daten[0], daten[1]));
        System.out.println("Vergleich von " + daten[1] + " und " + daten[2]
                + ": " + dc.compare(daten[1], daten[2]));
        System.out.println("Vergleich von " + daten[2] + " und " + daten[3]
                + ": " + dc.compare(daten[2], daten[3]));
        System.out.println("Vergleich von " + daten[3] + " und " + daten[0]
                + ": " + dc.compare(daten[3], daten[0]));
    }
}

class DateComparator implements Comparator<String> {
    
    boolean sortType = true;

    public DateComparator(){
        this(true);
    }

    public DateComparator(boolean sortType){
        this.sortType = sortType;
    }

    public int compare(String arg0, String arg1) {
        String[] date0 = arg0.split("\\.");
        String[] date1 = arg1.split("\\.");
        if (date0.length != date1.length)
            throw new ClassCastException();
        String compStr0 = date0[2] + date0[1] + date0[0];
        String compStr1 = date1[2] + date1[1] + date1[0];
        if(!sortType)
            return compStr0.compareTo(compStr1) * -1;
        return compStr0.compareTo(compStr1);
    }
}

Um die Reihenfolge des Vergleichs wechseln zu können und somit z.B. eine auf- und absteigende Sortierung zu ermöglichen, deklariert die Klasse DateComparator zu diesem Zweck zwei Konstruktoren, von denen einer einen boolschen Wert beim Aufruf übergeben bekommt. Er steuert den gewünschten Vergleichsmodus: Bei Übergabe von true und als Standardwert wird ein aufsteigender Vergleich wie oben beschrieben durchgeführt. Bei Übergabe von false wird absteigend verglichen. Der nicht parametrisierte Konstruktor ruft ganz einfach den zweiten mit dem Standardwert true auf.
Der Vergleich von jeweils zwei Objekten wird in den letzten Zeilen der main-Methode gezeigt.

Das Sortieren eines Datums-Arrays benutzt die gleiche Technik. Die Java-Core-Klasse Arrays stellt eine Reihe überladener statischer Methoden zur Sortierung von Arrays bereit, die laut Dokumentation intern einen modifizierten Mergesort-Algorithmus verwenden. Die hier verwendete Variante der Methode bekommt neben dem zu sortierenden Array einfach ein Objekt des DateComparator als zweiten Parameter übergeben. Die Methode compare() muss hierbei nicht gesondert aufgerufen werden.

Wenn Ihnen javabeginners.de gefällt, freue ich mich über eine Spende an diese gemeinnützigen Organisationen.