Berechnung der Differenz zwischen zwei Java-Datumsinstanzen


433

Ich verwende Javas java.util.DateKlasse in Scala und möchte ein DateObjekt und die aktuelle Zeit vergleichen. Ich weiß, dass ich das Delta mit getTime () berechnen kann:

(new java.util.Date()).getTime() - oldDate.getTime()

Dies lässt mir jedoch nur longMillisekunden. Gibt es einen einfacheren und schöneren Weg, um ein Zeitdelta zu erhalten?


10
Warum keine Liebe zur Joda-Zeit? Es ist so ziemlich die beste Option, wenn Sie sich mit Daten in Java befassen möchten.
Doktor Jones

7
Bitte überprüfen Sie meine elegante 2-Liner-Lösung, ohne Joda zu verwenden, und geben Sie das Ergebnis in einer TimeUnit unter stackoverflow.com/a/10650881/82609
Sebastien Lorber

2
Schande über all diejenigen, die Joda-Zeit empfehlen und keine echte Java-Antwort empfehlen ...
Zizouz212

2
@ Zizouz212 In Bezug auf die Empfehlung von Joda-Time sind die mit Java gebündelten alten Datums- und Uhrzeitklassen schlecht, wirklich schlecht, schlecht gestaltet, verwirrend und problematisch. So schlecht, dass Joda-Time als Ersatz sehr erfolgreich wurde. So schlimm, dass sogar Sun / Oracle sie aufgab und das Paket java.time als Teil von Java 8 und höher übernahm. Die java.time-Klassen sind von Joda-Time inspiriert. Sowohl Joda-Time als auch java.time werden von demselben Mann geführt, Stephen Colbourne . Ich würde sagen : „Schande über jeden empfehlen Verwendung Date, Calendarund SimpleDateFormat“.
Basil Bourque

2
Während Joda Time wahrscheinlich eine gute Antwort war, als die Frage gestellt wurde, ist heute die beste Antwort für jeden, der Java 8 verwenden kann, die Verwendung java.time.Periodund / oder Duration. Siehe die Antwort von Basil Bourque unten .
Ole VV

Antworten:


198

Die JDK- DateAPI ist leider schrecklich kaputt. Ich empfehle die Verwendung der Joda Time Bibliothek .

Joda Time hat ein Konzept des Zeitintervalls :

Interval interval = new Interval(oldTime, new Instant());

BEARBEITEN: Joda hat übrigens zwei Konzepte: Intervalfür die Darstellung eines Zeitintervalls zwischen zwei Zeitpunkten (repräsentieren die Zeit zwischen 8 und 10 Uhr) und eines Duration, das eine Zeitspanne ohne die tatsächlichen Zeitgrenzen darstellt (z. B. zwei Stunden!)

Wenn Sie sich nur für Zeitvergleiche interessieren, Dateimplementieren die meisten Implementierungen (einschließlich der JDK-Implementierung) eine ComparableSchnittstelle, über die Sie die verwenden könnenComparable.compareTo()


Übrigens - du meinst Comparable.compareTo()nicht Comparable.compare().
Scott Morrison

Joda-Time hat drei Klassen, um eine Zeitspanne auf verschiedene Arten darzustellen: Intervall, Dauer und Periode. Diese richtige Antwort beschreibt die ersten beiden. Siehe meine Antwort für Informationen über Zeitraum.
Basil Bourque

Java 8 hat eine neue Datums- und Uhrzeit-API wie joda.
Bis zum

11
Das neue java.timePaket in Java 8 ist von Joda-Time inspiriert, jedoch kein Ersatz. Jeder hat seine Vor- und Nachteile. Zum Glück müssen Sie sich nicht zwischen ihnen entscheiden. Verwenden Sie jedes für seine Stärken, solange Sie mit Ihren importAussagen vorsichtig sind . Siehe diese andere Antwort zum Beispiel von java.time.
Basil Bourque

6
Zu Ihrer Information , das Joda-Time- Projekt befindet sich jetzt im Wartungsmodus. Das Team empfiehlt die Migration zu den Klassen java.time . Siehe Tutorial von Oracle .
Basil Bourque

550

Einfaches Diff (ohne lib)

/**
 * Get a diff between two dates
 * @param date1 the oldest date
 * @param date2 the newest date
 * @param timeUnit the unit in which you want the diff
 * @return the diff value, in the provided unit
 */
public static long getDateDiff(Date date1, Date date2, TimeUnit timeUnit) {
    long diffInMillies = date2.getTime() - date1.getTime();
    return timeUnit.convert(diffInMillies,TimeUnit.MILLISECONDS);
}

Und dann können Sie anrufen:

getDateDiff(date1,date2,TimeUnit.MINUTES);

um den Unterschied der 2 Daten in Minuten zu erhalten.

TimeUnitist java.util.concurrent.TimeUniteine Standard-Java-Aufzählung, die von Nanos bis zu Tagen reicht.


Vom Menschen lesbarer Diff (ohne Bibliothek)

public static Map<TimeUnit,Long> computeDiff(Date date1, Date date2) {

    long diffInMillies = date2.getTime() - date1.getTime();

    //create the list
    List<TimeUnit> units = new ArrayList<TimeUnit>(EnumSet.allOf(TimeUnit.class));
    Collections.reverse(units);

    //create the result map of TimeUnit and difference
    Map<TimeUnit,Long> result = new LinkedHashMap<TimeUnit,Long>();
    long milliesRest = diffInMillies;

    for ( TimeUnit unit : units ) {

        //calculate difference in millisecond 
        long diff = unit.convert(milliesRest,TimeUnit.MILLISECONDS);
        long diffInMilliesForUnit = unit.toMillis(diff);
        milliesRest = milliesRest - diffInMilliesForUnit;

        //put the result in the map
        result.put(unit,diff);
    }

    return result;
}

http://ideone.com/5dXeu6

Die Ausgabe ist so etwas wie Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0}mit den bestellten Einheiten.

Sie müssen diese Karte nur in eine benutzerfreundliche Zeichenfolge konvertieren.


Warnung

Die obigen Codefragmente berechnen einen einfachen Unterschied zwischen zwei Zeitpunkten. Es kann Probleme während eines Sommerzeitschalters verursachen, wie in diesem Beitrag erläutert . Dies bedeutet, wenn Sie den Unterschied zwischen Daten ohne Uhrzeit berechnen, fehlt möglicherweise ein Tag / eine Stunde.

Meiner Meinung nach ist der Datumsunterschied subjektiv, besonders an Tagen. Du darfst:

  • Zählen Sie die Anzahl der verstrichenen 24 Stunden: Tag + 1 - Tag = 1 Tag = 24 Stunden

  • Zählen Sie die Anzahl der verstrichenen Zeit und achten Sie dabei auf die Sommerzeit: Tag + 1 - Tag = 1 = 24 Stunden (bei Mitternacht und Sommerzeit können es jedoch 0 Tage und 23 Stunden sein).

  • Zählen Sie die Anzahl von day switches, dh Tag + 1 1 Uhr - Tag 11 Uhr = 1 Tag, auch wenn die verstrichene Zeit nur 2 Stunden beträgt (oder 1 Stunde, wenn eine Sommerzeit vorhanden ist: p).

Meine Antwort ist gültig, wenn Ihre Definition des Datumsunterschieds an Tagen mit dem 1. Fall übereinstimmt

Mit JodaTime

Wenn Sie JodaTime verwenden, können Sie den Diff für 2 Instants (Millies Backed ReadableInstant) -Daten erhalten mit:

Interval interval = new Interval(oldInstant, new Instant());

Sie können den Diff aber auch für lokale Daten / Zeiten abrufen:

// returns 4 because of the leap year of 366 days
new Period(LocalDate.now(), LocalDate.now().plusDays(365*5), PeriodType.years()).getYears() 

// this time it returns 5
new Period(LocalDate.now(), LocalDate.now().plusDays(365*5+1), PeriodType.years()).getYears() 

// And you can also use these static methods
Years.yearsBetween(LocalDate.now(), LocalDate.now().plusDays(365*5)).getYears()

Wow, du kannst einem alten Hund wirklich neue Tricks beibringen! Noch nie davon gehört, sehr nützlich, um Datumsunterschiede in aussagekräftige Zeichenfolgen zu übersetzen.
Jeremy Goodell

@SebastienLorber Gibt es in TimeUnit eine Möglichkeit, die Differenz so zu berechnen? "Der Alarm ist in 3 Tagen, 4 Stunden und 12 Minuten eingestellt".
Likejudo

brillantes Zeug hat mir wirklich viel Zeit gespart. Schätze deine Hilfe.
Lyju I Edwinson

Ich habe 3 Tage meines Lebens mit Java Dates verschwendet und einfach viel davon weggeworfen und durch dieses ersetzt. Vielen Dank.
user1091524

Dies ist die beste Antwort, die ich gesehen habe, seit ich auf Stackoverflow gekommen bin! : D: D: D
Kalt

153
int diffInDays = (int)( (newerDate.getTime() - olderDate.getTime()) 
                 / (1000 * 60 * 60 * 24) )

Beachten Sie, dass dies mit UTC-Daten funktioniert. Wenn Sie sich die lokalen Daten ansehen, kann der Unterschied ein freier Tag sein. Und damit es mit lokalen Daten richtig funktioniert, ist aufgrund der Sommerzeit ein völlig anderer Ansatz erforderlich.


6
Dies funktioniert in Android eigentlich nicht richtig. Rundungsfehler liegen vor. Beispiel 19. bis 21. Mai sagt 1 Tag, weil es 1,99 zu 1 wirft. Verwenden Sie Runde, bevor Sie zu int werfen.
Pratik Mandrekar

4
Dies ist die beste und einfachste Antwort. Bei der Berechnung einer Differenz zwischen zwei Daten subtrahieren sich lokale Zeitzonen gegenseitig ... so dass die richtige Antwort (als Doppel) einfach durch ((Doppel) (neuer.getTime () - älter.getTime ()) / gegeben wird. (86400.0 * 1000.0); ... als Doppel haben Sie auch den Bruchteil des Tages, der leicht in HH: MM: ss.
scottb

8
@scottb: Das Problem mit lokalen Daten ist, dass Sie Sommerzeit haben können, was bedeutet, dass einige Tage 23 oder 25 Stunden haben, was möglicherweise das Ergebnis durcheinander bringt.
Michael Borgwardt

1
@Steve: Es ist 28 für mich, wenn ich sie wie dieses neue Datum definiere (115, 2, 26); (Beachten Sie das API-Dokument für die Parameter). Ist es möglich, dass Sie sie im US-Datumsformat und im milden Modus analysieren, sodass der 26.03.2015 als 3. Tag des 26. Monats 2015 interpretiert wird?
Michael Borgwardt

1
@Steve: hm, ich bin mir nicht sicher, warum ich vorher ein anderes Ergebnis erhalten habe, aber jetzt kann ich Ihren Fehler reproduzieren. Die geschweiften Klammern in Ihrem Code unterscheiden sich von meiner Antwort, was dazu führt (endDate.getTime() - startDate.getTime()), dass intanstelle des Endergebnisses eine Umwandlung erfolgt und Sie einen ganzzahligen Überlauf erhalten.
Michael Borgwardt

54

Verwenden des in Java 8+ integrierten java.time- Frameworks:

ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime oldDate = now.minusDays(1).minusMinutes(10);
Duration duration = Duration.between(oldDate, now);
System.out.println("ISO-8601: " + duration);
System.out.println("Minutes: " + duration.toMinutes());

Ausgabe:

ISO-8601: PT24H10M

Minuten: 1450

Weitere Informationen finden Sie im Oracle Tutorial und im ISO 8601- Standard.


5
Dies oder Periodanstelle von Durationfür Daten verwenden.
Aphex

53

Sie müssen Ihr Problem klarer definieren. Sie können einfach die Anzahl der Millisekunden zwischen den beiden DateObjekten nehmen und durch die Anzahl der Millisekunden in 24 Stunden dividieren, zum Beispiel ... aber:

  • Dies berücksichtigt keine Zeitzonen - Dateist immer in UTC
  • Dabei wird die Sommerzeit nicht berücksichtigt (wo es beispielsweise Tage geben kann, die nur 23 Stunden lang sind).
  • Wie viele Tage gibt es innerhalb von UTC vom 16. August um 23 Uhr bis zum 18. August um 2 Uhr morgens? Es sind nur 27 Stunden, bedeutet das also einen Tag? Oder sollten es drei Tage sein, weil es drei Daten abdeckt?

1
Ich dachte java.util. Das Datum war nur ein winziger Wrapper um eine Zeit-Millis-Darstellung, interpretiert in der lokalen (Standard-) Zeitzone. Durch Ausdrucken eines Datums bekomme ich eine lokale Zeitzonendarstellung. Bin ich hier verwirrt?
Adriaan Koster

46

tl; dr

Konvertieren Sie Ihre veralteten java.util.DateObjekte in deren Ersatz java.time.Instant. Berechnen Sie dann die verstrichene Zeit als Duration.

Duration d = 
    Duration.between(                   // Calculate the span of time between two moments as a number of hours, minutes, and seconds.
        myJavaUtilDate.toInstant() ,    // Convert legacy class to modern class by calling new method added to the old class.
        Instant.now()                   // Capture the current moment in UTC. About two and a half hours later in this example.
    )
;

d.toString (): PT2H34M56S

d.toMinutes (): 154

d.toMinutesPart (): 34

ISO 8601 Format: PnYnMnDTnHnMnS

Die sinnvolle Norm ISO 8601 definiert eine präzise Textdarstellung einer Zeitspanne als Anzahl von Jahren, Monaten, Tagen, Stunden usw. Die Norm nennt eine solche Zeitspanne eine Dauer . Das Format ist, PnYnMnDTnHnMnSwo das PMittel "Punkt" bedeutet, das Tden Datumsabschnitt vom Zeitabschnitt trennt und dazwischen Zahlen stehen, gefolgt von einem Buchstaben.

Beispiele:

  • P3Y6M4DT12H30M5S
    drei Jahre, sechs Monate, vier Tage, zwölf Stunden, dreißig Minuten und fünf Sekunden
  • PT4H30M
    Viereinhalb Stunden

java.time

Das in Java 8 und höher integrierte Java.time- Framework ersetzt die problematischen alten java.util.Date/ java.util.CalendarKlassen. Die neuen Klassen sind von dem äußerst erfolgreichen Joda-Time- Framework inspiriert , das als Nachfolger gedacht ist. Das Konzept ist ähnlich, aber neu aufgebaut. Definiert durch JSR 310 . Erweitert um das ThreeTen-Extra- Projekt. Siehe das Tutorial .

Moment

Die InstantKlasse repräsentiert einen Moment auf der Zeitachse in UTC mit einer Auflösung von Nanosekunden (bis zu neun (9) Stellen eines Dezimalbruchs).

Instant instant = Instant.now() ;  // Capture current moment in UTC.

Vermeiden Sie am besten ältere Klassen wie Date/ Calendar. Wenn Sie jedoch mit altem Code interagieren müssen , der noch nicht auf java.time aktualisiert wurde , konvertieren Sie hin und her. Rufen Sie neue Konvertierungsmethoden auf, die den alten Klassen hinzugefügt wurden. Rufen Sie java.util.Datean Instant, um von a nach a zu wechseln Date::toInstant.

Instant instant = myJavaUtilDate.toInstant() ;  // Convert from legacy `java.util.Date` class to modern `java.time.Instant` class.

Zeitspanne

Die java.time-Klassen haben diese Idee, eine Zeitspanne als Anzahl von Jahren, Monaten, Tagen, Stunden, Minuten, Sekunden in zwei Hälften darzustellen, in zwei Hälften geteilt:

  • Period seit Jahren, Monaten, Tagen
  • Duration für Tage, Stunden, Minuten, Sekunden

Hier ist ein Beispiel.

ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime now = ZonedDateTime.now ( zoneId );
ZonedDateTime future = now.plusMinutes ( 63 );
Duration duration = Duration.between ( now , future );

Dump zur Konsole.

Beide Periodund Durationverwenden den ISO 8601- Standard zum Generieren einer String-Darstellung ihres Werts.

System.out.println ( "now: " + now + " to future: " + now + " = " + duration );

jetzt: 2015-11-26T00: 46: 48.016-05: 00 [Amerika / Montreal] bis Zukunft: 2015-11-26T00: 46: 48.016-05: 00 [Amerika / Montreal] = PT1H3M

Java 9 fügt Methoden hinzu Duration, um den Tag-, Stunden-, Minuten- und Sekunden-Teil abzurufen.

Sie können die Gesamtzahl der Tage oder Stunden oder Minuten oder Sekunden oder Millisekunden oder Nanosekunden in der gesamten Dauer abrufen.

long totalHours = duration.toHours();

In Java 9 Durationerhält die Klasse neue Methoden zum Zurückgeben der verschiedenen Teile von Tagen, Stunden, Minuten, Sekunden, Millisekunden / Nanosekunden. Rufen Sie die to…PartMethoden: toDaysPart(), toHoursPart(), und so weiter.

ChronoUnit

Wenn Sie sich nur für eine einfachere, größere Zeitgranularität interessieren, z. B. "Anzahl der verstrichenen Tage", verwenden Sie die ChronoUnitAufzählung.

long daysElapsed = ChronoUnit.DAYS.between( earlier , later );

Ein anderes Beispiel.

Instant now = Instant.now();
Instant later = now.plus( Duration.ofHours( 2 ) );

long minutesElapsed = ChronoUnit.MINUTES.between( now , later );

120


Über java.time

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

Das Joda-Time- Projekt, das sich jetzt im Wartungsmodus befindet , empfiehlt die Migration zu java.time.

Weitere Informationen finden Sie im Oracle-Lernprogramm . Suchen Sie im Stapelüberlauf nach vielen Beispielen und Erklärungen. Die Spezifikation ist JSR 310 .

Woher bekomme ich die java.time-Klassen?

Das ThreeTen-Extra- Projekt erweitert java.time um zusätzliche Klassen. Dieses Projekt ist ein Testfeld für mögliche zukünftige Ergänzungen von java.time. Sie können einige nützliche Klassen hier wie finden Interval, YearWeek, YearQuarter, und mehr .


Joda-Zeit

UPDATE: Das Joda-Time- Projekt befindet sich jetzt im Wartungsmodus. Das Team empfiehlt die Migration zu den Klassen java.time . Ich lasse diesen Abschnitt für die Geschichte intakt.

Die Joda-Time-Bibliothek verwendet für ihre Standardeinstellungen ISO 8601. Die PeriodKlasse analysiert und generiert diese PnYnMnDTnHnMnS-Zeichenfolgen.

DateTime now = DateTime.now(); // Caveat: Ignoring the important issue of time zones.
Period period = new Period( now, now.plusHours( 4 ).plusMinutes( 30));
System.out.println( "period: " + period );

Rendert:

period: PT4H30M

Es ist lustig, dass Sie mit "tl; dr" eine nicht zu hinterfragende Textwand gestartet haben. Die Frage ist nicht, wie man den Zeitstempel von X vor oder in X Zeiteinheiten erhält, sondern wie man das Delta zwischen zwei Daten erhält. Das ist es.
Buffalo

@ Buffalo Ich verstehe deinen Kommentar nicht. Meine Antwort beinhaltet Period, Durationund ChronoUnit, drei Klassen , deren Zweck das Delta zwischen den Zeitpunkten ist die Bestimmung. Bitte geben Sie an, welche Teile meiner „Textwand“ irrelevant sind. Und Sie sagen zu Unrecht die Frage nach einem „Delta zwischen Datumsangaben“: Die Frage nach einem Delta zwischen DateObjekten, bei denen es sich um Datums- und Uhrzeitmomente handelt, nicht um „Datumsangaben“, trotz der unglücklichen Benennung dieser Klasse.
Basil Bourque

Ihr Kommentar enthält nichts, was zwei vorhandene java.util.Date-Objekte behandelt. Ich habe versucht, verschiedene Snippets in meinem Code zu verwenden, und nichts gefunden, das ein java.util.Date-Objekt verwendet.
Buffalo

@ Buffalo Fair genug, gute Kritik. Ich habe Code im Abschnitt "tl; dr" hinzugefügt, der von a java.util.Datein a konvertiert Instant(einfach aufrufen .toInstant). Und ich habe den MomentAbschnitt hinzugefügt , um zu erklären. Sie haben ein Paar von DateObjekten erwähnt, aber tatsächlich verwendet die Frage nur ein einziges vorhandenes DateObjekt und erfasst dann den aktuellen Moment, also habe ich dasselbe getan. Danke für die Rückmeldung! Tipp: Geben Sie die Verwendung auf Date- Diese Legacy-Klassen sind wirklich ein schreckliches Durcheinander.
Basil Bourque


23

Eine etwas einfachere Alternative:

System.currentTimeMillis() - oldDate.getTime()

Was "schöner" betrifft: Nun, was genau brauchst du? Das Problem bei der Darstellung der Zeitdauer als Anzahl von Stunden und Tagen usw. besteht darin, dass dies aufgrund der Komplexität der Daten zu Ungenauigkeiten und falschen Erwartungen führen kann (z. B. können Tage aufgrund der Sommerzeit 23 oder 25 Stunden haben).


22

Die Verwendung des Millisekunden-Ansatzes kann in einigen Regionen zu Problemen führen.

Nehmen wir zum Beispiel, die Differenz zwischen den beiden Daten 24.03.2007 und 25.03.2007 sollte 1 Tag betragen.

Wenn Sie jedoch die Millisekunden-Route verwenden, erhalten Sie 0 Tage, wenn Sie dies in Großbritannien ausführen!

/** Manual Method - YIELDS INCORRECT RESULTS - DO NOT USE**/  
/* This method is used to find the no of days between the given dates */  
public long calculateDays(Date dateEarly, Date dateLater) {  
   return (dateLater.getTime() - dateEarly.getTime()) / (24 * 60 * 60 * 1000);  
} 

Eine bessere Möglichkeit, dies zu implementieren, ist die Verwendung von java.util.Calendar

/** Using Calendar - THE CORRECT WAY**/  
public static long daysBetween(Calendar startDate, Calendar endDate) {  
  Calendar date = (Calendar) startDate.clone();  
  long daysBetween = 0;  
  while (date.before(endDate)) {  
    date.add(Calendar.DAY_OF_MONTH, 1);  
    daysBetween++;  
  }  
  return daysBetween;  
}  

19
Könnten Sie bitte den ursprünglichen Autor dieses Codes und den dritten Satz angeben, dessen Blogeintrag auf 2007 datiert ist ?
Wchargin

Ist es nicht ein bisschen unwirksam?
Gangnus

Es funktioniert nicht richtig. daysBetween (neuer Gregorianischer Kalender (2014,03,01), neuer Gregorianischer Kalender (2014,04,02)); gibt 31 zurück und sollte 32 zurückgeben: timeanddate.com/date/…
marcolopes

5
@marcolopes - Du liegst falsch - weil Kalendermonate auf Null basieren. Ich bin sicher, Sie meinen März / April, aber was Sie testen, ist April / Juni, der 31 ist. Um sicher zu gehen, schreiben Sie es wie -> neuer Gregorianischer Kalender (2014, Calendar.MARCH, 1) ....
Onkel Iroh

@ OnkelIroh, du hast recht! Ich habe diese wichtige Tatsache übersehen (Kalendermonate basieren auf Null). Ich muss diese Frage noch einmal überprüfen.
marcolopes

22

Es gibt viele Möglichkeiten, wie Sie den Unterschied zwischen Datum und Uhrzeit feststellen können. Eine der einfachsten Möglichkeiten, die ich kenne, wäre:

      Calendar calendar1 = Calendar.getInstance();
      Calendar calendar2 = Calendar.getInstance();
      calendar1.set(2012, 04, 02);
      calendar2.set(2012, 04, 04);
      long milsecs1= calendar1.getTimeInMillis();
      long milsecs2 = calendar2.getTimeInMillis();
      long diff = milsecs2 - milsecs1;
      long dsecs = diff / 1000;
      long dminutes = diff / (60 * 1000);
      long dhours = diff / (60 * 60 * 1000);
      long ddays = diff / (24 * 60 * 60 * 1000);

      System.out.println("Your Day Difference="+ddays);

Die print-Anweisung ist nur ein Beispiel - Sie können sie nach Ihren Wünschen formatieren.


5
@ Manoj Kumar Bardhan: Willkommen zum Stapelüberlauf: Wie Sie sehen, sind die Fragen und Antworten Jahre alt. Ihre Antwort sollte der Frage / Antwort mehr hinzufügen als die vorhandenen.
Jayan

3
Was ist mit den Tagen, die aufgrund eines Sommerzeitübergangs 23 oder 25 Stunden haben?
Joni

19

Da alle Antworten hier korrekt sind, aber ältere Java- oder Drittanbieter-Bibliotheken wie joda oder ähnliches verwenden, werde ich einfach neue Java.time- Klassen in Java 8 und höher verwenden. Siehe Oracle Tutorial .

Verwenden Sie LocalDateund ChronoUnit:

LocalDate d1 = LocalDate.of(2017, 5, 1);
LocalDate d2 = LocalDate.of(2017, 5, 18);

long days = ChronoUnit.DAYS.between(d1, d2);
System.out.println( days );

9

Das Subtrahieren der Daten in Millisekunden funktioniert (wie in einem anderen Beitrag beschrieben), aber Sie müssen HOUR_OF_DAY und nicht HOUR verwenden, wenn Sie die Zeitteile Ihrer Daten löschen:

public static final long MSPERDAY = 60 * 60 * 24 * 1000;
...
final Calendar dateStartCal = Calendar.getInstance();
dateStartCal.setTime(dateStart);
dateStartCal.set(Calendar.HOUR_OF_DAY, 0); // Crucial.
dateStartCal.set(Calendar.MINUTE, 0);
dateStartCal.set(Calendar.SECOND, 0);
dateStartCal.set(Calendar.MILLISECOND, 0);
final Calendar dateEndCal = Calendar.getInstance();
dateEndCal.setTime(dateEnd);
dateEndCal.set(Calendar.HOUR_OF_DAY, 0); // Crucial.
dateEndCal.set(Calendar.MINUTE, 0);
dateEndCal.set(Calendar.SECOND, 0);
dateEndCal.set(Calendar.MILLISECOND, 0);
final long dateDifferenceInDays = ( dateStartCal.getTimeInMillis()
                                  - dateEndCal.getTimeInMillis()
                                  ) / MSPERDAY;
if (dateDifferenceInDays > 15) {
    // Do something if difference > 15 days
}

1
Dies ist die beste Methode, um den Unterschied zwischen zwei Kalenderdaten zu ermitteln, ohne die Standardbibliotheken zu verlassen. Die meisten anderen Antworten behandeln einen Tag als willkürlichen 24-Stunden-Zeitraum. Wenn Schaltsekunden jemals subtrahiert und nicht addiert werden sollten, könnte die endgültige Berechnung aufgrund von Kürzungen um eins abweichen, da die absolute Differenz etwas geringer sein könnte als eine ganze Anzahl von Vielfachen von MSPERDAY.
JulianSymes

8

Wenn Sie JodaTime oder ähnliches nicht verwenden möchten, ist die beste Lösung wahrscheinlich folgende:

final static long MILLIS_PER_DAY = 24 * 3600 * 1000;
long msDiff= date1.getTime() - date2.getTime();
long daysDiff = Math.round(msDiff / ((double)MILLIS_PER_DAY));

Die Anzahl der ms pro Tag ist nicht immer gleich (aufgrund der Sommerzeit und der Schaltsekunden), liegt jedoch sehr nahe beieinander, und zumindest Abweichungen aufgrund der Sommerzeit werden über längere Zeiträume aufgehoben. Daher ergibt das Teilen und anschließende Runden ein korrektes Ergebnis (zumindest solange der verwendete lokale Kalender keine anderen seltsamen Zeitsprünge als Sommerzeit und Schaltsekunden enthält).

Beachten Sie, dass dies immer noch davon ausgeht date1und date2auf dieselbe Tageszeit eingestellt ist. Für verschiedene Tageszeiten müssten Sie zuerst definieren, was "Datumsunterschied" bedeutet, wie von Jon Skeet hervorgehoben.


Das Problem ist in date1.getTime()vs date2.getTime(). Wenn Sie also zwischen 2016-03-03 und 2016-03-31 unterscheiden, werden 27 Tage berechnet, während Sie 28 Tage möchten.
Malat

@malat: Entschuldigung, ich kann nicht folgen. Ich habe es gerade versucht - zwischen 2016-03-03 und 2016-03-31 mit meinem Code berechnet 28 Tage. Wenn in Ihrem Beispiel etwas anderes berechnet wird, sollten Sie dies als separate Frage stellen.
Sleske

Hast du auch meine Einschränkung gelesen? "Dies setzt immer noch voraus, dass Datum1 und Datum2 auf dieselbe Tageszeit eingestellt sind". Haben Sie in Ihrem Test möglicherweise andere Tageszeiten verwendet?
Sleske

Ah richtig ! Ich habe den Trick verpasst, der Math.round()in "realen" Kalendern sicher zu sein scheint. Entschuldigung für den Lärm.
Malat

8

Schauen Sie sich Joda Time an , eine verbesserte Datums- / Uhrzeit-API für Java, die mit Scala problemlos funktionieren sollte.


ersetzt durch java.time (JSR-310) in Java 8
malat

5

Lassen Sie mich den Unterschied zwischen Joda-Intervall und Tagen zeigen:

DateTime start = new DateTime(2012, 2, 6, 10, 44, 51, 0);
DateTime end = new DateTime(2012, 2, 6, 11, 39, 47, 1);
Interval interval = new Interval(start, end);
Period period = interval.toPeriod();
System.out.println(period.getYears() + " years, " + period.getMonths() + " months, " + period.getWeeks() + " weeks, " + period.getDays() + " days");
System.out.println(period.getHours() + " hours, " + period.getMinutes() + " minutes, " + period.getSeconds() + " seconds ");
//Result is:
//0 years, 0 months, *1 weeks, 1 days*
//0 hours, 54 minutes, 56 seconds 

//Period can set PeriodType,such as PeriodType.yearMonthDay(),PeriodType.yearDayTime()...
Period p = new Period(start, end, PeriodType.yearMonthDayTime());
System.out.println(p.getYears() + " years, " + p.getMonths() + " months, " + p.getWeeks() + " weeks, " + p.getDays() + "days");
System.out.println(p.getHours() + " hours, " + p.getMinutes() + " minutes, " + p.getSeconds() + " seconds ");
//Result is:
//0 years, 0 months, *0 weeks, 8 days*
//0 hours, 54 minutes, 56 seconds 

5

Wenn Sie eine formatierte Rückgabezeichenfolge wie "2 Days 03h 42m 07s" benötigen, versuchen Sie Folgendes:

public String fill2(int value)
{
    String ret = String.valueOf(value);

    if (ret.length() < 2)
        ret = "0" + ret;            
    return ret;
}

public String get_duration(Date date1, Date date2)
{                   
    TimeUnit timeUnit = TimeUnit.SECONDS;

    long diffInMilli = date2.getTime() - date1.getTime();
    long s = timeUnit.convert(diffInMilli, TimeUnit.MILLISECONDS);

    long days = s / (24 * 60 * 60);
    long rest = s - (days * 24 * 60 * 60);
    long hrs = rest / (60 * 60);
    long rest1 = rest - (hrs * 60 * 60);
    long min = rest1 / 60;      
    long sec = s % 60;

    String dates = "";
    if (days > 0) dates = days + " Days ";

    dates += fill2((int) hrs) + "h ";
    dates += fill2((int) min) + "m ";
    dates += fill2((int) sec) + "s ";

    return dates;
}

2
Whoa, warum würfeln Sie Ihre eigenen, wenn Joda-Time die bereits geschriebene und debuggte Period- Klasse bereitstellt ?
Basil Bourque

8
Warum sollte ich eine Bibliothek mit einer komprimierten Dateigröße von 4,1 MB herunterladen und meinem Projekt hinzufügen, wenn ich nur 32 Codezeilen benötige?
Ingo

1
Weil Joda-Time wie Kartoffelchips ist: Man kann nicht nur einen essen. Sie werden Joda-Time überall verwenden. Und weil Joda-Time ein bewährter und abgenutzter Code ist. Und weil Joda-Time Standard- ISO 8601-Dauerzeichenfolgen analysiert und generiert, die für die Serialisierung oder Berichterstellung dieser Werte hilfreich sein können. Und weil Joda-Time Formatierer enthält, um lokalisierte Darstellungen dieser Werte zu drucken.
Basil Bourque

Nicht Ihr gesamter Code wird getestet. stdoben ist undefiniert.
Basil Bourque

@ Basil Bourque: Danke für den Hinweis. Ich habe die Quelle korrigiert. Dieser Fehler kam von der Übersetzung ins Englische.
Ingo

5

Hinweis: startDate und endDates sind -> java.util.Date

import org.joda.time.Duration;
import org.joda.time.Interval;
// Use .getTime() unless it is a joda DateTime object
Interval interval = new Interval(startDate.getTime(), endDate.getTime());
Duration period = interval.toDuration();
//gives the number of days elapsed between start 
period.getStandardDays();

und Enddatum

Ähnlich wie bei Tagen können Sie auch Stunden, Minuten und Sekunden erhalten

period.getStandardHours();
period.getStandardMinutes();
period.getStandardSeconds();

4

Beispiel hier ansehen http://www.roseindia.net/java/beginners/DateDifferent.shtml Dieses Beispiel gibt Ihnen einen Unterschied in Tagen, Stunden, Minuten, Sekunden und Millisekunden :).

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

public class DateDifferent {
    public static void main(String[] args) {
        Date date1 = new Date(2009, 01, 10);
        Date date2 = new Date(2009, 07, 01);
        Calendar calendar1 = Calendar.getInstance();
        Calendar calendar2 = Calendar.getInstance();
        calendar1.setTime(date1);
        calendar2.setTime(date2);
        long milliseconds1 = calendar1.getTimeInMillis();
        long milliseconds2 = calendar2.getTimeInMillis();
        long diff = milliseconds2 - milliseconds1;
        long diffSeconds = diff / 1000;
        long diffMinutes = diff / (60 * 1000);
        long diffHours = diff / (60 * 60 * 1000);
        long diffDays = diff / (24 * 60 * 60 * 1000);
        System.out.println("\nThe Date Different Example");
        System.out.println("Time in milliseconds: " + diff + " milliseconds.");
        System.out.println("Time in seconds: " + diffSeconds + " seconds.");
        System.out.println("Time in minutes: " + diffMinutes + " minutes.");
        System.out.println("Time in hours: " + diffHours + " hours.");
        System.out.println("Time in days: " + diffDays + " days.");
    }
}

3
-1 Das ist falsch, es sei denn, die Datumsinstanzen wurden aus UTC-Zeiten abgeleitet. Siehe Jon Skeets Antwort.
Sleske

4

Verwenden Sie die GMT-Zeitzone, um eine Instanz des Kalenders abzurufen. Legen Sie die Zeit mithilfe der festgelegten Methode der Kalenderklasse fest. Die GMT-Zeitzone hat einen Offset von 0 (nicht wirklich wichtig) und ein Sommerzeit-Flag auf false gesetzt.

    final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

    cal.set(Calendar.YEAR, 2011);
    cal.set(Calendar.MONTH, 9);
    cal.set(Calendar.DAY_OF_MONTH, 29);
    cal.set(Calendar.HOUR, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    final Date startDate = cal.getTime();

    cal.set(Calendar.YEAR, 2011);
    cal.set(Calendar.MONTH, 12);
    cal.set(Calendar.DAY_OF_MONTH, 21);
    cal.set(Calendar.HOUR, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    final Date endDate = cal.getTime();

    System.out.println((endDate.getTime() - startDate.getTime()) % (1000l * 60l * 60l * 24l));

Vergessen Sie nicht, den Millisekunden-Teil auf Null zu setzen, da dies eine gute Antwort im Zusammenhang mit alten Klassen java.util.Dateusw. ist. Wenn Sie den Hack verwenden, um die Zeitzone auf GMT einzustellen, wird der Code unempfindlich gegenüber Sommerzeiteffekten.
Meno Hochschild

4

Der folgende Code kann Ihnen die gewünschte Ausgabe geben:

String startDate = "Jan 01 2015";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy");
LocalDate date = LocalDate.parse(startDate, formatter);

String currentDate = "Feb 11 2015";
LocalDate date1 = LocalDate.parse(currentDate, formatter);

System.out.println(date1.toEpochDay() - date.toEpochDay());

3
Können Sie genau erklären, was Ihr Code tut? Die Frage scheint nach einem Zeitdelta zu fragen, und auf den ersten Blick scheint Ihr Code ein Tagesdelta zurückzugeben?
GHC

4
public static String getDifferenceBtwTime(Date dateTime) {

    long timeDifferenceMilliseconds = new Date().getTime() - dateTime.getTime();
    long diffSeconds = timeDifferenceMilliseconds / 1000;
    long diffMinutes = timeDifferenceMilliseconds / (60 * 1000);
    long diffHours = timeDifferenceMilliseconds / (60 * 60 * 1000);
    long diffDays = timeDifferenceMilliseconds / (60 * 60 * 1000 * 24);
    long diffWeeks = timeDifferenceMilliseconds / (60 * 60 * 1000 * 24 * 7);
    long diffMonths = (long) (timeDifferenceMilliseconds / (60 * 60 * 1000 * 24 * 30.41666666));
    long diffYears = (long)(timeDifferenceMilliseconds / (1000 * 60 * 60 * 24 * 365));

    if (diffSeconds < 1) {
        return "one sec ago";
    } else if (diffMinutes < 1) {
        return diffSeconds + " seconds ago";
    } else if (diffHours < 1) {
        return diffMinutes + " minutes ago";
    } else if (diffDays < 1) {
        return diffHours + " hours ago";
    } else if (diffWeeks < 1) {
        return diffDays + " days ago";
    } else if (diffMonths < 1) {
        return diffWeeks + " weeks ago";
    } else if (diffYears < 12) {
        return diffMonths + " months ago";
    } else {
        return diffYears + " years ago";
    }
}   

3
int daysDiff = (date1.getTime() - date2.getTime()) / MILLIS_PER_DAY;

5
-1 Das ist falsch, es sei denn, die Datumsinstanzen wurden aus UTC-Zeiten abgeleitet. Siehe Jon Skeets Antwort.
Sleske

5
@sleske du hast nicht recht Er hat die Zeitzoneninformationen bereits durch die Verwendung verloren Date, daher ist dieser Vergleich der beste, der unter den gegebenen Umständen erreicht werden kann.
Bozho

1
OK, ich denke wir haben beide recht. Es ist wahr, dass es davon abhängt, woher die Date-Instanz kommt. Trotzdem ist es ein so häufiger Fehler, dass er erwähnt werden sollte.
Sleske

Wenn ich Ihre Lösung verwende, heißt es: Typkonflikt: Konvertiert nicht von long nach int. Ich denke du solltest auch Casting hinzufügen oder fehlt mir etwas?
Ad Infinitum

3

Das Beste ist

(Date1-Date2)/86 400 000 

Diese Zahl ist die Anzahl der Millisekunden pro Tag.

Ein Datum und ein anderes Datum geben den Unterschied in Millisekunden an.

Sammeln Sie die Antwort in einer doppelten Variablen.


Ja, warum nicht? Ich verstehe den Punkt der Frage in gewisser Weise nicht: OP hat einen Unterschied in ms ... und es gibt eine bestimmte Anzahl von ms an einem Tag (OK mit bestimmten astronomischen Anpassungen einmal in einem blauen Mond, aber das OP nicht Ich sage nicht, dass es so genau sein muss, wie es Astronomen brauchen ...)
Mike Nagetier

3

Hier ist eine korrekte Java 7-Lösung in O (1) ohne Abhängigkeiten.

public static int countDaysBetween(Date date1, Date date2) {

    Calendar c1 = removeTime(from(date1));
    Calendar c2 = removeTime(from(date2));

    if (c1.get(YEAR) == c2.get(YEAR)) {

        return Math.abs(c1.get(DAY_OF_YEAR) - c2.get(DAY_OF_YEAR)) + 1;
    }
    // ensure c1 <= c2
    if (c1.get(YEAR) > c2.get(YEAR)) {
        Calendar c = c1;
        c1 = c2;
        c2 = c;
    }
    int y1 = c1.get(YEAR);
    int y2 = c2.get(YEAR);
    int d1 = c1.get(DAY_OF_YEAR);
    int d2 = c2.get(DAY_OF_YEAR);

    return d2 + ((y2 - y1) * 365) - d1 + countLeapYearsBetween(y1, y2) + 1;
}

private static int countLeapYearsBetween(int y1, int y2) {

    if (y1 < 1 || y2 < 1) {
        throw new IllegalArgumentException("Year must be > 0.");
    }
    // ensure y1 <= y2
    if (y1 > y2) {
        int i = y1;
        y1 = y2;
        y2 = i;
    }

    int diff = 0;

    int firstDivisibleBy4 = y1;
    if (firstDivisibleBy4 % 4 != 0) {
        firstDivisibleBy4 += 4 - (y1 % 4);
    }
    diff = y2 - firstDivisibleBy4 - 1;
    int divisibleBy4 = diff < 0 ? 0 : diff / 4 + 1;

    int firstDivisibleBy100 = y1;
    if (firstDivisibleBy100 % 100 != 0) {
        firstDivisibleBy100 += 100 - (firstDivisibleBy100 % 100);
    }
    diff = y2 - firstDivisibleBy100 - 1;
    int divisibleBy100 = diff < 0 ? 0 : diff / 100 + 1;

    int firstDivisibleBy400 = y1;
    if (firstDivisibleBy400 % 400 != 0) {
        firstDivisibleBy400 += 400 - (y1 % 400);
    }
    diff = y2 - firstDivisibleBy400 - 1;
    int divisibleBy400 = diff < 0 ? 0 : diff / 400 + 1;

    return divisibleBy4 - divisibleBy100 + divisibleBy400;
}


public static Calendar from(Date date) {

    Calendar c = Calendar.getInstance();
    c.setTime(date);

    return c;
}


public static Calendar removeTime(Calendar c) {

    c.set(HOUR_OF_DAY, 0);
    c.set(MINUTE, 0);
    c.set(SECOND, 0);
    c.set(MILLISECOND, 0);

    return c;
}

2

Das ist wahrscheinlich der einfachste Weg, dies zu tun - vielleicht liegt es daran, dass ich schon seit einiger Zeit in Java (mit seinen zugegebenermaßen klobigen Datums- und Zeitbibliotheken) codiere, aber dieser Code sieht für mich "einfach und nett" aus!

Sind Sie mit der Rückgabe des Ergebnisses in Millisekunden zufrieden oder ist es Teil Ihrer Frage, dass Sie es lieber in einem anderen Format zurückgeben möchten?


2

Nicht mit der Standard-API, nein. Sie können Ihre eigenen machen, indem Sie so etwas tun:

class Duration {
    private final TimeUnit unit;
    private final long length;
    // ...
}

Oder Sie können Joda verwenden :

DateTime a = ..., b = ...;
Duration d = new Duration(a, b);

2

Nur um die erste Frage zu beantworten:

Fügen Sie den folgenden Code in eine Funktion wie Long getAge () {} ein

Date dahora = new Date();
long MillisToYearsByDiv = 1000l *60l * 60l * 24l * 365l;
long javaOffsetInMillis = 1990l * MillisToYearsByDiv;
long realNowInMillis = dahora.getTime() + javaOffsetInMillis;
long realBirthDayInMillis = this.getFechaNac().getTime() + javaOffsetInMillis;
long ageInMillis = realNowInMillis - realBirthDayInMillis;

return ageInMillis / MillisToYearsByDiv;

Das Wichtigste dabei ist, beim Multiplizieren und Dividieren mit langen Zahlen zu arbeiten. Und natürlich der Offset, den Java in seiner Datumsrechnung anwendet.

:) :)


2

Da die Frage mit Scala markiert ist,

import scala.concurrent.duration._
val diff = (System.currentTimeMillis() - oldDate.getTime).milliseconds
val diffSeconds = diff.toSeconds
val diffMinutes = diff.toMinutes
val diffHours = diff.toHours
val diffDays = diff.toDays

2

Nachdem Sie alle anderen Antworten durchgesehen haben, um den Java 7-Datumstyp beizubehalten, aber mit dem Java 8-Diff-Ansatz präziser / standardisierter zu sein,

public static long daysBetweenDates(Date d1, Date d2) {
    Instant instant1 = d1.toInstant();
    Instant instant2 = d2.toInstant();
    long diff = ChronoUnit.DAYS.between(instant1, instant2);
    return diff;
}

1

Versuche dies:

int epoch = (int) (new java.text.SimpleDateFormat("MM/dd/yyyy HH:mm:ss").parse("01/01/1970  00:00:00").getTime() / 1000);

Sie können die Zeichenfolge im Parameter parse () -Methoden bearbeiten.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.