Wie kann ich ein Java 8 LocalDate aus einer langen Epoche in Millisekunden erstellen?

218

Ich habe eine externe API, die mir Daten als longs zurückgibt , dargestellt als Millisekunden seit Beginn der Epoche.

Mit der alten Java-API würde ich einfach eine Datedaraus erstellen

Date myDate = new Date(startDateLong)

Was ist das Äquivalent in Java 8 LocalDate/ LocalDateTimeKlassen?

Ich bin bei der Umwandlung der Zeitpunkt durch die dargestellte interessiert longan eine LocalDatein meiner aktuellen lokalen Zeitzone.

Vihung
quelle
6
Nun, Sie müssen zunächst herausfinden, welche Zeitzone Sie interessiert. Ein Wert "Millisekunden seit Epoche" gibt Ihnen einen Zeitpunkt an, der sich auf verschiedene Daten in verschiedenen Zeitzonen beziehen kann. Denken Sie daran, dass dies java.util.Datenie wirklich ein Datum war LocalDate- es war auch ein Augenblick in der Zeit.
Jon Skeet
2
Überprüfen Sie diese Frage: stackoverflow.com/questions/21242110/… , die die Umwandlung von java.util.DateinLocalDate
hotzst
3
Hinweis: Diese Fragen und File.lastModified()Antworten sind auch für diejenigen hilfreich, die versuchen, (Epoche Millis) zu konvertieren LocalDate(Time).
Kevinarpe

Antworten:

403

Wenn Sie die Millisekunden seit der Epoche haben und sie unter Verwendung der aktuellen lokalen Zeitzone in ein lokales Datum konvertieren möchten, können Sie sie verwenden

LocalDate date =
    Instant.ofEpochMilli(longValue).atZone(ZoneId.systemDefault()).toLocalDate();

Beachten Sie jedoch, dass sich auch die Standardzeitzone des Systems ändern longkann. Daher kann derselbe Wert bei nachfolgenden Läufen zu unterschiedlichen Ergebnissen führen, selbst auf demselben Computer.

Denken Sie außerdem daran LocalDate, dass es sich im Gegensatz zu java.util.Datewirklich um ein Datum handelt, nicht um ein Datum und eine Uhrzeit.

Andernfalls können Sie Folgendes verwenden LocalDateTime:

LocalDateTime date =
    LocalDateTime.ofInstant(Instant.ofEpochMilli(longValue), ZoneId.systemDefault());
Holger
quelle
2
+1 von mir für eine detailliertere Erklärung. Übrigens kann sich auch eine Nicht-Systemzone ändern (per tzupdater-tool oder jdk-change) und somit vorher und nachher unterschiedliche Ergebnisse erzielen.
Meno Hochschild
2
@Meno Hochschild: Ich habe mich nicht auf fest codierte Zeitzonen konzentriert, sondern mit vom Benutzer angegebenen Zeitzonen verglichen, die aus einer Konfigurationsdatei oder Umgebungsvariablen gelesen wurden, wobei der Programmierer natürlich davon ausgeht, dass sich die ändern können. Fest codierte Zeitzonen ähneln in der Tat dem Systemstandard. Der Programmierer ist versucht zu glauben, sie würden sich nie ändern ...
Holger
2
@Demigod LocalDateTime.ofEpochSecond(…)benötigt eine tatsächliche ZoneOffset, gibt aber ZoneId.systemDefault()eine zurück ZoneId. A ZoneIdkann je nach dem Zeitpunkt, auf den Sie sich beziehen, verschiedenen Offsets zugeordnet werden. Das ist es, was LocalDateTime.ofInstantfür Sie getan wird, indem Sie die angegebenen ZoneIdgemäß den bereitgestellten konvertieren Instant.
Holger
2
Epoche ist als UTC definiert und sollte daher zeitzonenunabhängig sein, daher sollte die ZoneId immer UTC sein.
PlexQ
2
@PlexQ Die angegebene Zeitzone ist nicht relevant für die Epoche, die zwar zeitzonenunabhängig ist, sondern für die Semantik des resultierenden LocalDateoder LocalDateTime. Sie können eine beliebige Zeitzone angeben, sofern dies mit der späteren Verwendung dieser Ergebnisobjekte vereinbar ist. Überlegen Sie, was passiert, wenn Sie mit mehreren Objekten arbeiten, die mit unterschiedlichen Methoden erstellt wurden. Die typischen Anwendungsfälle für lokales Datum oder Datum beinhalten die Standardzeitzone des Systems, z. B. LocalDateTime.now()LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneId.systemDefault())
Holger
37

Sie können mit Instant.ofEpochMilli (lang) beginnen :

LocalDate date =
  Instant.ofEpochMilli(startDateLong)
  .atZone(ZoneId.systemDefault())
  .toLocalDate();
Meno Hochschild
quelle
5
+1 für die explizite Angabe der Zeitzone. Wenn nicht angegeben, wird die aktuelle Standardzeitzone der JVM implizit bei der Bestimmung des Datums angewendet. Für jeden Moment variiert das Datum weltweit je nach Zeitzone, da im Osten früher ein neuer Tag beginnt.
Basil Bourque
12

Ich denke, ich habe eine bessere Antwort.

new Timestamp(longEpochTime).toLocalDateTime();
Abhijeet
quelle
neuer Zeitstempel (ts) .toLocalDateTime (). toLocalDate ()
Stepan
5
Ich meine - wenn es Ihnen nichts ausmacht, javal.sql.Timestamp zu importieren, was angesichts der monolithischen Natur von Java vermutlich in Ordnung ist, weil es nur ein Teil der JVM ist ... aber es fühlt sich ein bisschen stinkend an, aber ich mag es immer noch besser als Es wurde erkannt, dass die Epoche grundsätzlich in UTC liegt.
PlexQ
1
Die TimestampKlasse ist schlecht gestaltet und längst veraltet. Ihr Code verwendet die Zeitzoneneinstellung der JVM. Da diese Einstellung jedoch von einem anderen Teil Ihres Programms oder einem anderen Programm, das in derselben JVM ausgeführt wird, geändert werden kann, können wir nicht ganz sicher sein, um was es sich handelt.
Ole VV
1
Es ist immer besser, explizit anzugeben, welche Zeitzone verwendet wird. Die Verwendung des alten java.sql.Timestamp hat den Nachteil, dass die Systemzeitzone implizit angewendet wird, was normalerweise zu Verwirrung unter den Entwicklern führt.
Ruslan
3

Zeitzonen und andere Dinge beiseite, eine sehr einfache Alternative zu sein new Date(startDateLong)könnteLocalDate.ofEpochDay(startDateLong / 86400000L)

Michael Piefel
quelle
6
Ich denke, Sie sollten zumindest erklären, wofür der 86400000L steht.
BAERUS
3
Ich fand es sehr leicht zu erkennen, dass es sich um die Anzahl der Millisekunden pro Tag handelt.
Michael Piefel
7
Für einige ist es das, und ich dachte mir, dass nur das Sinn machen würde, aber ohne eine Neuberechnung, wie viele ms ein Tag wirklich hat, wäre ich mir nicht sicher. Wenn ich nur für mich selbst spreche, kenne ich diese Nummer nicht so gut, dass ich automatisch weiß, wofür sie steht.
BAERUS
Beachten Sie auch, dass die akzeptierte Antwort wirklich die beste Antwort ist, sie sieht einfach überwältigend aus. Mein einfacher Hack reicht in vielen Fällen einfach aus. Es ist schade, dass java.timees nicht so ist DateTimeConstantswie Joda.
Michael Piefel
2
java.util.concurrent.TimeUnit.MILLISECONDS.toDays(startDateLong)
Vadzim
1

Ersetzen Sie now.getTime () durch Ihren langen Wert.

//GET UTC time for current date
        Date now= new Date();
        //LocalDateTime utcDateTimeForCurrentDateTime = Instant.ofEpochMilli(now.getTime()).atZone(ZoneId.of("UTC")).toLocalDateTime();
        LocalDate localDate = Instant.ofEpochMilli(now.getTime()).atZone(ZoneId.of("UTC")).toLocalDate();
        DateTimeFormatter dTF2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
        System.out.println(" formats as " + dTF2.format(utcDateTimeForCurrentDateTime));
Santhosh Hirekerur
quelle
-6

In einem bestimmten Fall, in dem Ihr Zeitstempel für Epochensekunden aus SQL stammt oder irgendwie mit SQL zusammenhängt, können Sie ihn folgendermaßen erhalten:

long startDateLong = <...>

LocalDate theDate = new java.sql.Date(startDateLong).toLocalDate();
M. Prokhorov
quelle
2
Dies hat nicht wirklich viel mit der gestellten Frage zu
tun
@ KetanR, ich bin anderer Meinung. Die Frage ist "wie man ein LocalDatevon erhält epoch-millis", und ich zeige, wie man es mit java.sql.DateKurzschrift verwendet. Dieser Ansatz ist in Code sinnvoll, der sich bereits in gewisser Weise mit JDBC befasst, und funktioniert einwandfrei. Wenn Sie immer noch nicht überzeugt sind, erklären Sie, wie es nicht mit der Ausgangsfrage zusammenhängt.
M. Prokhorov
2
Wenn Sie die Frage lesen, heißt es "Externe API, die mir Daten als Longs zurückgibt" und Sie erklären, wie diese Konvertierung durchgeführt werden kann, wenn Sie ein langes Datum von SQL erhalten. Ihre Antwort erklärt zwar einen ganz bestimmten Fall der Datumskonvertierung, ist jedoch für die gestellte Frage nicht wirklich relevant. Ihre Erklärung könnte jedoch eine gültige Antwort auf eine andere verwandte Frage sein.
Ketan R
@KetanR, wenn jemand ein langes Datum von SQL erhält, würde ich empfehlen, sein Schema zu ändern, damit er keine Daten in dieser Form mehr erhält. Wenn man jedoch Daten als Millis-Zeitstempel von einer anderen Stelle (der externen API) empfängt und diese Daten sofort verwendet, um JDBC-Abfragen durchzuführen, gehört der java.sql.DateAnsatz zu den kürzesten verfügbaren Codes, und ich würde sagen, dass er nicht allzu nützlich ist Instantmit allen zeitlichen Zwischenobjekten zu gehen, wenn das Endergebnis das gleiche ist.
M. Prokhorov
2
Wie ich bereits gesagt habe und aus Ihrer letzten Erklärung hervorgeht, ist Ihre Antwort richtig, aber nicht für die vorliegende Frage. Die Frage lautet: "Ich bin daran interessiert, den durch das lange dargestellten Zeitpunkt in ein lokales Datum in meiner aktuellen lokalen Zeitzone umzuwandeln. "Ihre Antwort lautet:" Empfangen Sie Daten als Millis-Zeitstempel und verwenden Sie diese Daten sofort, um JDBC-Abfragen durchzuführen. " Ich verstehe nicht, was hier nicht klar ist?
Ketan R