Cómo obtener milisegundos de LocalDateTime en Java 8

285

Me pregunto si hay una manera de conseguir milisegundos actuales desde 01/01/1970 (época) utilizando el nuevo LocalDate, LocalTimeo LocalDateTimeclases de Java 8.

La forma conocida es la siguiente:

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

o

long currentMilliseconds = System.currentTimeMillis();
George Siggouroglou
fuente
66
¿Qué tiene de malo System.currentTimeMillis()?
Dawood ibn Kareem
16
@DavidWallace ¿Está tratando de obtener la hora de una fecha, no la hora actual?
Anubian Noob
2
"... una forma de obtener milisegundos actuales ..."
Dawood ibn Kareem
milisegundos contando desde 1-1-1970. Estaba deambulando si hay un método para obtenerlos usando las nuevas clases de Java 8 LocalDate, LocalTime y LocalDateTime, porque no encontré uno.
George Siggouroglou
1
Mi comprensión del propósito para esas clases es que es una comprensión del tiempo "centrada en los humanos", y currentTimeMillissería irrelevante en ese contexto. Piense en Calendario + Reloj de pared con muy buena precisión y sin preocupaciones sobre zonas horarias y localidades. Así que no hay forma de volver a la "hora UTC" desde un horario local
Gus

Respuestas:

325

No estoy completamente seguro de lo que quiere decir con "milisegundos actuales", pero supongo que es la cantidad de milisegundos desde la "época", es decir, la medianoche, 1 de enero de 1970 UTC.

Si desea encontrar el número de milisegundos desde la época en este momento, utilice System.currentTimeMillis()como Anubian Noob ha señalado . Si es así, no hay razón para usar ninguna de las nuevas API java.time para hacer esto.

Sin embargo, tal vez ya tenga un LocalDateTimeobjeto similar en algún lugar y desee convertirlo a milisegundos desde la época. No es posible hacer eso directamente, ya que la LocalDateTimefamilia de objetos no tiene idea de en qué zona horaria se encuentran. Por lo tanto, se debe proporcionar información sobre la zona horaria para encontrar la hora relativa a la época, que está en UTC.

Supongamos que tienes una LocalDateTimecomo esta:

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

Debe aplicar la información de zona horaria, dando a ZonedDateTime. Estoy en la misma zona horaria que Los Ángeles, así que haría algo como esto:

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

Por supuesto, esto hace suposiciones sobre la zona horaria. Y hay casos extremos que pueden ocurrir, por ejemplo, si la hora local indica una hora cercana a la transición del horario de verano (horario de verano). Dejemos esto de lado, pero debe tener en cuenta que estos casos existen.

De todos modos, si puede obtener un valor válido ZonedDateTime, puede convertirlo a la cantidad de milisegundos desde la época, así:

long millis = zdt.toInstant().toEpochMilli();
Stuart Marks
fuente
55
Tenga en cuenta que ZonedDateTime ya tiene el getEpochSecondmétodo (a través de ChronoZonedDateTime predeterminado ). No es necesario para el Instant.
mabi
13
Claro, si todo lo que necesita son segundos, no milisegundos.
Stuart Marks,
1
Ah, bueno, yo era imprecisa: ZonedDateTimetambién tiene Instants getNanométodo, por lo que usted no sería capaz de reemplazar simplemente instcon zdten su ejemplo?
mabi
18
Evite las matemáticas en nanos usando zdt.get (ChronoField.MILLI_OF_SECOND). Evite todas las matemáticas usando zdt.toInstant (). ToEpochMilli ()
JodaStephen
2
@PerLundberg acabo de comparación ZonedDateTime.now().toInstant().toEpochMilli(), LocalDateTime.now().toInstant(OffsetDateTime.now().getOffset()).toEpochMilli(), LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli(), Calendar.getInstance().getTime().getTime(), new Date().getTime()y System.currentTimeMillis(). El único método que parece "apagado" es el que propuso: LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli()le da los millis para su fecha local como si fuera una fecha UTC , es decir, si la fecha local es UTC + 2, su método le da millis durante 2 horas en el futuro .
walen
81

Lo que hago para no especificar una zona horaria es,

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

da

ldt 1424812121078 
ctm 1424812121281

Como puede ver, los números son los mismos, excepto por un pequeño tiempo de ejecución.

En caso de que no le guste System.currentTimeMillis, use Instant.now().toEpochMilli()

brian
fuente
3
No, Epoch es relativo a UTC pero obtiene la hora actual de su zona local.
Rafael Membrives
2
@ ChristofferHammarström la cantidad de milisegundos que han pasado desde la época es un hecho independiente de la zona horaria. Es la misma cantidad de milisegundos, sin importar a qué hora del día lo llames. Los dos resultados son diferentes porque la máquina de Brian tardó 203 milisegundos en ejecutar el segundo comando.
Fletch
¿Está bien usar UTC cuando el usuario puede estar en una zona horaria diferente
GilbertS
2
@GilbertS probablemente nunca debería usar este código exacto, use la API según lo previsto. La fecha y hora siempre debe ser UTC cuando se almacena en una computadora o se transmite a otro usuario. Por lo general, debe presentarse al usuario como una hora local con su propia configuración de zona horaria.
Brian
20

Para evitar ZoneId puedes hacer:

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

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

Obtener 0 como valor, ¡es correcto!

Dani
fuente
8
ZoneOffset.ofTotalSeconds(0)es lo mismo queZoneOffset.UTC
Anton Novopashin
1
Sí, fui yo quien votó por el comentario de @ AntonNovopashin. Como necesitabas UTC, estás bien (quizás quieras mencionar eso en la respuesta). Por cierto, ZoneOffsetes una subclase de ZoneId, por lo que no diría exactamente que lo has evitado, pero mientras estés feliz ...
Ole VV
Mi primer comentario fue un poco duro, pero no fue tan ofensivo. Te ofendiste. Lo siento. Lo he borrado Permítame preguntar al revés: ¿cuál podría ser nuestra razón para querer evitar ZoneId?
Ole VV
@ OleV.V ¿Está bien usar UTC? No es solo para personas que viven en la zona horaria UTC.
GilbertS
1
@ GilbertS No creo que nadie viva en la zona horaria UTC. Se recomienda utilizar UTC para las horas que se utilizan en diferentes zonas horarias como una buena práctica. Consulte, por ejemplo, las mejores prácticas de Java para la manipulación / almacenamiento de fechas para usuarios geográficamente diversos . ¿O tal vez no entendí tu pregunta?
Ole VV
15

Desde Java 8 puedes llamar java.time.Instant.toEpochMilli().

Por ejemplo la llamada

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

te da los mismos resultados que

final long currentTimeJava1 = System.currentTimeMillis();
Marteng
fuente
1
"le da los mismos resultados que" ... pero consume más energía de la CPU y estresa mucho al recolector de basura.
VasiliNovikov
1
Me gustaría ver lo anterior cuantificado (especialmente para el uso normal, por ejemplo, no para alguna aplicación crítica en tiempo real de rendimiento ...)
Brian Agnew
11

Puede usar java.sql.Timestamptambién para obtener milisegundos.

LocalDateTime now = LocalDateTime.now();
long milliSeconds = Timestamp.valueOf(now).getTime();
System.out.println("MilliSeconds: "+milliSeconds);
Nalam
fuente
Estás ignorando la necesidad crucial de una zona horaria. No recomiendo hacerlo de esta manera. Además, la Timestampclase está desactualizada y llena de problemas de diseño, por lo que prefiero evitarla, especialmente cuando podemos usar las clases de me java.timegusta LocalDateTime.
Ole VV
@ OleV.V. Por curiosidad sobre los problemas de diseño de Timestamp, ¿puedes compartir algún artículo sobre eso? También me ayuda a evitar el uso Timestampde mi código. ¡Gracias!
Nalam
1
En pocas palabras, se implementa como una subclase de, Datepero a menudo no se puede manejar como un Date. La mayoría de los métodos heredados de Datey un constructor están en desuso. Su toStringmétodo utiliza la zona horaria de la JVM, lo que confunde a muchos ya que el mismo Timestampse imprime de manera diferente en diferentes computadoras ( ejemplo ).
Ole VV
Esto es perfecto para pruebas unitarias. Simplemente reemplace el ahora conLocalDate.of(year, month, day)
G_V
Esta debería ser la respuesta aceptada para solucionar los valores "siempre UTC".
LeYAUable
9

Para obtener la hora actual en milisegundos (desde la época), use System.currentTimeMillis().

Anubian Noob
fuente
3

Si tiene un Java 8 Clock, puede usarlo clock.millis()(aunque se recomienda usarlo clock.instant()para obtener un Java 8 Instant, ya que es más preciso).

¿Por qué usarías un reloj Java 8? Entonces, en su marco DI puede crear un bean Clock:

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

y luego en tus pruebas puedes burlarte fácilmente:

@MockBean private Clock clock;

o puedes tener un bean diferente:

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

que ayuda con las pruebas que afirman fechas y horas inconmensurablemente.

JeeBee
fuente
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();
}
Mohamed.Abdo
fuente
0

¿Por qué nadie mencionó el método LocalDateTime.toEpochSecond()?

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

Esto parece mucho más corto que muchas de las respuestas sugeridas anteriormente ...

maxxyme
fuente
Esto es lo que estaba buscando. Esa respuesta aceptada me estaba dando los pelos de punta.
Brill Pappin
Acepte que solo está disponible en API 26: {
Brill Pappin
1
Porque solo da unos segundos. Es extraño que no haya ningún toEpochMillimétodo, teniendo en cuenta el hecho de que puede especificar incluso nanosegundos en LocalDateTime: hay un método LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond).
izogfif