So erhalten Sie Millisekunden von LocalDateTime in Java 8

285

Ich frage mich , ob es einen Weg gibt aktuelle Millisekunden seit 1970.01.01 (Epoche) mit dem neuen zu bekommen LocalDate, LocalTimeoder LocalDateTimeKlassen von Java 8.

Der bekannte Weg ist unten:

long currentMilliseconds = new Date().getTime();

oder

long currentMilliseconds = System.currentTimeMillis();
George Siggouroglou
quelle
6
Was ist los mit System.currentTimeMillis()?
Dawood ibn Kareem
16
@ DavidWallace Er versucht, die Uhrzeit eines Datums zu ermitteln, nicht die aktuelle Uhrzeit?
Anubian Noob
2
"... ein Weg, um aktuelle Millisekunden zu erhalten ..."
Dawood ibn Kareem
Millisekunden zählen vom 1-1-1970. Ich habe gewandert, ob es eine Methode gibt, um sie mit den neuen Klassen von Java 8 LocalDate, LocalTime und LocalDateTime abzurufen, da ich keine gefunden habe.
George Siggouroglou
1
Mein Verständnis des Zwecks für diese Klassen ist, dass es sich um ein "menschlich fokussiertes" Zeitverständnis handelt, currentTimeMillisdas in diesem Zusammenhang irrelevant wäre. Denken Sie an Kalender + Wanduhr mit wirklich guter Präzision und ohne Bedenken hinsichtlich Zeitzonen und Ort. Es gibt also keine Möglichkeit, von einer LocalTime
Gus

Antworten:

325

Ich bin mir nicht ganz sicher, was Sie unter "aktuellen Millisekunden" verstehen, aber ich gehe davon aus, dass dies die Anzahl der Millisekunden seit der "Epoche" ist, nämlich Mitternacht, 1. Januar 1970 UTC.

Wenn Sie die Anzahl der Millisekunden seit der Epoche jetzt ermitteln möchten , verwenden Sie, System.currentTimeMillis()wie Anubian Noob hervorgehoben hat . In diesem Fall gibt es keinen Grund, eine der neuen java.time-APIs zu verwenden.

Vielleicht haben Sie jedoch bereits ein LocalDateTimeoder ein ähnliches Objekt von irgendwoher und möchten es seit der Epoche in Millisekunden konvertieren. Dies ist nicht direkt möglich, da die LocalDateTimeObjektfamilie keine Ahnung hat, in welcher Zeitzone sie sich befinden. Daher müssen Zeitzoneninformationen bereitgestellt werden, um die Zeit relativ zur Epoche in UTC zu ermitteln.

Angenommen, Sie haben Folgendes LocalDateTime:

LocalDateTime ldt = LocalDateTime.of(2014, 5, 29, 18, 41, 16);

Sie müssen die Zeitzoneninformationen anwenden und a ZonedDateTime. Ich bin in der gleichen Zeitzone wie Los Angeles, also würde ich so etwas machen:

ZonedDateTime zdt = ldt.atZone(ZoneId.of("America/Los_Angeles"));

Dies macht natürlich Annahmen über die Zeitzone. Und es gibt Randfälle, die auftreten können, wenn beispielsweise die Ortszeit eine Zeit in der Nähe des Übergangs Sommerzeit (Sommerzeit) benennt. Lassen Sie uns diese beiseite legen, aber Sie sollten sich bewusst sein, dass diese Fälle existieren.

Wie auch immer, wenn Sie eine gültige erhalten können ZonedDateTime, können Sie diese in die Anzahl der Millisekunden seit der Epoche umwandeln, wie folgt:

long millis = zdt.toInstant().toEpochMilli();
Stuart Marks
quelle
5
Beachten Sie, dass ZonedDateTime bereits über die getEpochSecondMethode verfügt ( standardmäßig über ChronoZonedDateTime ). Keine Notwendigkeit für die Instant.
Mabi
13
Sicher, wenn Sie nur Sekunden brauchen, keine Millisekunden.
Stuart Marks
18
Vermeiden Sie die Mathematik auf Nanos mit zdt.get (ChronoField.MILLI_OF_SECOND). Vermeiden Sie alle Mathe mit zdt.toInstant (). ToEpochMilli ()
JodaStephen
2
Beachten Sie, zdt.toInstant().toEpochMilli();dass Sie die Millisekunden für den entsprechenden UTC-Wert erhalten , nicht für Ihre Zonendatumszeit. Ich fand das auf die harte Tour. toInstant()gibt Ihnen einen UTC-Augenblick. Wenn Sie die Ortszeit in Millis möchten, erhalten Sie nicht das, was Sie erwarten . Wenn Sie also z. B. eine Zeitzone von +02: 00 verwenden, beträgt Ihre zurückgegebene Zeit 3600 * 2 * 1000 Millisekunden weniger als erwartet.
Per Lundberg
2
@PerLundberg ich nur verglichen ZonedDateTime.now().toInstant().toEpochMilli(), LocalDateTime.now().toInstant(OffsetDateTime.now().getOffset()).toEpochMilli(), LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli(), Calendar.getInstance().getTime().getTime(), new Date().getTime()und System.currentTimeMillis(). Die einzige Methode, die "aus" zu sein scheint, ist die von Ihnen vorgeschlagene: LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli()Gibt Ihnen die Millis für Ihr lokales Datum an, als wäre es ein UTC-Datum , dh wenn das lokale Datum UTC + 2 ist, gibt Ihre Methode Millis für 2 Stunden in der Zukunft an .
Wal
81

Ich gebe keine Zeitzone an.

System.out.println("ldt " + LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
System.out.println("ctm " + System.currentTimeMillis());

gibt

ldt 1424812121078 
ctm 1424812121281

Wie Sie sehen können, sind die Zahlen bis auf eine kleine Ausführungszeit gleich.

Nur für den Fall, dass Sie System.currentTimeMillis nicht mögen, verwenden Sie Instant.now().toEpochMilli()

brian
quelle
3
Nein, Epoche ist relativ zu UTC, aber Sie erhalten die aktuelle Zeit von Ihrer lokalen Zone.
Rafael Membrives
2
@ ChristofferHammarström Die Anzahl der Millisekunden, die seit der Epoche vergangen sind, ist eine von der Zeitzone unabhängige Tatsache. Es ist die gleiche Anzahl von Millisekunden, egal zu welcher Tageszeit Sie es nennen. Die beiden Ergebnisse sind unterschiedlich, da Brian's Maschine 203 Millisekunden brauchte, um den zweiten Befehl auszuführen.
Fletch
Ist es in Ordnung, UTC zu verwenden, wenn sich der Benutzer möglicherweise in einer anderen Zeitzone befindet
GilbertS
2
@GilbertS Sie sollten wahrscheinlich nie genau diesen Code verwenden, verwenden Sie die API wie vorgesehen. Datum und Uhrzeit sollten immer UTC sein, wenn sie auf einem Computer gespeichert oder an einen anderen Benutzer übertragen werden. Es sollte dem Benutzer normalerweise als lokale Datums- und Uhrzeitangabe unter Verwendung seiner eigenen Zeitzoneneinstellungen angezeigt werden.
Brian
20

Um ZoneId zu vermeiden, können Sie Folgendes tun:

LocalDateTime date = LocalDateTime.of(1970, 1, 1, 0, 0);

System.out.println("Initial Epoch (TimeInMillis): " + date.toInstant(ZoneOffset.ofTotalSeconds(0)).toEpochMilli());

0 als Wert bekommen, das ist richtig!

Dani
quelle
8
ZoneOffset.ofTotalSeconds(0)es ist das gleiche wieZoneOffset.UTC
Anton Novopashin
1
Ja, ich habe @ AntonNovopashins Kommentar positiv bewertet. Da Sie UTC benötigen, geht es Ihnen gut (vielleicht möchten Sie das in der Antwort erwähnen). Übrigens ZoneOffsetist eine Unterklasse von ZoneId, also würde ich nicht genau sagen, dass Sie es vermieden haben, aber solange Sie glücklich sind ...
Ole VV
Mein erster Kommentar war etwas hart, aber nicht als anstößig gedacht. Du hast Anstoß genommen. Tut mir leid. Ich habe es gelöscht. Gestatten Sie mir, umgekehrt zu fragen: Was könnte unser Grund sein, dies zu vermeiden ZoneId?
Ole VV
@ OleV.V Ist es in Ordnung, UTC zu verwenden? Nicht nur für Menschen, die in der UTC-Zeitzone leben.
GilbertS
1
@ Gilbert Ich glaube nicht, dass jemand in der UTC-Zeitzone lebt. Die Verwendung von UTC für Zeiten, die über Zeitzonen hinweg verwendet werden, wird als bewährte Methode empfohlen. Siehe zum Beispiel Java Best Practice für die Datumsmanipulation / -speicherung für geografisch unterschiedliche Benutzer . Oder habe ich deine Frage nicht verstanden?
Ole VV
15

Seit Java 8 können Sie anrufen java.time.Instant.toEpochMilli().

Zum Beispiel der Anruf

final long currentTimeJava8 = Instant.now().toEpochMilli();

gibt Ihnen die gleichen Ergebnisse wie

final long currentTimeJava1 = System.currentTimeMillis();
Marteng
quelle
1
"gibt Ihnen die gleichen Ergebnisse wie" ... benötigt jedoch mehr CPU-Leistung und belastet den Garbage Collector viel mehr.
VasiliNovikov
Ich würde gerne das oben Quantifizierte sehen (insbesondere für den normalen Gebrauch - zB nicht für einige leistungskritische Echtzeitanwendungen ...)
Brian Agnew
11

Sie können java.sql.Timestampauch Millisekunden abrufen.

LocalDateTime now = LocalDateTime.now();
long milliSeconds = Timestamp.valueOf(now).getTime();
System.out.println("MilliSeconds: "+milliSeconds);
Nalam
quelle
Sie ignorieren die entscheidende Notwendigkeit einer Zeitzone. Ich empfehle es nicht so. Außerdem ist die TimestampKlasse längst veraltet und voller Designprobleme, daher möchte ich sie lieber vermeiden, insbesondere wenn wir die Klassen von java.timelike verwenden können LocalDateTime.
Ole VV
@ OleV.V. Nur neugierig auf die Designprobleme von Timestamp, können Sie einen Artikel darüber teilen? Es hilft mir, die Verwendung Timestampmeines Codes zu vermeiden . Vielen Dank!
Nalam
1
Kurz gesagt, es ist als Unterklasse von implementiert Date, kann aber oft nicht als Unterklasse behandelt werden Date. Die meisten von Dateund einem Konstruktor geerbten Methoden sind veraltet. Die toStringMethode verwendet die Zeitzone der JVM, die viele verwirrt, da dieselbe Timestampauf verschiedenen Computern unterschiedlich gedruckt wird ( Beispiel ).
Ole VV
Dies ist perfekt für Unit-Tests. Ersetzen Sie einfach das Jetzt durchLocalDate.of(year, month, day)
G_V
Dies sollte die akzeptierte Antwort sein, um die "immer UTC" -Werte zu umgehen.
LeYAUable
9

Verwenden Sie, um die aktuelle Zeit in Millisekunden (seit der Epoche) abzurufen System.currentTimeMillis().

Anubian Noob
quelle
3

Wenn Sie eine Java 8-Uhr haben, können Sie diese verwenden clock.millis()(obwohl empfohlen wird clock.instant(), eine Java 8-Instanz zu verwenden, da diese genauer ist).

Warum sollten Sie eine Java 8-Uhr verwenden? In Ihrem DI-Framework können Sie also eine Clock-Bean erstellen:

@Bean
public Clock getClock() {
    return Clock.systemUTC();
}

und dann können Sie es in Ihren Tests leicht verspotten:

@MockBean private Clock clock;

oder Sie können eine andere Bohne haben:

@Bean
public Clock getClock() {
    return Clock.fixed(instant, zone);
}

Das hilft bei Tests, die Daten und Zeiten unermesslich bestätigen.

JeeBee
quelle
1
  default LocalDateTime getDateFromLong(long timestamp) {
    try {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneOffset.UTC);
    } catch (DateTimeException tdException) {
      //  throw new 
    }
}

default Long getLongFromDateTime(LocalDateTime dateTime) {
    return dateTime.atOffset(ZoneOffset.UTC).toInstant().toEpochMilli();
}
Mohamed.Abdo
quelle
0

Warum hat niemand die Methode erwähnt LocalDateTime.toEpochSecond():

LocalDateTime localDateTime = ... // whatever e.g. LocalDateTime.now()
long time2epoch = localDateTime.toEpochSecond(ZoneOffset.UTC);

Dies scheint viel kürzer zu sein als viele der oben vorgeschlagenen Antworten ...

maxxyme
quelle
das habe ich gesucht. Diese akzeptierte Antwort gab mir die Willies.
Brill Pappin
Akzeptiere es nur in API 26: {
Brill Pappin
1
Weil es nur Sekunden gibt. Es ist seltsam, dass es keine toEpochMilliMethode gibt , wenn man bedenkt, dass man in LocalDateTime sogar Nanosekunden angeben kann: Es gibt eine Methode LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond).
izogfif