La conversión de Long to Date en Java devuelve 1970

118

Tengo una lista con valores largos (por ejemplo: 1220227200, 1220832000, 1221436800 ...) que descargué del servicio web. Debo convertirlo a Fechas. Desafortunadamente de esta manera, por ejemplo:

Date d = new Date(1220227200);

devuelve el 1 de enero de 1970. ¿Alguien conoce otra forma de convertirlo correctamente?

mmmiki
fuente
¿Podrías decir qué valores esperas? La cuestión de segundos / milisegundos puede ser válida, pero 1220227200 no es 1/1/1970. Parece que está pasando 0 al constructor. Un poco más de código podría ayudar.
SJuan76
1
@mmmiki - debería aceptar una respuesta
Stewart
devuelve el 15 de enero de 1970, aquí, no el 1 de enero.
njzk2
Para su información, las clases de fecha y hora terriblemente defectuosas como java.util.Date, java.util.Calendary java.text.SimpleDateFormatahora son heredadas , suplantadas por las clases java.time integradas en Java 8 y posteriores.
Basil Bourque

Respuestas:

161

El Dateconstructor (¡haga clic en el enlace!) Acepta el tiempo longen milisegundos , no en segundos. Necesita multiplicarlo por 1000 y asegurarse de proporcionarlo como long.

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

Esto se muestra aquí

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

BalusC
fuente
22
O alternativamente, use Date d = new Date(TimeUnit.SECONDS.toMillis(1220227200L));para una solución más limpia y 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.

Conozca sus datos

La gente usa varias precisiones para rastrear el tiempo como un número desde una época . Entonces, cuando obtenga algunos números para ser interpretados como un conteo desde una época, debe determinar:

  • ¿Qué época?
    Se han utilizado fechas de muchas épocas en varios sistemas. Normalmente se utiliza la hora POSIX / Unix , donde la época es el primer momento de 1970 en UTC. Pero no debes asumir esta época.
  • ¿Qué precisión?
    ¿Estamos hablando de segundos, milisegundos , microsegundos o nanosegundos desde la época?
  • ¿Qué zona horaria?
    Por lo general, un recuento desde que la época está en la zona horaria UTC / GMT, es decir, no tiene ningún desplazamiento de zona horaria. Pero a veces, cuando se involucran programadores sin experiencia o que ignoran la fecha y la hora, puede haber una zona horaria implícita.

En su caso, como señalaron otros, parece que le han dado segundos desde la época de Unix. Pero le estás pasando esos segundos a un constructor que espera milisegundos. Entonces la solución es multiplicar por 1,000.

Lecciones aprendidas:

  • Determine, no asuma, el significado de los datos recibidos.
  • Leer el doc .

Gráfico que muestra varias granularidades de resolución en sistemas de fecha y hora, incluidos segundos completos, milisegundos, microsegundos y nanosegundos.

Tu información

Tus datos parecen estar en segundos enteros. Si asumimos una época de principios de 1970, y si asumimos la zona horaria UTC, entonces 1,220,227,200es el primer momento del primer día de septiembre de 2008.

Joda-Time

Las clases java.util.Date y .Calendar incluidas con Java son notoriamente problemáticas. Evítales. En su lugar, utilice la biblioteca Joda-Time o el nuevo paquete java.time incluido en Java 8 (e inspirado en Joda-Time).

Tenga en cuenta que, a diferencia de juDate, DateTimeen Joda-Time realmente conoce su propia zona horaria asignada . Entonces, en el ejemplo de código Joda-Time 2.4 que se ve a continuación, tenga en cuenta que primero analizamos los milisegundos utilizando la suposición predeterminada de UTC. Luego, en segundo lugar, asignamos una zona horaria de París para ajustar. Mismo momento en la línea de tiempo del Universo, pero diferente hora del reloj de pared . Para la demostración, ajustamos nuevamente a UTC. Casi siempre es mejor especificar explícitamente su zona horaria deseada / esperada en lugar de confiar en un valor predeterminado implícito (a menudo la causa de problemas en el trabajo de fecha y hora).

Necesitamos milisegundos para construir un DateTime. Así que tome su entrada de segundos y multiplíquela por mil. Tenga en cuenta que el resultado debe ser de 64 bits, longya que desbordaríamos uno 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 ese recuento de milisegundos al constructor. Ese constructor en particular asume que el recuento es de la época Unix de 1970. Por lo tanto, ajuste la zona horaria como desee, después de la construcción.

Utilice nombres de zona horaria adecuados , una combinación de continente y ciudad / región. Nunca use códigos de 3 o 4 letras, ya ESTque no están estandarizados ni son únicos.

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

Para la demostración, vuelva a ajustar la zona horaria.

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

Volcar a la consola. Observe cómo la fecha es diferente en Montreal, ya que el nuevo día ha comenzado en Europa pero aún no en América.

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

Cuando se ejecuta.

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

Los creadores de Joda-Time nos han pedido que migremos a su reemplazo, el marco java.time tan pronto como sea conveniente. Si bien Joda-Time continúa recibiendo soporte activo, todo el desarrollo futuro se realizará en las clases java.time y sus extensiones en el proyecto ThreeTen-Extra.

El marco de tiempo de Java está definido por JSR 310 y está integrado en Java 8 y versiones posteriores. Las clases java.time se han adaptado a Java 6 y 7 en el proyecto ThreeTen-Backport y a Android en el proyecto ThreeTenABP .

Un Instantes un momento en la línea de tiempo en UTC con una resolución de nanosegundos. Su época es el primer momento de 1970 en UTC.

Instant instant = Instant.ofEpochSecond( 1_220_227_200L );

Aplique un desplazamiento de UTC ZoneOffset para obtener un OffsetDateTime.

Mejor aún, si lo conoce, aplique una zona horaria ZoneIdpara obtener un ZonedDateTime.

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

Tabla de todos los tipos de fecha y hora en Java, tanto modernos como heredados

Albahaca Bourque
fuente
1
Salud Amigo. Gran explicación Estaba obteniendo un nuevo DateTime (<número largo>) de 1970 cuando me di cuenta de que lo estaba dando en segundos y requerido en milisegundos
Suyash Dixit
40

Parece que tus largos son segundos y no milisegundos. El constructor de fechas toma tiempo como milis, por lo que

Date d = new Date(timeInSeconds * 1000);
Codemwnci
fuente
4
@ f1sh: No voté en contra, pero la respuesta original fue diferente. Lo editó dentro de un período de gracia de 5 minutos.
BalusC
gracias por la aclaración. Esa es la desventaja propia que SO tiene ...: - /
f1sh
11

Solo configure el tiempo en molinos en el objeto Calendario

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
fuente
9

Esas son probablemente marcas de tiempo en segundos y no en milisegundos que se requieren para el constructor java new Date (long). Simplemente multiplíquelos por 1000 y estará bien.

Magnus Winter
fuente
23
más correctamente 30000 milisegundos demasiado lento
SJuan76
5

Lo más probable es que los valores largos correspondan a las marcas de tiempo de Epoch , y los valores son:

1220227200 = lun, 01 de septiembre de 2008 00:00:00 GMT

1220832000 = lunes, 08 de septiembre de 2008 00:00:00 GMT

1221436800 = Lun, 15 de septiembre de 2008 00:00:00 GMT

Uno puede convertir estos valores largos a java.util.Date , teniendo en cuenta el hecho de que java.util.Date usa milisegundos, como se sugirió anteriormente, pero con algunos defectos, como este:

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

Ahora, para mostrar la fecha correctamente, se puede usar java.text.DateFormat como se ilustra a continuación:

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

A continuación se muestran los resultados de mostrar el valor largo convertido a java.util.Date sin usar y usar 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.
fuente
4

Prueba esto:

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

1220227200 corresponde al 15 de enero de 1980 (y, de hecho, la nueva fecha (1220227200) .toString () devuelve "Thu Jan 15 03:57:07 CET 1970"). Si pasa un valor largo a una fecha, es decir, antes del 01/01/1970, de hecho devolverá una fecha del 01/01/1970. Asegúrese de que sus valores no se encuentren en esta situación (inferiores a 82800000).

Dragón Shivan
fuente
2

Intente esto ajustando el formato de fecha.

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

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

abhimanyu
fuente
0

New Date (número) devuelve una fecha en numbermilisegundos posterior al 1 de enero de 1970. Es probable que el formato de fecha no muestre horas, minutos y segundos para que pueda ver que es solo un poco posterior al 1 de enero de 1970.

Debe analizar la fecha de acuerdo con el enrutamiento de análisis correcto. No sé qué es un 1220227200, pero si son segundos después del 1 de enero de 1970, multiplíquelo para obtener milisegundos. Si no es así, conviértalo de alguna manera a milisegundos después de 1970 (si desea continuar usando java.util.Date).

Edwin Buck
fuente
0

Funciona para mi. Probablemente quieras multiplicarlo por 1000, ya que lo que obtienes son los segundos de 1970 y tienes que pasar los milisegundos del 1 de enero de 1970.

Leifg
fuente