Come ottenere millisecondi da LocalDateTime in Java 8


285

Mi chiedo se c'è un modo per ottenere millisecondi attuali dal 1970/01/01 (epoca) utilizzando il nuovo LocalDate, LocalTimeo di LocalDateTimeclassi di Java 8.

Il modo noto è di seguito:

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

o

long currentMilliseconds = System.currentTimeMillis();

6
Cosa c'è che non va System.currentTimeMillis()?
Dawood ibn Kareem,

16
@DavidWallace Sta cercando di ottenere l'ora di una data, non l'ora corrente?
Anubian Noob,

2
"... un modo per ottenere millisecondi attuali ..."
Dawood ibn Kareem

millisecondi che contano da 1-1-1970. Stavo vagando se esiste un metodo per ottenerli utilizzando le nuove classi di Java 8 LocalDate, LocalTime e LocalDateTime, perché non l'ho trovato.
George Siggouroglou,

1
La mia comprensione dello scopo di quelle classi è che si tratta di una comprensione del tempo "focalizzata sull'uomo", e currentTimeMillissarebbe irrilevante in quel contesto. Pensa a Calendar + Orologio da parete con una precisione davvero buona e senza preoccupazioni per fusi orari e località. Quindi non c'è modo di tornare a "UTC Time" da un LocalTime
Gus

Risposte:


325

Non sono del tutto sicuro di cosa intendi per "millisecondi attuali", ma suppongo che sia il numero di millisecondi dall'epoca "epoca", cioè mezzanotte, 1 gennaio 1970 UTC.

Se vuoi trovare il numero di millisecondi dall'epoca in questo momento, allora usa System.currentTimeMillis()come ha sottolineato Anubian Noob . In tal caso, non c'è motivo di utilizzare nessuna delle nuove API java.time per farlo.

Tuttavia, forse hai già un LocalDateTimeoggetto simile o simile da qualche parte e vuoi convertirlo in millisecondi dall'epoca. Non è possibile farlo direttamente, poiché la LocalDateTimefamiglia di oggetti non ha idea del fuso orario in cui si trovano. Pertanto, è necessario fornire le informazioni sul fuso orario per trovare l'ora relativa all'epoca, che è in UTC.

Supponiamo di avere un LocalDateTimesimile:

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

È necessario applicare le informazioni sul fuso orario, fornendo a ZonedDateTime. Sono nello stesso fuso orario di Los Angeles, quindi farei una cosa del genere:

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

Naturalmente, questo fa ipotesi sul fuso orario. E ci sono casi limite che possono verificarsi, ad esempio, se l'ora locale indica un orario vicino alla transizione dell'ora legale (ora legale). Mettiamoli da parte, ma dovresti essere consapevole che questi casi esistono.

Ad ogni modo, se riesci a ottenere un valore valido ZonedDateTime, puoi convertirlo nel numero di millisecondi dall'epoca, in questo modo:

long millis = zdt.toInstant().toEpochMilli();

5
Nota che ZonedDateTime ha già il getEpochSecondmetodo (tramite impostazione predefinita ChronoZonedDateTime ). Non c'è bisogno di Instant.
mabi,

14
Certo, se tutto ciò che serve è secondi, non millisecondi.
Stuart Marks,

1
Ah bene, ero impreciso: ZonedDateTimeha anche Instantil getNanometodo s , quindi non saresti in grado di sostituirlo instcon il zdttuo esempio?
mabi,

18
Evita la matematica sui nanos usando zdt.get (ChronoField.MILLI_OF_SECOND). Evita tutti i calcoli usando zdt.toInstant (). ToEpochMilli ()
JodaStephen

1
Comunque, dato che sia tu che @walen avete commentato, ho deciso di eliminare i miei messaggi originali ora, per evitare di ingannare le persone.
Per Lundberg, il

81

Quello che faccio, quindi non specificare un fuso orario è,

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

ldt 1424812121078 
ctm 1424812121281

Come puoi vedere, i numeri sono gli stessi tranne per un piccolo tempo di esecuzione.

Nel caso in cui non ti piaccia System.currentTimeMillis, usa Instant.now().toEpochMilli()


3
No, l'epoca è relativa all'ora UTC ma ottieni l'ora corrente dalla tua zona locale.
Rafael Membrives,

2
@ ChristofferHammarström la quantità di millisecondi trascorsi dall'epoca è un fatto indipendente dal fuso orario. È la stessa quantità di millisecondi, indipendentemente dall'ora del giorno in cui lo chiami. I due risultati sono diversi perché la macchina di Brian ha impiegato 203 millisecondi per eseguire il secondo comando.
Fletch,

È possibile utilizzare UTC quando l'utente può trovarsi in un fuso orario diverso
GilbertS

2
@GilbertS probabilmente non dovresti mai usare questo codice esatto, usa l'API come previsto. La data e l'ora devono essere sempre UTC se archiviate su un computer o trasmesse a un altro utente. Di solito dovrebbe essere presentato all'utente come data locale usando le proprie impostazioni del fuso orario.
Brian

20

Per evitare ZoneId puoi fare:

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

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

Ottenere 0 come valore, esatto!


8
ZoneOffset.ofTotalSeconds(0)è lo stesso diZoneOffset.UTC
Anton Novopashin,

1
Sì, sono stato io a votare il commento di AntonNovopashin. Dato che avevi bisogno di UTC, stai bene (potresti voler menzionarlo nella risposta). BTW ZoneOffsetè una sottoclasse di ZoneId, quindi non direi esattamente che l'hai evitato, ma finché sei felice ...
Ole VV

Il mio primo commento è stato un po 'duro, ma non era inteso come offensivo. Ti sei offeso. Mi dispiace. L'ho cancellato Consentitemi di chiedere il contrario: quale potrebbe essere la nostra ragione per voler evitare ZoneId?
Ole VV,

@ OleV.V Va bene usare UTC. Non è solo per le persone che vivono nel fuso orario UTC.
GilbertS

1
@GilbertS Non credo che nessuno viva nel fuso orario UTC. Si consiglia di utilizzare UTC per gli orari utilizzati in più fusi orari. Vedere ad esempio Best practice Java per la manipolazione / archiviazione della data per utenti geograficamente diversi . O forse non ho capito la tua domanda?
Ole VV,

15

Da Java 8 puoi chiamare java.time.Instant.toEpochMilli().

Ad esempio la chiamata

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

ti dà gli stessi risultati di

final long currentTimeJava1 = System.currentTimeMillis();

1
"ti dà gli stessi risultati di" ... ma richiede più potenza della CPU e sollecita molto di più il garbage collector.
Vasili Novikov,

1
Mi piacerebbe vedere quanto sopra quantificato (soprattutto per il normale utilizzo - ad es. Non per alcune applicazioni real-time critiche in termini di prestazioni ...)
Brian Agnew,

11

Puoi usare java.sql.Timestampanche per ottenere millisecondi.

LocalDateTime now = LocalDateTime.now();
long milliSeconds = Timestamp.valueOf(now).getTime();
System.out.println("MilliSeconds: "+milliSeconds);

Stai ignorando la necessità cruciale di un fuso orario. Non consiglio di farlo in questo modo. Anche la Timestampclasse è obsoleta e piena di problemi di progettazione, quindi preferirei evitarlo, specialmente quando possiamo usare le classi da java.timelike LocalDateTime.
Ole VV,

@ OleV.V. Solo curioso dei problemi di progettazione di Timestamp, puoi condividere qualche articolo su questo? Mi aiuta a evitare di usare anche il Timestampmio codice. Grazie!
Nalam,

1
In breve, è implementato come sottoclasse di Datema spesso non può essere gestito come a Date. La maggior parte dei metodi ereditati da Datee un costruttore sono obsoleti. Il suo toStringmetodo utilizza il fuso orario di JVM, che confonde molti poiché lo stesso Timestampviene stampato in modo diverso su computer diversi ( esempio ).
Ole VV,

Questo è perfetto per i test unitari. Basta sostituire ora conLocalDate.of(year, month, day)
G_V

Questa dovrebbe essere la risposta accettata per aggirare i valori "sempre UTC".
LeYAUable

9

Per ottenere l'ora corrente in millisecondi (dall'epoca), utilizzare System.currentTimeMillis().


3

Se hai un Java 8 Clock, puoi usare clock.millis()(anche se ti consiglia di usare clock.instant()Java 8 Instant, poiché è più preciso).

Perché dovresti usare un orologio Java 8? Quindi nel tuo framework DI puoi creare un bean Clock:

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

e poi nei tuoi test puoi facilmente deriderlo:

@MockBean private Clock clock;

oppure puoi avere un bean diverso:

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

che aiuta con test che affermano incommensurabilmente date e orari.


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

0

Perché nessuno ha menzionato il metodo LocalDateTime.toEpochSecond():

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

Questo sembra molto più breve di molte risposte suggerite sopra ...


questo è quello che stavo cercando. Quella risposta accettata mi stava dando i willies.
Brill Pappin,

Accetta il suo disponibile solo in API 26: {
Brill Pappin

1
Perché dà solo pochi secondi. È strano che non esista un toEpochMillimetodo, tenuto conto del fatto che è possibile specificare anche i nanosecondi in LocalDateTime: esiste un metodo LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond).
izogfif
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.