Berechnung von Tagen zwischen zwei Daten mit Java

150

Ich möchte ein Java-Programm, das Tage zwischen zwei Daten berechnet.

  1. Geben Sie das erste Datum ein (deutsche Notation; mit Leerzeichen: "TT MM JJJJ")
  2. Geben Sie das zweite Datum ein.
  3. Das Programm sollte die Anzahl der Tage zwischen den beiden Daten berechnen.

Wie kann ich Schaltjahre und Sommerzeit einbeziehen?

Mein Code:

import java.util.Calendar;
import java.util.Date;
import java.util.Scanner;

public class NewDateDifference {

    public static void main(String[] args) {

        System.out.print("Insert first date: ");
        Scanner s = new Scanner(System.in);
        String[] eingabe1 = new String[3];

        while (s.hasNext()) {
            int i = 0;
            insert1[i] = s.next();
            if (!s.hasNext()) {
                s.close();
                break;
            }
            i++;
        }

        System.out.print("Insert second date: ");
        Scanner t = new Scanner(System.in);
        String[] insert2 = new String[3];

        while (t.hasNext()) {
            int i = 0;
            insert2[i] = t.next();
            if (!t.hasNext()) {
                t.close();
                break;
            }
            i++;
        }

        Calendar cal = Calendar.getInstance();

        cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(insert1[0]));
        cal.set(Calendar.MONTH, Integer.parseInt(insert1[1]));
        cal.set(Calendar.YEAR, Integer.parseInt(insert1[2]));
        Date firstDate = cal.getTime();

        cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(insert2[0]));
        cal.set(Calendar.MONTH, Integer.parseInt(insert2[1]));
        cal.set(Calendar.YEAR, Integer.parseInt(insert2[2]));
        Date secondDate = cal.getTime();


        long diff = secondDate.getTime() - firstDate.getTime();

        System.out.println ("Days: " + diff / 1000 / 60 / 60 / 24);
    }
}
user3025448
quelle
Was funktioniert nicht? Stürzt es ab? Gibt es Ihnen falsche Zahlen?
Jens108
Wo ist die Deklaration des Arrays: insert1?
Rhys
1
insert1 = eingabe1 auf Deutsch :)
peter.petrov
@ peter.petrov Ah, ich verstehe!
Rhys
Ich denke, er hat ein Problem mit mmund MM: P
Sage

Antworten:

229

UPDATE: Die ursprüngliche Antwort von 2013 ist jetzt veraltet, da einige der Klassen ersetzt wurden. Die neue Methode besteht darin, die neuen java.timeKlassen zu verwenden.

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd MM yyyy");
String inputString1 = "23 01 1997";
String inputString2 = "27 04 1997";

try {
    LocalDateTime date1 = LocalDate.parse(inputString1, dtf);
    LocalDateTime date2 = LocalDate.parse(inputString2, dtf);
    long daysBetween = Duration.between(date1, date2).toDays();
    System.out.println ("Days: " + daysBetween);
} catch (ParseException e) {
    e.printStackTrace();
}

Beachten Sie, dass diese Lösung die Anzahl der tatsächlichen 24-Stunden-Tage und nicht die Anzahl der Kalendertage angibt. Für letzteres verwenden

long daysBetween = ChronoUnit.DAYS.between(date1, date2)

Ursprüngliche Antwort (veraltet ab Java 8)

Sie führen mit Ihren Strings einige Konvertierungen durch, die nicht erforderlich sind. Es gibt eine SimpleDateFormatKlasse dafür - versuchen Sie Folgendes:

SimpleDateFormat myFormat = new SimpleDateFormat("dd MM yyyy");
String inputString1 = "23 01 1997";
String inputString2 = "27 04 1997";

try {
    Date date1 = myFormat.parse(inputString1);
    Date date2 = myFormat.parse(inputString2);
    long diff = date2.getTime() - date1.getTime();
    System.out.println ("Days: " + TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS));
} catch (ParseException e) {
    e.printStackTrace();
}

EDIT: Da es einige Diskussionen über die Richtigkeit dieses Codes gegeben hat: Es kümmert sich in der Tat um Schaltjahre. Die TimeUnit.DAYS.convertFunktion verliert jedoch an Genauigkeit, da Millisekunden in Tage konvertiert werden (weitere Informationen finden Sie im verknüpften Dokument). Wenn dies ein Problem ist, diffkann es auch von Hand konvertiert werden:

float days = (diff / (1000*60*60*24));

Beachten Sie, dass dies ein floatWert ist, nicht unbedingt ein int.

jens108
quelle
40
Dies ist eine schlechte Implementierung, die Schaltjahre nicht richtig berücksichtigt.
Groovy Ed
3
TimeUnit.DAYS.convert (diff, TimeUnit.MILLISECONDS)); <3
Guihgo
3
@GroovyEd Nach dem, was ich getestet habe, scheint dieser Code kein Problem mit Schaltjahren zu haben. Bitte beachten Sie, dass TimeUnit.Days.convert () verbleibende Einheiten ignoriert, z. B. die Konvertierung von 999 Millisekunden in Sekunden ergibt 0. Dies bedeutet, dass Sie einen Tag weniger erhalten, wenn Sie new Date () als eines der Date-Objekte verwenden
Klitos G.
3
Es funktioniert auch für Schaltjahre. Überprüfen Sie diese String inputString1 = "28 2 2016"; String inputString2 = "1 3 2016";ans: 2
Rohit Gaikwad
10
Ich glaube, dass dies für Schaltjahre richtig funktioniert, aber es bringt die Sommerzeit durcheinander. Wenn Ihr Gebietsschema Sommerzeit hat, gibt es jedes Jahr einen Tag mit 23 Stunden und einen Tag mit 25 Stunden. Diese Lösung geht fälschlicherweise davon aus, dass jeder Tag 24 Stunden hat. Es gibt daher die falsche Antwort für jeden Zeitraum, der während der Sommerzeit beginnt und während der Sommerzeit endet. VERWENDEN SIE DIESE LÖSUNG NICHT - es gibt bessere Möglichkeiten.
Dawood ibn Kareem
100

Einfachster Weg:

public static long getDifferenceDays(Date d1, Date d2) {
    long diff = d2.getTime() - d1.getTime();
    return TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);
}
Bart
quelle
7
Nun, im Grunde ist dies die gleiche wie die derzeit beste Antwort , obwohl diese Antwort sie als Funktion bereitstellt.
Andrew T.
16
Beachten Sie, dass dies nur zählt, wenn das Zeitintervall zwischen zwei Daten größer als 24 Stunden ist (ziemlich offensichtlich aus dem Code), alsogetDifferenceDays(11PM, 4 AM nextday) == 0
ReDetection
1
Diese Implementierung dauert den letzten Tag wie heute. Wenn ich zum Beispiel das Programm mit d1 = heute und d2 = gestern
starte
1
@Nav das liegt daran, dass es im Juni 30 Tage gibt.
Dawood ibn Kareem
1
Diese Antwort ist falsch. Die Sommerzeit wird nicht richtig behandelt. Verwenden Sie es nicht, wenn Sie korrekte Ergebnisse wünschen.
Dawood ibn Kareem
89

In Java 8 können Sie dies mit LocalDateund erreichen DateTimeFormatter. Aus dem Javadoc von LocalDate:

LocalDate ist ein unveränderliches Datum-Uhrzeit-Objekt, das ein Datum darstellt, das häufig als Jahr-Monat-Tag angesehen wird.

Und das Muster kann mit konstruiert werden DateTimeFormatter. Hier ist der Javadoc und die relevanten Musterzeichen, die ich verwendet habe:

Symbol - Bedeutung - Darstellung - Beispiele

y - Jahr der Ära - Jahr - 2004; 04

M / L - Monat des Jahres - Nummer / Text - 7; 07; Jul; Juli; J.

d - Tag des Monats - Nummer - 10

Hier ist das Beispiel:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

public class Java8DateExample {
    public static void main(String[] args) throws IOException {
        final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MM yyyy");
        final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        final String firstInput = reader.readLine();
        final String secondInput = reader.readLine();
        final LocalDate firstDate = LocalDate.parse(firstInput, formatter);
        final LocalDate secondDate = LocalDate.parse(secondInput, formatter);
        final long days = ChronoUnit.DAYS.between(firstDate, secondDate);
        System.out.println("Days between: " + days);
    }
}

Beispiel für eine Eingabe / Ausgabe mit neuerer letzter:

23 01 1997
27 04 1997
Days between: 94

Mit neueren zuerst:

27 04 1997
23 01 1997
Days between: -94

Nun, Sie könnten es als Methode auf einfachere Weise tun:

public static long betweenDates(Date firstDate, Date secondDate) throws IOException
{
    return ChronoUnit.DAYS.between(firstDate.toInstant(), secondDate.toInstant());
}
mkobit
quelle
4
Exzellentes Beispiel. Dies berücksichtigt automatisch das Schaltjahr. Wenn Sie 1991 und 1992 (Schaltjahr) überprüft haben, wird es korrekt berechnet. Perfekt!
Woahguy
Gute Nutzung der Standardbibliothek.
Dieresys
Dies sollte die aktuell akzeptierte Antwort sein. Die Standardnutzung der Bibliothek und die Berücksichtigung von Schaltjahren und Sommerzeit sind kein Problem.
Pehmolelu
3
Dies ist die aktuelle / moderne Antwort (die anderen sind veraltet). Es berücksichtigt auch die Sommerzeit (DST). Für die Verwendung unter Java 6 oder 7 erhalten Sie ThreeTen Backport . Auf nicht neuem Android ThreeTenABP .
Ole VV
Sommerzeit wird nicht berücksichtigt
Alex
63

Die meisten / alle Antworten verursachten Probleme, als die Sommerzeit kam. Hier ist unsere Arbeitslösung für alle Daten ohne Verwendung von JodaTime. Es werden Kalenderobjekte verwendet:

public static int daysBetween(Calendar day1, Calendar day2){
    Calendar dayOne = (Calendar) day1.clone(),
            dayTwo = (Calendar) day2.clone();

    if (dayOne.get(Calendar.YEAR) == dayTwo.get(Calendar.YEAR)) {
        return Math.abs(dayOne.get(Calendar.DAY_OF_YEAR) - dayTwo.get(Calendar.DAY_OF_YEAR));
    } else {
        if (dayTwo.get(Calendar.YEAR) > dayOne.get(Calendar.YEAR)) {
            //swap them
            Calendar temp = dayOne;
            dayOne = dayTwo;
            dayTwo = temp;
        }
        int extraDays = 0;

        int dayOneOriginalYearDays = dayOne.get(Calendar.DAY_OF_YEAR);

        while (dayOne.get(Calendar.YEAR) > dayTwo.get(Calendar.YEAR)) {
            dayOne.add(Calendar.YEAR, -1);
            // getActualMaximum() important for leap years
            extraDays += dayOne.getActualMaximum(Calendar.DAY_OF_YEAR);
        }

        return extraDays - dayTwo.get(Calendar.DAY_OF_YEAR) + dayOneOriginalYearDays ;
    }
}
John Leehey
quelle
handhabt Sommerzeitschalter gut
Ravi Sanwal
1
+1 für die Antwort möchten jedoch hinzufügen, dass wir die Calendar dayOne = (Calendar) day1.clone(), dayTwo = (Calendar) day2.clone();Zeilen benötigen , da sie sicherstellen, dass die ursprünglichen Kalenderwerte nicht überschrieben werden. Ich habe diese Zeilen gelöscht, weil ich sie für überflüssig hielt, und eine Stunde damit verschwendet, dass die Werte meines ursprünglichen Objekts innerhalb dieser Funktion überschrieben wurden.
Rohan Kandwal
2
Vergessen Sie nicht, dass der Monatswert in der Kalenderklasse auf 0 basiert. calendar.set (2015, 11, 30, 0, 00, 00); bedeutet eigentlich 30/12/2015
Dmitry
20

Der beste Weg, und es wird als Bonus in einen String umgewandelt;)

protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    try {
        //Dates to compare
        String CurrentDate=  "09/24/2015";
        String FinalDate=  "09/26/2015";

        Date date1;
        Date date2;

        SimpleDateFormat dates = new SimpleDateFormat("MM/dd/yyyy");

        //Setting dates
        date1 = dates.parse(CurrentDate);
        date2 = dates.parse(FinalDate);

        //Comparing dates
        long difference = Math.abs(date1.getTime() - date2.getTime());
        long differenceDates = difference / (24 * 60 * 60 * 1000);

        //Convert long to String
        String dayDifference = Long.toString(differenceDates);

        Log.e("HERE","HERE: " + dayDifference);
    }
    catch (Exception exception) {
        Log.e("DIDN'T WORK", "exception " + exception);
    }
}
SoVinceble
quelle
Was ist die Möglichkeit, eine Ausnahme zu werfen?
CoDe
Beachten Sie, dass dies in Schaltjahren nicht funktioniert. Beispielsweise beträgt der Zeitraum vom 15.02.2020 bis zum 02.04.2020 47 Tage. Diese Logik wird mit 46.
user1070304
11

Verwenden:

public int getDifferenceDays(Date d1, Date d2) {
    int daysdiff = 0;
    long diff = d2.getTime() - d1.getTime();
    long diffDays = diff / (24 * 60 * 60 * 1000) + 1;
    daysdiff = (int) diffDays;
    return daysdiff;
}
sagteesh kilaru
quelle
Berücksichtigt dies Schaltjahre und Sommerzeit?
Max Alexander Hanna
1
@MaxAlexanderHanna berücksichtigt Schaltjahre korrekt, aber keine Sommerzeit. Es gibt nur dann die richtige Antwort, wenn ein Zeitraum während der Sommerzeit beginnt, aber während der Sommerzeit endet. In allen anderen Fällen ist es um eins aus.
Dawood ibn Kareem
1
@saidesh_kilaru Was ist die "+ 1"? Ich denke du solltest es entfernen.
Alisa
Ich hatte ein Problem, dass das Casting zu INT zu 4 und das Casting zu Float zu 4,9 führte. Das war also nicht wirklich das, was ich wollte. Vielleicht nicht klar genug beschrieben die Fälle für Datum1 um 23:59 und Datum2 um 00:01 und was das erwartete Ergebnis sein würde.
EricG
10

Java-Datumsbibliotheken sind notorisch kaputt. Ich würde empfehlen, Joda Time zu verwenden . Es kümmert sich um Schaltjahr, Zeitzone und so weiter für Sie.

Minimales Arbeitsbeispiel:

import java.util.Scanner;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

public class DateTestCase {

    public static void main(String[] args) {

        System.out.print("Insert first date: ");
        Scanner s = new Scanner(System.in);
        String firstdate = s.nextLine();
        System.out.print("Insert second date: ");
        String seconddate = s.nextLine();

        // Formatter
        DateTimeFormatter dateStringFormat = DateTimeFormat
                .forPattern("dd MM yyyy");
        DateTime firstTime = dateStringFormat.parseDateTime(firstdate);
        DateTime secondTime = dateStringFormat.parseDateTime(seconddate);
        int days = Days.daysBetween(new LocalDate(firstTime),
                                    new LocalDate(secondTime)).getDays();
        System.out.println("Days between the two dates " + days);
    }
}
Julien
quelle
4
Diese Antwort könnte auf verschiedene Weise verbessert werden. (a) Geben Sie die Zeitzone an, anstatt sich auf die Standardeinstellung der JVM zu verlassen. Fügen Sie beim Erstellen dieses DateTimeFormatter einen Aufruf zu hinzu withZone( DateTimeZone.forID( "Europe/Berlin" ) ). (b) Warum LocalDateim daysBetweenAnruf verwenden? Übergeben Sie einfach DateTime-Objekte (firstTime, secondTime). Für volle Tage rufen Sie an withTimeAtStartOfDays. (c) Ich würde firstDateTimeeher Variablennamen verwenden firstTime, um Mehrdeutigkeiten zwischen Datums-, Uhrzeit- und Datums- / Uhrzeitobjekten zu vermeiden. (d) Fügen Sie einen Try-Catch hinzu, um fehlerhafte Dateneingaben zu verarbeiten, die nicht unserem erwarteten Format entsprechen.
Basil Bourque
5
String dateStart = "01/14/2015 08:29:58";
String dateStop = "01/15/2015 11:31:48";

//HH converts hour in 24 hours format (0-23), day calculation
SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");

Date d1 = null;
Date d2 = null;

d1 = format.parse(dateStart);
d2 = format.parse(dateStop);

//in milliseconds
long diff = d2.getTime() - d1.getTime();

long diffSeconds = diff / 1000 % 60;
long diffMinutes = diff / (60 * 1000) % 60;
long diffHours = diff / (60 * 60 * 1000) % 24;
long diffDays = diff / (24 * 60 * 60 * 1000);

System.out.print(diffDays + " days, ");
System.out.print(diffHours + " hours, ");
System.out.print(diffMinutes + " minutes, ");
System.out.print(diffSeconds + " seconds.");
Gautam Viradiya
quelle
1

Wenn ich Ihr Programm ausführe, komme ich nicht einmal an den Punkt, an dem ich das zweite Datum eingeben kann.

Dies ist einfacher und weniger fehleranfällig.

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Test001 {

    public static void main(String[] args) throws Exception {

        BufferedReader br = null;

        br = new BufferedReader(new InputStreamReader(System.in));
        SimpleDateFormat sdf = new SimpleDateFormat("dd MM yyyy");

        System.out.println("Insert first date : ");
        Date dt1 = sdf.parse(br.readLine().trim());

        System.out.println("Insert second date : ");
        Date dt2 = sdf.parse(br.readLine().trim());

        long diff = dt2.getTime() - dt1.getTime();

        System.out.println("Days: " + diff / 1000L / 60L / 60L / 24L);

        if (br != null) {
            br.close();
        }
    }
}
peter.petrov
quelle
1
// date format, it will be like "2015-01-01"
private static final String DATE_FORMAT = "yyyy-MM-dd";

// convert a string to java.util.Date
public static Date convertStringToJavaDate(String date)
        throws ParseException {
    DateFormat dataFormat = new SimpleDateFormat(DATE_FORMAT);
    return dataFormat.parse(date);
}

// plus days to a date
public static Date plusJavaDays(Date date, int days) {
    // convert to jata-time
    DateTime fromDate = new DateTime(date);
    DateTime toDate = fromDate.plusDays(days);
    // convert back to java.util.Date
    return toDate.toDate();
}

// return a list of dates between the fromDate and toDate
public static List<Date> getDatesBetween(Date fromDate, Date toDate) {
    List<Date> dates = new ArrayList<Date>(0);
    Date date = fromDate;
    while (date.before(toDate) || date.equals(toDate)) {
        dates.add(date);
        date = plusJavaDays(date, 1);
    }
    return dates;
}
Dayong
quelle
0

Wir können die Java-Bibliothek LocalDate und ChronoUnit verwenden. Der folgende Code funktioniert einwandfrei. Das Datum sollte das Format JJJJ-MM-TT haben.

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;
class Solution {
    public int daysBetweenDates(String date1, String date2) {
        LocalDate dt1 = LocalDate.parse(date1);
        LocalDate dt2= LocalDate.parse(date2);

        long diffDays = ChronoUnit.DAYS.between(dt1, dt2);

        return Math.abs((int)diffDays);
    }
}
Abhijeet Upadhyay
quelle
4
Vielen Dank für Ihren Beitrag. Ich glaube, dass dieser gute Vorschlag bereits in der Antwort von mkobit enthalten war.
Ole VV