Convertendo Long to Date em Java retorna 1970

119

Tenho uma lista com valores longos (por exemplo: 1220227200, 1220832000, 1221436800 ...) que baixei do serviço da web. Devo convertê-lo para datas. Infelizmente, desta forma, por exemplo:

Date d = new Date(1220227200);

retorna 1 de janeiro de 1970. Alguém conhece outra maneira de convertê-lo corretamente?

mmmiki
fonte
Você poderia dizer quais valores você espera? A questão de segundos / milissegundos pode ser válida, mas 1220227200 não é 01/01/1970. Parece que você está passando 0 para o construtor. Um pouco mais de código pode ajudar.
SJuan76 de
1
@mmmiki - você deve aceitar uma resposta
Stewart
ele retorna em 15 de janeiro de 1970, aqui, não em 1º de janeiro.
njzk2
Para sua informação, as classes data-hora terrivelmente defeituosas como java.util.Date, java.util.Calendare java.text.SimpleDateFormatagora são legadas , suplantadas pelas classes java.time construídas no Java 8 e posterior.
Basil Bourque

Respostas:

161

O Dateconstrutor (clique no link!) Aceita o tempo longem milissegundos , não segundos. Você precisa multiplicar por 1000 e certificar-se de fornecê-lo como long.

Date d = new Date(1220227200L * 1000);

Isso mostra aqui

Dom 31 de agosto 20:00:00 GMT-04: 00 2008

BalusC
fonte
22
Ou, alternativamente, use Date d = new Date(TimeUnit.SECONDS.toMillis(1220227200L));para uma solução mais limpa e menos mágica .
Priidu Neemre
56

tl; dr

java.time.Instant                    // Represent a moment as seen in UTC. Internally, a count of nanoseconds since 1970-01-01T00:00Z.
.ofEpochSecond( 1_220_227_200L )     // Pass a count of whole seconds since the same epoch reference of 1970-01-01T00:00Z.

Conheça seus dados

As pessoas usam várias precisões para rastrear o tempo como um número desde uma época . Portanto, ao obter alguns números a serem interpretados como uma contagem desde uma época, você deve determinar:

  • Que época?
    Muitas datas de épocas foram usadas em vários sistemas. Normalmente usado é o horário POSIX / Unix , onde a época é o primeiro momento de 1970 no UTC. Mas você não deve assumir esta época.
  • Que precisão?
    Estamos falando de segundos, milissegundos , microssegundos ou nanossegundos desde a época?
  • Qual fuso horário?
    Normalmente, uma contagem desde que a época está no fuso horário UTC / GMT, ou seja, não tem deslocamento de fuso horário. Mas às vezes, ao envolver programadores inexperientes ou ignorantes de data e hora, pode haver um fuso horário implícito.

No seu caso, como outros notaram, você parece ter recebido segundos desde a época do Unix. Mas você está passando esses segundos para um construtor que espera milissegundos. Portanto, a solução é multiplicar por 1.000.

Lições aprendidas:

  • Determine, não assuma, o significado dos dados recebidos.
  • Leia o doc .

Gráfico mostrando várias granularidades de resolução em sistemas de data e hora, incluindo segundos inteiros, milissegundos, microssegundos e nanossegundos.

Seus dados

Seus dados parecem estar em segundos inteiros. Se assumirmos uma época do início de 1970, e se assumirmos o fuso horário UTC, então 1,220,227,200é o primeiro momento do primeiro dia de setembro de 2008.

Joda-Time

As classes java.util.Date e .Calendar agrupadas com Java são notoriamente problemáticas. Evite-os. Em vez disso, use a biblioteca Joda-Time ou o novo pacote java.time empacotado em Java 8 (e inspirado em Joda-Time).

Observe que, ao contrário de juDate, um DateTimeem Joda-Time realmente conhece seu próprio fuso horário atribuído . Portanto, no código Joda-Time 2.4 de exemplo visto abaixo, observe que primeiro analisamos os milissegundos usando a suposição padrão de UTC. Então, em segundo lugar, atribuímos um fuso horário de Paris para ajustar. Mesmo momento na linha do tempo do Universo, mas com um relógio de parede diferente . Para demonstração, ajustamos novamente, para UTC. Quase sempre é melhor especificar explicitamente o fuso horário desejado / esperado, em vez de confiar em um padrão implícito (frequentemente a causa de problemas no trabalho de data e hora).

Precisamos de milissegundos para construir um DateTime. Portanto, pegue a sua entrada de segundos e multiplique por mil. Observe que o resultado deve ser de 64 bits, longpois estouraríamos um de 32 bits int.

long input = 1_220_227_200L;  // Note the "L" appended to long integer literals.
long milliseconds = ( input * 1_000L ); // Use a "long", not the usual "int". Note the appended "L".

Alimente essa contagem de milissegundos para o construtor. Esse construtor particular assume que a contagem é da época Unix de 1970. Portanto, ajuste o fuso horário conforme desejado, após a construção.

Use nomes de fuso horário adequados , uma combinação de continente e cidade / região. Nunca use códigos de 3 ou 4 letras, ESTpois eles não são padronizados nem únicos.

DateTime dateTimeParis = new DateTime( milliseconds ).withZone( DateTimeZone.forID( "Europe/Paris" ) );

Para demonstração, ajuste o fuso horário novamente.

DateTime dateTimeUtc = dateTimeParis.withZone( DateTimeZone.UTC );
DateTime dateTimeMontréal = dateTimeParis.withZone( DateTimeZone.forID( "America/Montreal" ) );

Despeje para o console. Observe como a data é diferente em Montreal, pois o novo dia começou na Europa, mas ainda não na América.

System.out.println( "dateTimeParis: " + dateTimeParis );
System.out.println( "dateTimeUTC: " + dateTimeUtc );
System.out.println( "dateTimeMontréal: " + dateTimeMontréal );

Quando corre.

dateTimeParis: 2008-09-01T02:00:00.000+02:00
dateTimeUTC: 2008-09-01T00:00:00.000Z
dateTimeMontréal: 2008-08-31T20:00:00.000-04:00

java.time

Os criadores do Joda-Time nos pediram para migrar para seu substituto, o framework java.time , assim que for conveniente. Enquanto Joda-Time continua a ter suporte ativo, todo o desenvolvimento futuro será feito nas classes java.time e suas extensões no projeto ThreeTen-Extra.

A estrutura java-time é definida pelo JSR 310 e integrada no Java 8 e posterior. As classes java.time foram portadas para Java 6 e 7 no projeto ThreeTen-Backport e para Android no projeto ThreeTenABP .

Um Instanté um momento na linha do tempo em UTC com resolução de nanossegundos. Sua época é o primeiro momento de 1970 na UTC.

Instant instant = Instant.ofEpochSecond( 1_220_227_200L );

Aplique um offset-from-UTC ZoneOffset para obter um OffsetDateTime.

Melhor ainda, se conhecido, aplique um fuso horário ZoneIdpara obter um ZonedDateTime.

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

Tabela de todos os tipos de data e hora em Java, tanto modernos quanto legados

Basil Bourque
fonte
1
Saúde amigo. Ótima explicação. Eu estava recebendo um novo DateTime (<número longo>) de 1970 quando percebi que estava dando em segundos e requerido em milissegundos
Suyash Dixit
40

Parece que seus longos são segundos, e não milissegundos. O construtor de data leva tempo em milis, então

Date d = new Date(timeInSeconds * 1000);
Codemwnci
fonte
4
@ f1sh: Eu não votei negativamente, mas a resposta original foi diferente. Ele editou em um período de tolerância de 5 minutos.
BalusC de
obrigado pelo esclarecimento. Essa é a própria desvantagem que a SO tem ...: - /
f1sh de
10

Apenas defina o tempo em moinhos no objeto Calendário

Calendar c = Calendar.getInstance();
c.setTimeInMillis(1385355600000l);
System.out.println(c.get(Calendar.YEAR));
System.out.println(c.get(Calendar.MONTH));
System.out.println(c.get(Calendar.DAY_OF_MONTH));
// get Date
System.out.println(c.getTime());
Marlon
fonte
9

Provavelmente são carimbos de data / hora em segundos e não em milissegundos, necessários para o construtor java new Date (long). Basta multiplicá-los por 1000 e você deve ficar bem.

Magnus Winter
fonte
23
mais apropriadamente 30000 milissegundos muito lento
SJuan76 de
5

Os valores longos, provavelmente, correspondem aos carimbos de data / hora da época , e os valores são:

1220227200 = Seg, 01 de setembro de 2008 00:00:00 GMT

1220832000 = Seg, 08 de setembro de 2008 00:00:00 GMT

1221436800 = Seg, 15 de setembro de 2008 00:00:00 GMT

Pode-se converter esses valores longos para java.util.Date , levando em consideração o fato de java.util.Date usar milissegundos - como sugerido anteriormente, mas com alguma falha - como este:

// note: enforcing long literals (L), without it the values would just be wrong.
Date date = new Date(1220227200L * 1000L); 

Agora, para exibir a data corretamente, pode-se usar java.text.DateFormat conforme ilustrado a seguir:

DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL);
df.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("Wrong date time value: " + date);
System.out.println("Correct date time value: " + df.format(date));

Abaixo estão os resultados da exibição do valor longo convertido para java.util.Date sem usar e usar o DateFormat:

Date wrong (off by 2 hours): Mon Sep 01 02:00:00 CEST 2008
Correct date : Monday, 1 September 2008 00:00:00 o'clock UTC
Jack G.
fonte
4

Experimente isto:

Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(1220227200 * 1000);
System.out.println(cal.getTime());
Mohammad Namvar
fonte
3

Tente fazer isso ajustando o formato da data.

long longtime = 1212580300;
SimpleDateFormat dateFormat = new SimpleDateFormat("MMddyyHHmm");
Date date = (Date) dateFormat.parseObject(longtime + "");
System.out.println(date);

Nota: Verifique o ciclo de 24 horas ou 12 horas.

Abhimanyu
fonte
2

1220227200 corresponde a 15 de janeiro de 1980 (e, de fato, a nova Data (1220227200) .toString () retorna "Qui 15 de janeiro 03:57:07 CET 1970"). Se você passar um valor longo para uma data, ou seja, antes de 01/01/1970, ele retornará de fato uma data de 01/01/1970. Certifique-se de que seus valores não estejam nesta situação (inferior a 82800000).

Dragão shivan
fonte
0

Nova data (número) retorna uma data que é number milissegundos após 1 de janeiro de 1970. Provavelmente, o formato de data não está mostrando horas, minutos e segundos para você ver que é um pouco depois de 1 de janeiro de 1970.

Você precisa analisar a data de acordo com o roteamento de análise correto. Não sei o que é 1220227200, mas se for segundos depois de 1 de janeiro de 1970, multiplique para render milissegundos. Se não estiver, converta-o de alguma maneira em milissegundos após 1970 (se quiser continuar a usar java.util.Date).

Edwin Buck
fonte
0

Funciona para mim. Você provavelmente deseja multiplicá-lo por 1000, já que o que você obtém são os segundos de 1970 e você tem que passar os milissegundos de 1 de janeiro de 1970

Leifg
fonte