Come estrarre epoch da LocalDate e LocalDateTime?


102

Come estrarre il valore dell'epoca in Longdalle istanze di LocalDateTimeo LocalDate? Ho provato quanto segue, ma mi dà altri risultati:

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

Quello che voglio è semplicemente il valore 1391539861per il datetime locale "04.02.2014 19:51:01". Il mio fuso orario è Europe/OsloUTC + 1 con l'ora legale.


Spiega il tuo numero previsto 1396468261. Ottengo senza correzione del fuso orario: 1391543461 (vedi modifica nella mia risposta). 57 giorni di differenza!
Meno Hochschild

@MenoHochschild Ho aggiornato la mia domanda con le informazioni sul fuso orario e ho corretto il valore effettivo da GTM a localtime. C'è un modo più semplice per ottenere l'epoca di qualcun LocalDateTimealtro che calcolarlo manualmente?

Tornando dalla mia pausa, guarda il mio aggiornamento.
Meno Hochschild

Risposte:


147

Le classi LocalDatee LocalDateTimenon contengono informazioni sul fuso orario o sulla differenza di fuso orario e i secondi trascorsi da Epoch sarebbero ambigui senza queste informazioni. Tuttavia, gli oggetti dispongono di diversi metodi per convertirli in oggetti data / ora con fusi orari passando ZoneIdun'istanza.

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();

2
È possibile evitare di utilizzare ZoneId o utilizzare con un'istanza ZoneId personalizzata e costante (di +0, che significa GMT)? Lo chiedo perché voglio che tutti i calcoli siano normalizzati su di esso. Inoltre, come faccio il contrario: convertire da epoch time a LocalDate / LocalDateTime (anche senza ZoneId, o con quello GMT)?
sviluppatore Android

2
Non importa. Trovato:ZoneId.ofOffset("UTC", ZoneOffset.ofHours(0))
sviluppatore Android

7
Un approccio più semplice è solo long epoch = time.toEpochSecond(ZoneOffset.UTC)per i casi UTC, o dove conosci già il fuso orario, o long epoch = time.toEpochSecond(ZoneId.systemDefault());se vuoi seguire quella strada.
Marcus

Potrebbe sembrare ridicolo, ma che ne dici di riconvertire da epoch a LocalDate, LocalTime e LocalDateTime
samuel owino

Non importa se penso di averlo trovato; Instant.ofEpochMilli(responseTime).atZone(ZoneId.systemDefault()).toLocalTime()
samuel owino

27

'Millis since unix epoch' rappresenta un istante, quindi dovresti usare la classe Instant:

private long toEpochMilli(LocalDateTime localDateTime)
{
  return localDateTime.atZone(ZoneId.systemDefault())
    .toInstant().toEpochMilli();
}

non è corretto da usare ZoneId.systemDefault()perché unix epoch si riferisce a UTC
ACV

10

La conversione necessaria richiede l'offset da UTC / Greewich o un fuso orario.

Se avete un offset, esiste un metodo dedicato su LocalDateTimeper questo compito:

long epochSec = localDateTime.toEpochSecond(zoneOffset);

Se hai solo un ZoneId, puoi ottenerlo ZoneOffsetda ZoneId:

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

Ma potresti trovare la conversione tramite ZonedDateTimepiù semplice:

long epochSec = ldt.atZone(zoneId).toEpochSecond();

4
Se ti interessa solo l'UTC, c'èlong epochSec = localDateTime.toEpochSecond(ZoneOffset.UTC);
ruhong

2

Guarda questo metodo per vedere quali campi sono supportati. Troverai per 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 

Il campo INSTANT_SECONDS è, ovviamente, non supportato perché a LocalDateTimenon può fare riferimento a nessun timestamp assoluto (globale). Ma ciò che è utile è il campo EPOCH_DAY che conta i giorni trascorsi dal 1970-01-01. Pensieri simili sono validi per il tipo LocalDate(con campi ancora meno supportati).

Se si intende ottenere il campo millis-since-unix-epoch non esistente, è necessario anche il fuso orario per la conversione da un tipo locale a uno globale. Questa conversione può essere eseguita in modo molto più semplice, vedere altri post SO .

Tornando alla tua domanda e ai numeri nel codice:

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 secondi dal 1970-01-01T00: 00: 00 (attenzione, nessun fuso orario) Quindi è possibile sottrarre l'offset del fuso orario (fare attenzione alla possibile moltiplicazione per 1000 se in millisecondi).

AGGIORNAMENTO dopo le informazioni sul fuso orario:

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

Come codice JSR-310 con due approcci equivalenti:

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();

1
Grazie per la spiegazione. Hai ottenuto il risultato giusto usando LocalDateTime time = LocalDateTime.parse("04.02.2014 19:51:01", DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss"));e poi Long epoch = time.atZone(ZoneId.of("Europe/Oslo")).toEpochSecond();.

1

Converti da data leggibile dall'uomo a epoca :

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

Converti da epoca a data leggibile dall'uomo :

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

Per il convertitore di altre lingue: https://www.epochconverter.com


0

Questo è un modo senza utilizzare l'ora di una zona:

LocalDateTime now = LocalDateTime.now();
long epoch = (now.getLong(ChronoField.EPOCH_DAY) * 86400000) + now.getLong(ChronoField.MILLI_OF_DAY);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.