Wie extrahiere ich eine Epoche aus LocalDate und LocalDateTime?

102

Wie extrahiere ich den Epochenwert Longaus Instanzen von LocalDateTimeoder LocalDate? Ich habe Folgendes versucht, aber es gibt mir andere Ergebnisse:

LocalDateTime time = LocalDateTime.parse("04.02.2014  19:51:01", DateTimeFormatter.ofPattern("dd.MM.yyyy  HH:mm:ss"));
System.out.println(time.getLong(ChronoField.SECOND_OF_DAY)); // gives 71461
System.out.println(time.getLong(ChronoField.EPOCH_DAY)); // gives 16105

Was ich will, ist einfach der Wert 1391539861für die lokale Datums- / Uhrzeitangabe "04.02.2014 19:51:01". Meine Zeitzone ist Europe/OsloUTC + 1 mit Sommerzeit.

Vadim Kotov
quelle
Bitte erläutern Sie Ihre erwartete Nummer 1396468261. Ich erhalte ohne Zeitzonenkorrektur: 1391543461 (siehe Bearbeiten in meiner Antwort). 57 Tage Unterschied!
Meno Hochschild
@MenoHochschild Ich habe meine Frage mit Zeitzoneninformationen aktualisiert und den tatsächlichen Wert von GTM auf Ortszeit korrigiert. Gibt es eine einfachere Möglichkeit, die Epoche einer LocalDateTimeanderen zu ermitteln, als sie manuell zu berechnen?
Wenn Sie von meiner Pause zurückkommen, sehen Sie sich mein Update an.
Meno Hochschild

Antworten:

146

Die Klassen LocalDateund LocalDateTimeenthalten keine Informationen über die Zeitzone oder den Zeitversatz sowie Sekunden seit der Epoche, die ohne diese Informationen nicht eindeutig wären. Die Objekte verfügen jedoch über mehrere Methoden, um sie durch Übergeben einer ZoneIdInstanz in Datums- / Zeitobjekte mit Zeitzonen zu konvertieren .

LocalDate

LocalDate date = ...;
ZoneId zoneId = ZoneId.systemDefault(); // or: ZoneId.of("Europe/Oslo");
long epoch = date.atStartOfDay(zoneId).toEpochSecond();

LocalDateTime

LocalDateTime time = ...;
ZoneId zoneId = ZoneId.systemDefault(); // or: ZoneId.of("Europe/Oslo");
long epoch = time.atZone(zoneId).toEpochSecond();
nosid
quelle
2
Ist es möglich, die Verwendung von ZoneId zu vermeiden oder mit einer angepassten, konstanten ZoneId-Instanz (von +0, was GMT bedeutet) zu verwenden? Ich frage dies, weil ich möchte, dass alle Berechnungen darauf normalisiert werden. Wie mache ich das Gegenteil: Konvertieren von der Epochenzeit in LocalDate / LocalDateTime (auch ohne ZoneId oder mit der GMT)?
Android-Entwickler
2
Keine Ursache. Gefunden:ZoneId.ofOffset("UTC", ZoneOffset.ofHours(0))
Android-Entwickler
7
Ein einfacherer Ansatz ist nur long epoch = time.toEpochSecond(ZoneOffset.UTC)für UTC-Fälle oder long epoch = time.toEpochSecond(ZoneId.systemDefault());wenn Sie die Zeitzone bereits kennen oder wenn Sie diesen Weg gehen möchten.
Marcus
Das mag lächerlich klingen, aber wie wäre es mit einer Konvertierung von Epoche zu LocalDate, LocalTime & LocalDateTime
Samuel Owino
Egal, ich glaube ich habe es gefunden; Instant.ofEpochMilli(responseTime).atZone(ZoneId.systemDefault()).toLocalTime()
Samuel Owino
27

'Millis seit Unix-Epoche' stellt einen Augenblick dar, daher sollten Sie die Instant-Klasse verwenden:

private long toEpochMilli(LocalDateTime localDateTime)
{
  return localDateTime.atZone(ZoneId.systemDefault())
    .toInstant().toEpochMilli();
}
Werner Harnisch
quelle
Es ist falsch zu verwenden, ZoneId.systemDefault()da sich die Unix-Epoche auf UTC
ACV
10

Die Konvertierung, die Sie benötigen, erfordert den Offset von UTC / Greewich oder eine Zeitzone.

Wenn Sie einen Offset haben, gibt es eine spezielle Methode auf LocalDateTimefür diese Aufgabe:

long epochSec = localDateTime.toEpochSecond(zoneOffset);

Wenn Sie nur eine haben ZoneId, können Sie die erhalten ZoneOffsetvon ZoneId:

ZoneOffset zoneOffset = ZoneId.of("Europe/Oslo").getRules().getOffset(ldt);

Möglicherweise finden Sie die Konvertierung jedoch ZonedDateTimeeinfacher:

long epochSec = ldt.atZone(zoneId).toEpochSecond();
JodaStephen
quelle
4
Wenn Sie sich nur für UTC interessieren, gibt eslong epochSec = localDateTime.toEpochSecond(ZoneOffset.UTC);
ruhong
2

Sehen Sie sich diese Methode an, um festzustellen, welche Felder unterstützt werden. Sie finden für LocalDateTime:

NANO_OF_SECOND 
NANO_OF_DAY 
MICRO_OF_SECOND 
MICRO_OF_DAY 
MILLI_OF_SECOND 
MILLI_OF_DAY 
SECOND_OF_MINUTE 
SECOND_OF_DAY 
MINUTE_OF_HOUR 
MINUTE_OF_DAY 
HOUR_OF_AMPM 
CLOCK_HOUR_OF_AMPM 
HOUR_OF_DAY 
CLOCK_HOUR_OF_DAY 
AMPM_OF_DAY 
DAY_OF_WEEK 
ALIGNED_DAY_OF_WEEK_IN_MONTH 
ALIGNED_DAY_OF_WEEK_IN_YEAR 
DAY_OF_MONTH 
DAY_OF_YEAR 
EPOCH_DAY 
ALIGNED_WEEK_OF_MONTH 
ALIGNED_WEEK_OF_YEAR 
MONTH_OF_YEAR 
PROLEPTIC_MONTH 
YEAR_OF_ERA 
YEAR 
ERA 

Das Feld INSTANT_SECONDS wird natürlich nicht unterstützt, da a LocalDateTimenicht auf einen absoluten (globalen) Zeitstempel verweisen kann. Hilfreich ist jedoch das Feld EPOCH_DAY, das die seit dem 01.01.1970 verstrichenen Tage zählt. Ähnliche Gedanken gelten für den Typ LocalDate(mit noch weniger unterstützten Feldern).

Wenn Sie das nicht vorhandene Millis-Since-Unix-Epoch-Feld abrufen möchten, benötigen Sie auch die Zeitzone für die Konvertierung von einem lokalen in einen globalen Typ. Diese Konvertierung kann viel einfacher durchgeführt werden, siehe andere SO-Beiträge .

Zurück zu Ihrer Frage und den Zahlen in Ihrem Code:

The result 1605 is correct
  => (2014 - 1970) * 365 + 11 (leap days) + 31 (in january 2014) + 3 (in february 2014)
The result 71461 is also correct => 19 * 3600 + 51 * 60 + 1

16105L * 86400 + 71461 = 1391543461 Sekunden seit 1970-01-01T00: 00: 00 (Aufmerksamkeit, keine Zeitzone) Dann können Sie den Zeitzonenversatz subtrahieren (achten Sie auf mögliche Multiplikation mit 1000, wenn in Millisekunden).

UPDATE nach angegebenen Zeitzoneninformationen:

local time = 1391543461 secs
offset = 3600 secs (Europe/Oslo, winter time in february)
utc = 1391543461 - 3600 = 1391539861

Als JSR-310-Code mit zwei äquivalenten Ansätzen:

long secondsSinceUnixEpoch1 =
  LocalDateTime.of(2014, 2, 4, 19, 51, 1).atZone(ZoneId.of("Europe/Oslo")).toEpochSecond();

long secondsSinceUnixEpoch2 =
  LocalDate
    .of(2014, 2, 4)
    .atTime(19, 51, 1)
    .atZone(ZoneId.of("Europe/Oslo"))
    .toEpochSecond();
Meno Hochschild
quelle
1
Danke für die Erklärung. Erhalten Sie das richtige Ergebnis mit LocalDateTime time = LocalDateTime.parse("04.02.2014 19:51:01", DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss"));und dann Long epoch = time.atZone(ZoneId.of("Europe/Oslo")).toEpochSecond();.
1

Vom vom Menschen lesbaren Datum in die Epoche konvertieren :

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

Von der Epoche zum lesbaren Datum konvertieren :

String date = new java.text.SimpleDateFormat("MM/dd/yyyyHH:mm:ss").format(new java.util.Date (epoch*1000));

Für andere Sprachkonverter: https://www.epochconverter.com

michmich
quelle
0

Dies ist eine Möglichkeit, ohne Zeit und Zone zu verwenden:

LocalDateTime now = LocalDateTime.now();
long epoch = (now.getLong(ChronoField.EPOCH_DAY) * 86400000) + now.getLong(ChronoField.MILLI_OF_DAY);
aled evans
quelle