Wie finde ich die Anzahl der Jahre zwischen zwei Daten?

Lesezeit: 3 Minuten

Benutzer-Avatar
Micha Hainline

Ich versuche, ein Alter in Jahren von einem bestimmten Datum an zu bestimmen. Kennt jemand einen sauberen Weg, dies in Android zu tun? Ich habe natürlich die Java-API zur Verfügung, aber die direkte Java-API ist ziemlich schwach, und ich hatte gehofft, dass Android etwas hat, das mir hilft.

BEARBEITEN: Die mehrfachen Empfehlungen zur Verwendung von Joda Time in Android beunruhigen mich ein wenig aufgrund von Android Java – Joda Date ist langsam und verwandte Bedenken. Außerdem ist es wahrscheinlich übertrieben, eine nicht mit der Plattform gelieferte Bibliothek für etwas dieser Größe zu verwenden.

  • Eine ähnliche Frage: stackoverflow.com/questions/1116123/…

    – Jeha

    26. Oktober 2011 um 17:23 Uhr

  • Sowohl das Erbe Date/Calendar Klassen und Joda-Zeit wurden durch die ersetzt java.time Klassen. Die meisten von den java.time Funktionalität ist in Java 6 & Java 7 zurückportiert ThreeTen-Backport Projekt. Weiter angepasst für frühere Android in der ThreeTenABP Projekt. Sehen Wie benutzt man ThreeTenABP….

    – Basilikum Bourque

    1. Oktober 2018 um 0:40 Uhr

Benutzer-Avatar
sinuhepop

import java.util.Calendar;
import java.util.Locale;
import static java.util.Calendar.*;
import java.util.Date;

public static int getDiffYears(Date first, Date last) {
    Calendar a = getCalendar(first);
    Calendar b = getCalendar(last);
    int diff = b.get(YEAR) - a.get(YEAR);
    if (a.get(MONTH) > b.get(MONTH) || 
        (a.get(MONTH) == b.get(MONTH) && a.get(DATE) > b.get(DATE))) {
        diff--;
    }
    return diff;
}

public static Calendar getCalendar(Date date) {
    Calendar cal = Calendar.getInstance(Locale.US);
    cal.setTime(date);
    return cal;
}

Notiz: Wie Ole VV bemerkte, funktioniert dies nicht mit Daten vor Christus, da der Kalender funktioniert.

  • Was sind die Konstanten MONTH, YEAR und DATE ??

    – Chris Sim

    16. Juli 2013 um 9:57 Uhr

  • @ChrisSim: Sie sind statische Importe von Calendar.MONTH und so weiter.

    – sinuhepop

    16. Juli 2013 um 10:54 Uhr

  • Ich denke, statt DATE sollte es DAY_OF_MONTH sein.

    – jiahao

    19. Mai 2014 um 10:37 Uhr

  • @jiahao: Sie sind Synonyme

    – sinuhepop

    19. Mai 2014 um 12:49 Uhr

  • .get(YEAR) und .get(MONTH) sind jetzt veraltet, glaube ich. Eventuell bearbeiten?

    Benutzer3864935

    7. August 2015 um 9:32 Uhr

Benutzer-Avatar
Basil Bourque

tl;dr

ChronoUnit.YEARS.between( 
    LocalDate.of( 2010 , 1 , 1 ) , 
    LocalDate.now( ZoneId.of( "America/Montreal" ) ) 
)

java.time

Die alten Date-Time-Klassen sind wirklich schlecht, so schlecht, dass sowohl Sun als auch Oracle zugestimmt haben, sie durch die java.time-Klassen zu ersetzen. Wenn Sie überhaupt nennenswerte Arbeit mit Datums-/Uhrzeitwerten leisten, lohnt es sich, Ihrem Projekt eine Bibliothek hinzuzufügen. Die Joda-Time-Bibliothek war sehr erfolgreich und empfehlenswert, befindet sich aber jetzt im Wartungsmodus. Das Team empfiehlt die Migration zu den java.time-Klassen.

Ein Großteil der java.time-Funktionalität wurde in Java 6 & 7 zurückportiert ThreeTen-Backport und weiter angepasst Android in ThreeTenABP (sehen Wie benutzt man…).

LocalDate start = LocalDate.of( 2010 , 1 , 1 ) ;
LocalDate stop = LocalDate.now( ZoneId.of( "America/Montreal" ) );
long years = java.time.temporal.ChronoUnit.YEARS.between( start , stop );

Dump auf Konsole.

System.out.println( "start: " + start + " | stop: " + stop + " | years: " + years ) ;

Beginn: 01.01.2010 | Stopp: 06.09.2016 | Jahre: 6


Tabelle aller Datums- und Uhrzeittypen in Java, sowohl modern als auch veraltet


Um java.time

Das java.time Framework ist in Java 8 und höher integriert. Diese Klassen ersetzen die lästigen alten Erbe Datum-Zeit-Klassen wie z java.util.Date, Calendar& SimpleDateFormat.

Das Joda-Zeit Projekt, jetzt in Wartungsmodusrät zur Migration in die java.time Klassen.

Weitere Informationen finden Sie unter Oracle-Tutorial. Und durchsuchen Sie Stack Overflow nach vielen Beispielen und Erklärungen. Spezifikation ist JSR310.

Sie dürfen umtauschen java.time Objekte direkt mit Ihrer Datenbank. Verwenden ein JDBC-Treiber gemäß JDBC 4.2 oder später. Keine Notwendigkeit für Saiten, keine Notwendigkeit für java.sql.* Klassen.

Wo erhalte ich die java.time-Klassen?

  • Java SE 8, Java SE 9, JavaSE 10, Java SE 11und höher – Teil der Standard-Java-API mit einer gebündelten Implementierung.
    • Java 9 fügt einige kleinere Funktionen und Korrekturen hinzu.
  • Java SE 6 und Java SE 7
    • Der Großteil der java.time-Funktionalität wurde in Java 6 & 7 zurückportiert ThreeTen-Backport.
  • Android
    • Spätere Versionen von Android-Bundle-Implementierungen der java.time Klassen.
    • Für frühere Android-Versionen (<26) ist die ThreeTenABP Projekt passt ThreeTen-Backport (oben erwähnt). Sehen Wie benutzt man ThreeTenABP….

Tabelle, welche java.time-Bibliothek mit welcher Java- oder Android-Version verwendet werden soll

Ich würde empfehlen, die großartigen zu verwenden Joda-Zeit Bibliothek für alles, was mit Datum in Java zu tun hat.

Für Ihre Bedürfnisse können Sie die verwenden Years.yearsBetween() Methode.

  • Ich habe Joda viel dieses letzte Projekt verwendet. Es ist wirklich übertrieben in Bezug auf die Einrichtung …

    – StarWind0

    26. September 2015 um 9:00 Uhr

  • Nur zur Ausführung: public int getYears(org.java.util.Date time) { org.joda.time.DateTime now = org.joda.time.DateTime.now(); org.joda.time.DateTime then = new org.joda.time.DateTime(time.getTime()); return org.joda.time.Years.yearsBetween(now, then).getYears(); }

    – Nielsvh

    6. Oktober 2015 um 16:05 Uhr

Ich kann anscheinend noch keinen Kommentar abgeben, aber ich denke, Sie können einfach den DAY_OF_YEAR zum Training verwenden, wenn Sie die Jahre um eins anpassen sollten (kopiert und modifiziert von der aktuell besten Antwort).

public static int getDiffYears(Date first, Date last) {
    Calendar a = getCalendar(first);
    Calendar b = getCalendar(last);
    int diff = b.get(Calendar.YEAR) - a.get(Calendar.YEAR);
    if (a.get(Calendar.DAY_OF_YEAR) > b.get(Calendar.DAY_OF_YEAR)) {
        diff--;
    }
    return diff;
}

public static Calendar getCalendar(Date date) {
    Calendar cal = Calendar.getInstance(Locale.US);
    cal.setTime(date);
    return cal;
}

In ähnlicher Weise könnten Sie wahrscheinlich einfach die ms-Darstellungen der Zeit unterscheiden und durch die Anzahl der ms in einem Jahr dividieren. Halten Sie einfach alles in Longs und das sollte die meiste Zeit gut genug sein (Schaltjahre, autsch), aber es hängt von Ihrer Anwendung für die Anzahl der Jahre ab und wie leistungsfähig diese Funktion sein muss, ob es diese Art von Hack wert wäre.

Ich weiß, Sie haben nach einer sauberen Lösung gefragt, aber hier sind einmal zwei schmutzige:

        static void diffYears1()
{
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
    Calendar calendar1 = Calendar.getInstance(); // now
    String toDate = dateFormat.format(calendar1.getTime());

    Calendar calendar2 = Calendar.getInstance();
    calendar2.add(Calendar.DAY_OF_YEAR, -7000); // some date in the past
    String fromDate = dateFormat.format(calendar2.getTime());

    // just simply add one year at a time to the earlier date until it becomes later then the other one 
    int years = 0;
    while(true)
    {
        calendar2.add(Calendar.YEAR, 1);
        if(calendar2.getTimeInMillis() < calendar1.getTimeInMillis())
            years++;
        else
            break;
    }

    System.out.println(years + " years between " + fromDate + " and " + toDate);
}

static void diffYears2()
{
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
    Calendar calendar1 = Calendar.getInstance(); // now
    String toDate = dateFormat.format(calendar1.getTime());

    Calendar calendar2 = Calendar.getInstance();
    calendar2.add(Calendar.DAY_OF_YEAR, -7000); // some date in the past
    String fromDate = dateFormat.format(calendar2.getTime());

    // first get the years difference from the dates themselves
    int years = calendar1.get(Calendar.YEAR) - calendar2.get(Calendar.YEAR);
    // now make the earlier date the same year as the later
    calendar2.set(Calendar.YEAR, calendar1.get(Calendar.YEAR));
    // and see if new date become later, if so then one year was not whole, so subtract 1 
    if(calendar2.getTimeInMillis() > calendar1.getTimeInMillis())
        years--;

    System.out.println(years + " years between " + fromDate + " and " + toDate);
}

Folgendes halte ich für eine bessere Methode:

public int getYearsBetweenDates(Date first, Date second) {
    Calendar firstCal = GregorianCalendar.getInstance();
    Calendar secondCal = GregorianCalendar.getInstance();

    firstCal.setTime(first);
    secondCal.setTime(second);

    secondCal.add(Calendar.DAY_OF_YEAR, 1 - firstCal.get(Calendar.DAY_OF_YEAR));

    return secondCal.get(Calendar.YEAR) - firstCal.get(Calendar.YEAR);
}

BEARBEITEN

Abgesehen von einem Fehler, den ich behoben habe, funktioniert diese Methode nicht gut mit Schaltjahren. Hier ist eine vollständige Testsuite. Ich denke, Sie sind besser dran, die akzeptierte Antwort zu verwenden.

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

class YearsBetweenDates {
    public static int getYearsBetweenDates(Date first, Date second) {
        Calendar firstCal = GregorianCalendar.getInstance();
        Calendar secondCal = GregorianCalendar.getInstance();

        firstCal.setTime(first);
        secondCal.setTime(second);

        secondCal.add(Calendar.DAY_OF_YEAR, 1 - firstCal.get(Calendar.DAY_OF_YEAR));

        return secondCal.get(Calendar.YEAR) - firstCal.get(Calendar.YEAR);
    }

    private static class TestCase {
        public Calendar date1;
        public Calendar date2;
        public int expectedYearDiff;
        public String comment;

        public TestCase(Calendar date1, Calendar date2, int expectedYearDiff, String comment) {
            this.date1 = date1;
            this.date2 = date2;
            this.expectedYearDiff = expectedYearDiff;
            this.comment = comment;
        }
    }

    private static TestCase[] tests = {
        new TestCase(
                new GregorianCalendar(2014, Calendar.JULY, 15),
                new GregorianCalendar(2015, Calendar.JULY, 15),
                1,
                "exactly one year"),
        new TestCase(
                new GregorianCalendar(2014, Calendar.JULY, 15),
                new GregorianCalendar(2017, Calendar.JULY, 14),
                2,
                "one day less than 3 years"),
        new TestCase(
                new GregorianCalendar(2015, Calendar.NOVEMBER, 3),
                new GregorianCalendar(2017, Calendar.MAY, 3),
                1,
                "a year and a half"),
        new TestCase(
                new GregorianCalendar(2016, Calendar.JULY, 15),
                new GregorianCalendar(2017, Calendar.JULY, 15),
                1,
                "leap years do not compare correctly"),
    };

    public static void main(String[] args) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        for (TestCase t : tests) {
            int diff = getYearsBetweenDates(t.date1.getTime(), t.date2.getTime());
            String result = diff == t.expectedYearDiff ? "PASS" : "FAIL";
            System.out.println(t.comment + ": " +
                    df.format(t.date1.getTime()) + " -> " +
                    df.format(t.date2.getTime()) + " = " +
                    diff + ": " + result);
        }
    }
}

Benutzer-Avatar
Bienenfutter

praktisch, wenn Sie Kalender, Gebietsschema oder externe Bibliothek nicht einschränken möchten:

private static SimpleDateFormat YYYYMMDD = new SimpleDateFormat("yyyyMMdd");
public static Integer toDate8d(Date date) {
    String s;
    synchronized (YYYYMMDD) { s = YYYYMMDD.format(date); }  // SimpleDateFormat thread safety
    return Integer.valueOf(s);
}
public static Integer yearDiff(Date pEarlier, Date pLater) {
    return (toDate8d(pLater) - toDate8d(pEarlier)) / 10000;
}

  • Irgendein Vorteil gegenüber dem Einzeiler von Basil Bourque? Ich empfehle, sich von der Form fernzuhalten SImpleDateFormat, es ist ein notorischer Unruhestifter einer Klasse. Und die Umwandlung in ein int der Zahlenwert, wenn das keinen Sinn macht? Mag ich nicht.

    – Ole VV

    27. Mai 2021 um 17:52 Uhr

  • Der Vergleich mit Basil ist hauptsächlich die Lernkurve von java.time, denn nicht jeder hätte viel Zeit zum Lernen; SimpleDateFormat ist nur so konzipiert, dass es minimal ist und nicht für Multithreading, so dass viele Leute auf Probleme stoßen können, wenn sie sich dessen nicht bewusst sind. Dies kann leicht durch einen einfachen synchronisierten Block gelöst werden; Diese int-Lösung verschiebt die logische Berechnung von einer Teilbibliothek zu einer einfachen mathematischen Berechnung, die in der Tat nicht komplex ist. Dies ist der geringste Nutzen der Bibliothek, es muss nicht einmal die Kalenderklasse einbezogen werden. dies ist intuitiv und leicht verständlich.

    – Bienenfutter

    12. September 2021 um 12:23 Uhr

1174950cookie-checkWie finde ich die Anzahl der Jahre zwischen zwei Daten?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy