Come posso creare un LocalDate Java 8 da un lungo periodo di tempo in millisecondi?


219

Ho un'API esterna che mi restituisce le date come longs, rappresentate come millisecondi dall'inizio dell'epoca.

Con l'API Java vecchio stile, vorrei semplicemente costruirne uno Datecon

Date myDate = new Date(startDateLong)

Qual è l'equivalente nelle classi LocalDate/ LocalDateTimeclassi di Java 8 ?

Sono interessato a convertire il punto nel tempo rappresentato da longa in LocalDatenel mio fuso orario locale attuale.


6
Bene, devi iniziare a capire quale fuso orario ti interessa. Un valore "millisecondi dall'epoca" ti dà un istante nel tempo ... che potrebbe riferirsi a date diverse in fusi orari diversi. Ricorda che java.util.Datenon è mai stato un appuntamento così LocalDatecom'è - è stato anche un istante nel tempo.
Jon Skeet,

2
Controllare questa domanda: stackoverflow.com/questions/21242110/... , che copre la conversione di java.util.DateinLocalDate
hotzst

3
Nota: queste domande e File.lastModified()risposte sono utili anche per chi cerca di convertire (epoca millis) in LocalDate(Time).
kevinarpe,

Risposte:


404

Se hai i millisecondi dall'epoca e desideri convertirli in una data locale utilizzando il fuso orario locale corrente, puoi utilizzare

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

ma tieni presente che anche il fuso orario predefinito del sistema può cambiare, quindi lo stesso longvalore può produrre risultati diversi nelle esecuzioni successive, anche sulla stessa macchina.

Inoltre, tieni presente che LocalDate, a differenza java.util.Date, rappresenta davvero una data, non una data e un'ora.

Altrimenti, puoi usare un LocalDateTime:

LocalDateTime date =
    LocalDateTime.ofInstant(Instant.ofEpochMilli(longValue), ZoneId.systemDefault());

2
+1 da me per una spiegazione più dettagliata. A proposito, anche una zona non di sistema può cambiare (con tzupdater-tool o con jdk-change) e quindi produrre risultati diversi prima e dopo.
Meno Hochschild,

2
@Meno Hochschild: non mi concentravo sui fusi orari hardcoded, ma piuttosto sul confronto con i fusi orari specificati dall'utente, letti da un file di configurazione o da variabili di ambiente, dove il programmatore presume naturalmente che ciò possa cambiare. I fusi orari hardcoded sono in effetti molto simili all'impostazione predefinita del sistema; il programmatore è tentato di pensare che non cambieranno mai ...
Holger,

2
@Demigod LocalDateTime.ofEpochSecond(…)richiede un valore effettivo ZoneOffset, ma ZoneId.systemDefault()restituisce a ZoneId. Un ZoneIdpossibile mappare a diversi offset, a seconda del punto del tempo ti riferisci. Questo è ciò che LocalDateTime.ofInstantfa per te, convertendo lo specificato in ZoneIdbase a quello fornito Instant.
Holger,

2
L'epoca è definita come UTC e dovrebbe quindi essere indipendente dal fuso orario, quindi ZoneId dovrebbe essere sempre UTC.
PlexQ,

2
@PlexQ Il fuso orario specificato non è rilevante per l'epoca, che in effetti è indipendente dal fuso orario, ma per la semantica del risultante LocalDateo LocalDateTime. È possibile specificare qualsiasi fuso orario desiderato, purché sia ​​coerente con l'uso successivo di questi oggetti risultato. Pensa a cosa succede quando hai a che fare con più oggetti creati con metodi diversi. I casi d'uso tipici per locali data o datetimes incorporano il fuso orario di default del sistema, ad esempio LocalDateTime.now()LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneId.systemDefault())...
Holger

37

Puoi iniziare con Instant.ofEpochMilli (long) :

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

5
+1 per essere espliciti sul fuso orario. Se omesso, l'attuale fuso orario predefinito della JVM viene implicitamente applicato nel determinare la data. Per ogni dato momento la data varia in tutto il mondo in base al fuso orario mentre un nuovo giorno sorge prima a est.
Basil Bourque,

12

Penso di avere una risposta migliore.

new Timestamp(longEpochTime).toLocalDateTime();

nuovo Timestamp (ts) .toLocalDateTime (). toLocalDate ()
Stepan Yakovenko il

5
Voglio dire, se non ti dispiace importare javal.sql.Timestamp, che, data la natura monolitica di Java, suppongo che vada bene perché fa solo parte della JVM ... ma sembra un po 'puzzolente, ma mi piace ancora di più ha riconosciuto che l'epoca è fondamentalmente in UTC.
PlexQ,

1
La Timestampclasse è mal progettata e obsoleta da tempo. Il tuo codice utilizzerà l'impostazione del fuso orario della JVM, ma poiché questa impostazione può essere modificata da un'altra parte del programma o da un altro programma in esecuzione nella stessa JVM, non possiamo essere sicuri di cosa si tratti.
Ole VV,

1
È sempre meglio essere espliciti su quale fuso orario viene utilizzato. L'uso del vecchio java.sql.Timestamp ha lo svantaggio di applicare implicitamente il fuso orario del sistema che di solito provoca confusione tra gli sviluppatori.
Ruslan,

3

Fusi orari e cose a parte, new Date(startDateLong)potrebbe essere un'alternativa molto sempliceLocalDate.ofEpochDay(startDateLong / 86400000L)


6
Penso che dovresti almeno spiegare cosa rappresenta l'86400000L.
BAERUS,

3
Ho pensato che fosse molto facile capire che è il numero di millisecondi in un giorno.
Michael Piefel,

7
Per alcuni lo è, e ho pensato che solo questo avrebbe senso, ma senza ricalcolare quanti ms al giorno ha davvero, non ne sarei sicuro. Parlando da solo, non conosco questo numero così bene che so automaticamente cosa rappresenta.
BAERUS

Nota anche che la risposta accettata è davvero la risposta migliore, sembra solo travolgente. Il mio semplice hack è solo il mio bastare in molti casi. È un peccato che java.timenon includa DateTimeConstantscome ha fatto Joda.
Michael Piefel,

2
java.util.concurrent.TimeUnit.MILLISECONDS.toDays(startDateLong)
Vadzim,

1

sostituire now.getTime () con il valore lungo.

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

-6

In un caso specifico in cui il tuo timestamp di epoca deriva da SQL o è in qualche modo correlato a SQL, puoi ottenerlo in questo modo:

long startDateLong = <...>

LocalDate theDate = new java.sql.Date(startDateLong).toLocalDate();

2
Questo non si riferisce molto alla domanda posta
Ketan R

@KetanR, non sono d'accordo. La domanda è: "come ottenere un LocalDateda epoch-millis", e mi mostrano come, usando java.sql.Dateper la stenografia. Questo approccio ha senso nel codice che ha già a che fare con JDBC in qualche modo e funziona perfettamente. Se non sei ancora convinto, spiega in che modo non è correlato alla domanda iniziale.
M. Prokhorov,

2
Se leggi la domanda, dice "API esterna che mi restituisce le date come lunghe" e stai spiegando come questa conversione può essere eseguita se ricevi una lunga data da SQL. La tua risposta spiega un caso molto specifico della conversione della data, ma non è realmente rilevante per la domanda che è stata posta ed. La tua spiegazione potrebbe essere una risposta valida ad altre domande correlate.
Ketan R,

@KetanR, se uno riceve una lunga data da SQL, consiglierei di cambiare il suo schema in modo che non riceva più le date in tale forma. Tuttavia, se si ricevono le date come millisetest da altrove (l'API esterna) e si utilizzano immediatamente queste date per effettuare query JDBC, l' java.sql.Dateapproccio è tra i più brevi disponibili, in termini di codice, e direi che non è poi così utile per andare Instantcon tutti gli oggetti temporali intermedi quando il risultato finale è lo stesso.
M. Prokhorov,

2
Come ho già detto ed è evidente dalla tua ultima spiegazione, la tua risposta è corretta ma non per la domanda a portata di mano La domanda dice: "Sono interessato a convertire il punto nel tempo rappresentato dal lungo in una LocalDate nel mio fuso orario locale attuale. "la tua risposta dice:" ricevi le date come millis-timestamp e usa immediatamente queste date per fare query JDBC ". Non capisco cosa non sia chiaro qui?
Ketan R,
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.