Ich versuche die Differenz zwischen zwei zu berechnen LocalDateTime
.
Die Ausgabe muss das Format haben y years m months d days h hours m minutes s seconds
. Folgendes habe ich geschrieben:
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneId;
public class Main {
static final int MINUTES_PER_HOUR = 60;
static final int SECONDS_PER_MINUTE = 60;
static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
public static void main(String[] args) {
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 9, 19, 46, 45);
LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);
Period period = getPeriod(fromDateTime, toDateTime);
long time[] = getTime(fromDateTime, toDateTime);
System.out.println(period.getYears() + " years " +
period.getMonths() + " months " +
period.getDays() + " days " +
time[0] + " hours " +
time[1] + " minutes " +
time[2] + " seconds.");
}
private static Period getPeriod(LocalDateTime dob, LocalDateTime now) {
return Period.between(dob.toLocalDate(), now.toLocalDate());
}
private static long[] getTime(LocalDateTime dob, LocalDateTime now) {
LocalDateTime today = LocalDateTime.of(now.getYear(),
now.getMonthValue(), now.getDayOfMonth(), dob.getHour(), dob.getMinute(), dob.getSecond());
Duration duration = Duration.between(today, now);
long seconds = duration.getSeconds();
long hours = seconds / SECONDS_PER_HOUR;
long minutes = ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
long secs = (seconds % SECONDS_PER_MINUTE);
return new long[]{hours, minutes, secs};
}
}
Die Ausgabe, die ich bekomme, ist 29 years 8 months 24 days 12 hours 0 minutes 50 seconds
. Ich habe mein Ergebnis von dieser Website überprüft (mit Werten 12/16/1984 07:45:55
und 09/09/2014 19:46:45
). Der folgende Screenshot zeigt die Ausgabe:
Ich bin mir ziemlich sicher, dass die Felder nach dem Monatswert in meinem Code falsch sind. Jeder Vorschlag wäre sehr hilfreich.
Aktualisieren
Ich habe mein Ergebnis von einer anderen Website getestet und das Ergebnis ist anders. Hier ist es: Berechnen Sie die Dauer zwischen zwei Daten (Ergebnis: 29 Jahre, 8 Monate, 24 Tage, 12 Stunden, 0 Minuten und 50 Sekunden).
Aktualisieren
Da ich zwei unterschiedliche Ergebnisse von zwei verschiedenen Standorten erhalten habe, frage ich mich, ob der Algorithmus meiner Berechnung legitim ist oder nicht. Wenn ich folgende zwei LocalDateTime
Objekte verwende:
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 40, 45);
LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);
Dann kommt die Ausgabe: 29 years 8 months 25 days -1 hours -5 minutes -10 seconds.
Von diesem Link sollte es sein 29 years 8 months 24 days 22 hours, 54 minutes and 50 seconds
. Der Algorithmus muss also auch die negativen Zahlen verarbeiten.
Beachten Sie, dass es bei der Frage nicht darum geht, welche Site mir welches Ergebnis gebracht hat. Ich muss den richtigen Algorithmus kennen und die richtigen Ergebnisse erzielen.
Period.between()
eine Rundung anwenden?7:45:55
und die Endzeit19:46:45
(oder7:46:45
PM). Der Unterschied zwischen diesen beiden Zeiten beträgt also 12 Stunden, 0 Minuten und 50 Sekunden und niemals 23 Stunden, 34 Minuten und 12 Sekunden. Ihre tatsächliche Berechnung scheint also zumindest zeitlich korrekt zu sein.LocalDateTime
es möglicherweise keine eindeutige Antwort gibt , da es keine Zeitzone gibt. Selbst wenn Sie davon ausgehen, dass die Start- und Endzeitzonen gleich sind, werden in bestimmten Zonen Daten wie der 09.09.2014 in der Sommerzeit oder in der Sommerzeit angezeigt, in anderen nicht. Dies könnte die Dinge um eine Stunde abwerfen. Die Berechnung der Differenz zur Sekunde ist also bedeutungslos, es sei denn, dies wird behoben.LocalDateTime
unrealistische Ergebnisse liefert, da dieser Klasse absichtlich ein Konzept der Zeitzone oder des Versatzes von UTC fehlt? Weisen Sie für realistische Werte eineZoneId
zu verwendende Zeitzone über zuZonedDateTime
.Antworten:
Leider scheint es keine Zeitklasse zu geben, die sich auch über die Zeit erstreckt. Daher müssen Sie die Berechnungen möglicherweise selbst durchführen.
Glücklicherweise verfügen die Datums- und Zeitklassen über viele nützliche Methoden, die dies bis zu einem gewissen Grad vereinfachen. Hier ist eine Möglichkeit, die Differenz zu berechnen, obwohl dies nicht unbedingt die schnellste ist:
Die Grundidee lautet: Erstellen Sie ein temporäres Startdatum und erhalten Sie die vollen Jahre bis zum Ende. Passen Sie dieses Datum dann um die Anzahl der Jahre an, sodass das Startdatum weniger als ein Jahr nach dem Ende liegt. Wiederholen Sie dies für jede Zeiteinheit in absteigender Reihenfolge.
Zum Schluss noch ein Haftungsausschluss : Ich habe keine unterschiedlichen Zeitzonen berücksichtigt (beide Daten sollten in derselben Zeitzone liegen) und ich habe auch nicht getestet / überprüft, wie sich die Sommerzeit oder andere Änderungen in einem Kalender ändern (wie die Zeitzonen in Samoa). beeinflussen diese Berechnung. Also vorsichtig verwenden.
quelle
ChronoUnit
:), erledigt aber die Arbeit "von Hand".long minutes = ChronoUnit.MINUTES.between(fromDate, toDate);
müssten Sie immer noch die größeren Einheiten vom Intervall abziehen, da beispielsweise für ein Intervall von mindestens 1 Stunde eine Zahl größer als 59 zurückgegeben würde - und das ist nicht das, was das OP will. Wenn Sie dies berücksichtigen, können Sie nicht nur 6 Anrufe tätigenChronoUnit#between()
und fertig sein.Ich fand den besten Weg, dies zu tun, mit ChronoUnit.
Zusätzliche Dokumentation finden Sie hier: https://docs.oracle.com/javase/tutorial/datetime/iso/period.html
quelle
tempDateTime.until( toDateTime, ChronoUnit.YEARS)
mitChronoUnit.YEARS.between(fromDate, toDate)
. Die wichtigen zusätzlichen Zeilen wietempDateTime.plusYears( years )
usw. fehlen jedoch vollständig in Ihrer Antwort, sodass dies dem OP nicht hilft. Der komplette Algorithmus ist wichtig!Hier ein einzelnes Beispiel mit Duration und TimeUnit, um das Format 'hh: mm: ss' zu erhalten.
quelle
String.format("%02d:%02d:%02d",dur.toHoursPart(), dur.toMinutesPart(), dur.toSecondsPart());
. Die Teilemethoden geben Ihnen die richtigen Zahlen, um eine Zeichenfolge zu erstellen. Ich denke, es ist besser lesbar.Es sollte einfacher sein!
quelle
TL; DR
und dann die Methoden verwenden
period.getYears()
,period.getMonths()
,period.getDays()
,duration.toHoursPart()
,duration.toMinutesPart()
,duration.toSecondsPart()
.Erweiterte Antwort
Ich beantworte die ursprüngliche Frage, dh wie man den Zeitunterschied zwischen zwei
LocalDateTimes
in Jahren, Monaten, Tagen, Stunden und Minuten erhält, so dass die "Summe" (siehe Hinweis unten) aller Werte für die verschiedenen Einheiten der Summe entspricht zeitliche Differenz, und so , dass der Wert in jeder Einheit kleiner ist als die nächst größere Einheit, dhminutes < 60
,hours < 24
und so weiter.Gegeben zwei
LocalDateTimes
start
undend
zwir können die absolute Zeitspanne zwischen den beiden mit einem -
Duration
vielleicht mit darstellenDuration.between(start, end)
. Die größte Einheit, die wir aus a extrahieren können,Duration
sind Tage (als zeitliche Einheit, die 24 Stunden entspricht). Eine Erklärung finden Sie in der folgenden Anmerkung. Um größere Einheiten (Monate, Jahre) zu verwenden, können wir diesDuration
mit einem Paar von (Period
,Duration
) darstellen, wobeiPeriod
die Differenz die Differenz bis zu einer Genauigkeit von Tagen misst und dieDuration
den Rest darstellt:Jetzt können wir einfach die auf
Period
und definierten Methoden verwendenDuration
, um die einzelnen Einheiten zu extrahieren:oder im Standardformat:
Hinweis zu Jahren, Monaten und Tagen
Beachten Sie, dass in
java.time
der Konzeption "Einheiten" wie "Monat" oder "Jahr" keinen festen, absoluten Zeitwert darstellen - sie sind datums- und kalenderabhängig, wie das folgende Beispiel zeigt:quelle
Es gibt ein Problem mit dem Tapas Bose-Code und dem Thomas-Code. Wenn die Zeitdifferenz negativ ist, erhält das Array die negativen Werte. Zum Beispiel wenn
es gibt 0 Jahre 0 Monate 1 Tage -1 Stunden 0 Minuten 0 Sekunden zurück.
Ich denke, die richtige Ausgabe ist: 0 Jahre 0 Monate 0 Tage 23 Stunden 0 Minuten 0 Sekunden.
Ich schlage vor, die LocalDateTime-Instanzen in LocalDate- und LocalTime-Instanzen zu trennen. Danach können wir die Java 8 Period- und Duration-Instanzen erhalten. Die Dauer-Instanz wird nach der Anzahl der Tage und dem Tageszeitwert (<24 Stunden) mit anschließender Korrektur des Periodenwerts getrennt. Wenn der zweite LocalTime-Wert vor dem ersten LocalTime-Wert liegt, muss der Zeitraum um einen Tag verkürzt werden.
Hier ist meine Methode zur Berechnung der LocalDateTime-Differenz:
Die obige Methode kann verwendet werden, um die Differenz lokaler Datums- und Zeitwerte zu berechnen, zum Beispiel:
Es ist praktisch, einen Komponententest für die oben beschriebene Methode zu schreiben (beide sind Mitglieder der PeriodDuration-Klasse). Hier ist der Code:
}}
Alle Tests sind erfolgreich, unabhängig davon, ob der Wert der ersten LocalDateTime vor und für alle LocalTime-Werte liegt.
quelle
java.time.Period
wo Benutzer solche gemischten Zeichen aufgrund unterschiedlichen internen Designs erzwingen / erzeugen können).Und die Version von @Thomas in Groovy mit nimmt die gewünschten Einheiten in eine Liste, anstatt die Werte fest zu codieren. Diese Implementierung (die leicht nach Java portiert werden kann - ich habe die Funktionsdeklaration explizit gemacht) macht den Thomas-Ansatz wiederverwendbarer.
Zum Zeitpunkt dieses Schreibens wird der obige Code zurückgegeben
47 Years, 8 Months, 9 Days, 22 Hours, 52 Minutes, 7 Seconds, 140 Millis
. Und für die Eingabe von @Gennady Kolomoets wird der Code zurückgegeben23 Hours
.Wenn Sie eine Liste von Einheiten angeben, muss diese nach der Größe der Einheiten sortiert sein (größte zuerst):
quelle
Hier ist eine sehr einfache Antwort auf Ihre Frage. Es klappt.
quelle
Age is: 0 years,0 months, 1 days, -10 hours, -48 minutes old
. Ich glaube nicht, dass dies erwünscht war.Joda-Zeit
Da viele der Antworten API 26- Unterstützung erforderten und meine min-API 23 war, löste ich sie mit dem folgenden Code:
quelle
Nach mehr als fünf Jahren beantworte ich meine Frage. Ich denke, dass das Problem mit einer negativen Dauer durch eine einfache Korrektur gelöst werden kann:
Hinweis: Die Website https://www.epochconverter.com/date-difference berechnet den Zeitunterschied jetzt korrekt.
Vielen Dank für Ihre Diskussion und Vorschläge.
quelle
toHours
,toMinutes
undtoSeconds
MethodenDuration
. Seit Java 9 noch mehr vontoMinutesPart()
undtoSecondsPart()
. Und ich sehe keinen Sinn darin, die Stunden, Minuten und Sekunden in ein Array zu packen, nur um sie wieder herauszunehmen. Im Allgemeinen jedoch eine gute Antwort.