¿Cómo puedo crear un Java 8 LocalDate a partir de una larga época en milisegundos?

218

Tengo una API externa que me devuelve fechas como longs, representadas como milisegundos desde el comienzo de la época.

Con la API de Java de estilo antiguo, simplemente construiría una Datede ella con

Date myDate = new Date(startDateLong)

¿Cuál es el equivalente en Java 8's LocalDate/ LocalDateTimeclasses?

Estoy interesado en convertir el punto en el tiempo representado por longa LocalDateen mi zona horaria local actual.

Vihung
fuente
66
Bueno, debes comenzar por determinar qué zona horaria te importa. Un valor de "milisegundos desde época" le proporciona un instante en el tiempo ... que podría referirse a diferentes fechas en diferentes zonas horarias. Tenga en cuenta que java.util.Datenunca fue realmente una cita en la forma en que lo LocalDatees, también fue un instante en el tiempo.
Jon Skeet
2
Marque esta pregunta: ¿ stackoverflow.com/questions/21242110/... , que cubre la conversión de java.util.DateenLocalDate
hotzst
3
Nota: Este Q&A también es valioso para aquellos que intentan convertir File.lastModified()(epoch millis) a LocalDate(Time).
kevinarpe

Respuestas:

403

Si tiene los milisegundos desde la época y desea convertirlos a una fecha local utilizando la zona horaria local actual, puede usar

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

pero tenga en cuenta que incluso la zona horaria predeterminada del sistema puede cambiar, por lo tanto, el mismo longvalor puede producir resultados diferentes en ejecuciones posteriores, incluso en la misma máquina.

Además, tenga en cuenta que LocalDate, a diferencia java.util.Date, realmente representa una fecha, no una fecha y hora.

De lo contrario, puede usar un LocalDateTime:

LocalDateTime date =
    LocalDateTime.ofInstant(Instant.ofEpochMilli(longValue), ZoneId.systemDefault());
Holger
fuente
2
+1 de mi parte para una explicación más detallada. Por cierto, incluso una zona que no es del sistema puede cambiar (por tzupdater-tool o por jdk-change) y, por lo tanto, producir resultados diferentes antes y después.
Meno Hochschild
2
@Meno Hochschild: no me enfocaba en las zonas horarias codificadas, sino que las comparaba con las zonas horarias especificadas por el usuario, leídas de un archivo de configuración o variables de entorno, donde el programador supone naturalmente que puede cambiar. Las zonas horarias codificadas son muy parecidas a las predeterminadas del sistema; el programador es tentado a pensar que nunca fueron cambiando ...
Holger
2
@Demigod LocalDateTime.ofEpochSecond(…)requiere un real ZoneOffset, pero ZoneId.systemDefault()devuelve un ZoneId. A se ZoneIdpuede asignar a diferentes desplazamientos, según el momento al que se refiera. Eso es lo que LocalDateTime.ofInstanthace por usted, convirtiendo lo especificado de ZoneIdacuerdo con lo proporcionado Instant.
Holger
2
Epoch se define como UTC y, por lo tanto, debe ser independiente de la zona horaria, por lo que ZoneId siempre debe ser UTC.
PlexQ
2
@PlexQ La zona horaria especificada no es relevante para la época, que de hecho es independiente de la zona horaria, sino para la semántica de la resultante LocalDateo LocalDateTime. Puede especificar cualquier zona horaria que desee, siempre que sea coherente con el uso posterior de estos objetos de resultado. Piense en lo que sucede cuando maneja múltiples objetos creados por diferentes métodos. Los casos de uso típicos para la fecha local o la fecha y hora incorporan la zona horaria predeterminada del sistema, por ejemplo, LocalDateTime.now()LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneId.systemDefault())...
Holger
37

Puede comenzar con Instant.ofEpochMilli (largo) :

LocalDate date =
  Instant.ofEpochMilli(startDateLong)
  .atZone(ZoneId.systemDefault())
  .toLocalDate();
Meno Hochschild
fuente
55
+1 por ser explícito sobre la zona horaria. Si se omite, la zona horaria predeterminada actual de la JVM se aplica implícitamente para determinar la fecha. Para cualquier momento dado, la fecha varía en todo el mundo por zona horaria a medida que un nuevo día amanece más temprano en el este.
Basil Bourque
12

Creo que tengo una mejor respuesta.

new Timestamp(longEpochTime).toLocalDateTime();
Abhijeet
fuente
nueva marca de tiempo (ts) .toLocalDateTime (). toLocalDate ()
Stepan Yakovenko
55
Quiero decir, si no te importa importar javal.sql.Timestamp, que, dada la naturaleza monolítica de Java, supongo que está bien porque es solo parte de la JVM ... pero se siente un poco mal, pero aún así me gusta más como Reconoció que la época está fundamentalmente en UTC.
PlexQ
1
La Timestampclase está mal diseñada y anticuada desde hace mucho tiempo. Su código utilizará la configuración de zona horaria de la JVM, pero dado que esta configuración puede ser cambiada por otra parte de su programa u otro programa que se ejecute en la misma JVM, no podemos estar seguros de qué es.
Ole VV
1
Siempre es mejor ser explícito sobre qué zona horaria se usa. Usar el antiguo java.sql.Timestamp tiene el inconveniente de tener la zona horaria del sistema aplicada implícitamente, lo que generalmente causa confusión entre los desarrolladores.
Ruslan
3

Dejando a un lado las zonas horarias y otras cosas, una alternativa muy simple new Date(startDateLong)podría serLocalDate.ofEpochDay(startDateLong / 86400000L)

Michael Piefel
fuente
66
Creo que al menos deberías explicar qué significa el 86400000L.
BAERUS
3
Pensé que era muy fácil detectar que es la cantidad de milisegundos en un día.
Michael Piefel
77
Para algunos lo es, y pensé que solo eso tendría sentido, pero sin volver a calcular cuántos ms tiene realmente un día, no estaría seguro. Solo hablando por mí mismo, no conozco este número tan bien que automáticamente sé lo que significa.
BAERUS
Tenga en cuenta también que la respuesta aceptada realmente es la mejor respuesta, simplemente se ve abrumadora. Mi simple truco solo puede ser suficiente en muchos casos. Es una pena que java.timeno se incluya DateTimeConstantscomo lo hizo Joda.
Michael Piefel
2
java.util.concurrent.TimeUnit.MILLISECONDS.toDays(startDateLong)
Vadzim
1

reemplace now.getTime () con su valor largo.

//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));
Santhosh Hirekerur
fuente
-6

En un caso específico donde la marca de tiempo de los segundos de la época proviene de SQL o está relacionada con SQL de alguna manera, puede obtenerla de esta manera:

long startDateLong = <...>

LocalDate theDate = new java.sql.Date(startDateLong).toLocalDate();
M. Prokhorov
fuente
2
Esto realmente no se relaciona mucho con la pregunta formulada
Ketan R
@KetanR, no estoy de acuerdo. La pregunta es "cómo obtener un LocalDatede epoch-millis", y muestro cómo, usando la java.sql.Datetaquigrafía. Este enfoque tiene sentido en el código que ya está lidiando con JDBC en cierta capacidad, y funciona bien. Si aún no está convencido, explique cómo no está relacionado con la pregunta inicial.
M. Prokhorov
2
Si lee la pregunta, dice "API externa que me devuelve fechas tan largas" y está explicando cómo se puede hacer esta conversión si está recibiendo una fecha larga de SQL. Su respuesta explica un caso muy específico de la conversión de fecha, pero no es realmente relevante para la pregunta que se ha hecho. Sin embargo, su explicación podría ser una respuesta válida a alguna otra pregunta relacionada.
Ketan R
@KetanR, si uno recibe una fecha larga de SQL, le aconsejaría cambiar su esquema para que ya no reciba fechas de esa forma. Sin embargo, si uno recibe fechas como marcas de tiempo de milisegundos de otra parte (la API externa), e inmediatamente usa estas fechas para hacer consultas JDBC, entonces el java.sql.Dateenfoque está entre los más cortos disponibles, en cuanto a código, y yo diría que no es tan útil ir Instantcon todos los objetos temporales intermedios cuando el resultado final es el mismo.
M. Prokhorov
2
Como ya he dicho y es evidente por su última explicación, su respuesta es correcta, pero no por la pregunta en cuestión. La pregunta dice: "Estoy interesado en convertir el punto en el tiempo representado por el largo en una Fecha Local en mi zona horaria local actual. "su respuesta dice:" reciba fechas como marcas de tiempo millis, e inmediatamente use estas fechas para hacer consultas JDBC ". No entiendo lo que no está claro aquí?
Ketan R