2014-04-10 15 views
43

Come si estrae il valore di epoca su Long da istanze di LocalDateTime o LocalDate? Ho provato quanto segue, ma mi dà altri risultati:Come estrarre epoca da LocalDate e LocalDateTime?

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 1391539861 per il datetime locali "04.02.2014 19:51:01". Il mio fuso orario è Europe/Oslo UTC + 1 con ora legale.

+0

Si prega di spiegare il vostro numero previsto 1396468261. ricevo senza correzione fuso orario: 1.391.543,461 mila (vedi modifica nella mia risposta). 57 giorni di differenza! –

+0

@MenoHochschild Ho aggiornato la mia domanda con informazioni sul fuso orario e corretto il valore reale da GTM a localtime. C'è un modo più semplice per ottenere l'epoca di alcuni 'LocalDateTime' oltre a calcolarlo manualmente? –

+0

Tornando dalla mia pausa, vedi il mio aggiornamento. –

risposta

58

Le classi LocalDate e LocalDateTime non hanno informazioni a proposito del fuso orario fuso orario o . Ciò significa che devi fornire prima il fuso orario corretto.

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

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

+0

Non importa. Trovato: 'ZoneId.ofOffset (" UTC ", ZoneOffset.ofHours (0))' –

0

Vedere this method per vedere quali campi sono supportati. Troverete 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 

L'INSTANT_SECONDS campo è - ovviamente - non supportato perché un LocalDateTime non può riferirsi a qualsiasi 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 desidera 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 SO-posts.

Tornando alla tua domanda ei 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, senza fuso orario) Quindi puoi sottrarre l'offset del fuso orario (fai attenzione alla possibile moltiplicazione per 1000 se in millisecondi).

UPDATE dopo dato informazioni fuso orario:

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

Come JSR-310-codice 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. Ottenuto il risultato giusto usando 'LocalDateTime time = LocalDateTime.parse (" 04.02.2014 19:51:01 ", DateTimeFormatter.ofPattern (" gg.aa.yyyy HH: mm: ss "));' e quindi 'Epoca lunga = time.atZone (ZoneId.of ("Europe/Oslo")). toEpochSecond(); '. –

6

La conversione è necessario richiede l'offset da UTC/Greenwich, o di un fuso orario.

Se avete un offset, c'è un dedicated method su LocalDateTime per questo compito:

long epochSec = localDateTime.toEpochSecond(zoneOffset); 

Se avete solo un ZoneId allora si può ottenere il ZoneOffset dal ZoneId:

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

Ma è possibile trovare la conversione tramite ZonedDateTime più semplice:

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

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

9

'Millis dal unix epoca' rappresenta un istante, così si dovrebbe utilizzare la classe istantaneo:

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