Como criar um Java 8 LocalDate a partir de um longo período de época em milissegundos?

218

Eu tenho uma API externa que me retorna datas como longs, representadas como milissegundos desde o início da época.

Com a API Java de estilo antigo, eu simplesmente construía uma Datecom

Date myDate = new Date(startDateLong)

Qual é o equivalente em Java 8's LocalDate/ LocalDateTimeclasses?

Estou interessado em converter o ponto no tempo representado por longpara para LocalDateno meu fuso horário local atual.

Vihung
fonte
6
Bem, você precisa começar a trabalhar com o fuso horário. Um valor de "milissegundos desde a época" fornece um instante no tempo ... que pode se referir a diferentes datas em diferentes fusos horários. Lembre-se de que java.util.Datenunca foi realmente um encontro dessa maneira LocalDate- foi um instante no tempo também.
Jon Skeet
2
Verifique esta pergunta: stackoverflow.com/questions/21242110/… , que cobre a conversão de java.util.DateintoLocalDate
hotzst
3
Nota: Essas perguntas e respostas também são valiosas para quem tenta converter File.lastModified()(época milis) para LocalDate(Time).
Kevinarpe

Respostas:

403

Se você possui os milissegundos desde a época e deseja convertê-los em uma data local usando o fuso horário local atual, pode usar

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

mas lembre-se de que mesmo o fuso horário padrão do sistema pode mudar, portanto, o mesmo longvalor pode produzir resultados diferentes nas execuções subseqüentes, mesmo na mesma máquina.

Além disso, lembre-se de que LocalDate, ao contrário java.util.Date, realmente representa uma data, não uma data e hora.

Caso contrário, você pode usar um LocalDateTime:

LocalDateTime date =
    LocalDateTime.ofInstant(Instant.ofEpochMilli(longValue), ZoneId.systemDefault());
Holger
fonte
2
+1 de mim para uma explicação mais detalhada. A propósito, mesmo uma zona que não é do sistema pode mudar (por tzupdater-tool ou por jdk-change) e, portanto, produzir resultados diferentes antes e depois.
Meno Hochschild /
2
@ Meno Hochschild: eu não estava focando em fusos horários codificados, mas comparando com fusos horários especificados pelo usuário, lidos em um arquivo de configuração ou variáveis ​​de ambiente, onde o programador naturalmente assume que isso pode mudar. Os fusos horários codificados são realmente muito parecidos com o padrão do sistema; o programador é tentado a pensar que eles nunca estavam mudando ...
Holger
2
@Demigod LocalDateTime.ofEpochSecond(…)requer um real ZoneOffset, mas ZoneId.systemDefault()retorna a ZoneId. Um ZoneIdpode mapear para diferentes deslocamentos, dependendo do ponto no tempo ao qual você está se referindo. É o que LocalDateTime.ofInstantfaz para você, convertendo o especificado de ZoneIdacordo com o fornecido Instant.
21918 Holger
2
A época é definida como UTC e, portanto, deve ser independente do fuso horário; portanto, o ZoneId deve sempre ser UTC.
PlexQ
2
@PlexQ O fuso horário especificado não é relevante para a Época, que na verdade é independente do fuso horário, mas para a semântica do resultado LocalDateou LocalDateTime. Você pode especificar qualquer fuso horário que desejar, desde que seja consistente com o uso subsequente desses objetos de resultado. Pense no que acontece quando você lida com vários objetos criados por métodos diferentes. Os casos de uso típicos de locais data ou datetimes incorporar fuso horário padrão do sistema, por exemplo LocalDateTime.now()LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneId.systemDefault())...
Holger
37

Você pode começar com Instant.ofEpochMilli (long) :

LocalDate date =
  Instant.ofEpochMilli(startDateLong)
  .atZone(ZoneId.systemDefault())
  .toLocalDate();
Meno Hochschild
fonte
5
+1 por ser explícito sobre o fuso horário. Se omitido, o fuso horário padrão atual da JVM é aplicado implicitamente na determinação da data. Por um determinado momento, a data varia em todo o mundo por fuso horário, à medida que um novo dia aparece mais cedo no leste.
Basil Bourque
12

Eu acho que tenho uma resposta melhor.

new Timestamp(longEpochTime).toLocalDateTime();
Abhijeet
fonte
novo timestamp (ts) .toLocalDateTime (). toLocalDate ()
Stepan Yakovenko
5
Quero dizer - se você não se importa de importar o javal.sql.Timestamp, que, dada a natureza monolítica do Java, suponho que seja bom porque faz parte da JVM ... mas parece um pouco fedorento, mas ainda gosto mais reconheceu que a época está fundamentalmente no UTC.
PlexQ
1
A Timestampclasse é mal projetada e desatualizada há muito tempo. Seu código usará a configuração de fuso horário da JVM, mas como essa configuração pode ser alterada por outra parte do seu programa ou outro programa em execução na mesma JVM, não podemos ter certeza do que é.
Ole VV
1
É sempre melhor ser explícito sobre qual fuso horário é usado. O timestamp tem a desvantagem de aplicar o fuso horário do sistema implicitamente, o que geralmente causa confusão entre os desenvolvedores.
Ruslan
3

Fusos horários e outras coisas de lado, uma alternativa muito simples new Date(startDateLong)poderia serLocalDate.ofEpochDay(startDateLong / 86400000L)

Michael Piefel
fonte
6
Eu acho que você deveria pelo menos explicar o que significa o 86400000L.
BAERUS
3
Eu pensei que era muito fácil perceber que é o número de milissegundos em um dia.
Michael Piefel 01/06/19
7
Para alguns, é verdade, e imaginei que apenas isso faria sentido, mas sem recálculo quantos ms por dia realmente existem, eu não teria certeza. Falando por mim, não conheço esse número tão bem que sei automaticamente o que ele representa.
BAERUS
Observe também que a resposta aceita é realmente a melhor, apenas parece esmagadora. Meu hack simples é suficiente em muitos casos. É uma pena que java.timenão inclua DateTimeConstantscomo Joda.
precisa saber é o seguinte
2
java.util.concurrent.TimeUnit.MILLISECONDS.toDays(startDateLong)
Vadzim
1

substitua now.getTime () pelo seu valor longo.

//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
fonte
-6

Em um caso específico em que o carimbo de data e hora da sua época é proveniente do SQL ou está relacionado ao SQL de alguma forma, você pode obtê-lo assim:

long startDateLong = <...>

LocalDate theDate = new java.sql.Date(startDateLong).toLocalDate();
M. Prokhorov
fonte
2
Isso realmente não se relaciona muito com a pergunta feita
Ketan R
@KetanR, eu discordo. A questão é "como obter um LocalDatede epoch-millis", e eu mostro como, usando java.sql.Datepara abreviar. Essa abordagem faz sentido no código que já está lidando com o JDBC em alguma capacidade e funciona muito bem. Se você ainda não está convencido, explique como isso não está relacionado à pergunta inicial.
Prokhorov M.
2
Se você ler a pergunta, ela diz "API externa que me retorna datas como longas" e você está explicando como essa conversão pode ser feita se você estiver recebendo uma data longa do SQL. Sua resposta explica um caso muito específico da conversão de datas, mas não é realmente relevante para a pergunta que foi feita. Sua explicação pode ser uma resposta válida para algum outro questionamento relacionado.
Ketan R
@KetanR, se alguém receber uma data longa do SQL, aconselho a alterar seu esquema para que ele não receba mais datas dessa forma. No entanto, se alguém recebe datas como milissegundos de outros lugares (a API externa) e imediatamente usa essas datas para fazer consultas JDBC, a java.sql.Dateabordagem está entre as mais curtas disponíveis, em termos de código, e eu diria que não é tão útil ir embora Instantcom todos os objetos temporais intermediários quando o resultado final for o mesmo.
M. Prokhorov
2
Como já disse e é evidente em sua explicação mais recente, sua resposta está correta, mas não para a pergunta em questão. A pergunta diz: "Estou interessado em converter o ponto no tempo representado pelo tempo em um LocalDate no meu fuso horário local atual. "sua resposta diz:" receba datas como milissegundos e use essas datas imediatamente para fazer consultas JDBC ". Eu não entendo o que não está claro aqui?
precisa