La conversion de Long en date dans Java renvoie 1970

118

J'ai une liste avec de longues valeurs (par exemple: 1220227200, 1220832000, 1221436800 ...) que j'ai téléchargées à partir du service Web. Je dois le convertir en dates. Malheureusement de cette façon, par exemple:

Date d = new Date(1220227200);

renvoie le 1er janvier 1970. Quelqu'un connaît-il une autre façon de le convertir correctement?

mmmiki
la source
Pouvez-vous dire à quelles valeurs vous attendez-vous? La question des secondes / millisecondes peut être valide, mais 1220227200 n'est pas le 1/1/1970. Il semble que vous transmettez 0 au constructeur. Un peu plus de code pourrait aider.
SJuan76 du
1
@mmmiki - vous devriez accepter une réponse
Stewart
il revient le 15 janvier 1970, ici, pas le 1er janvier.
njzk2
Pour info, les classes de date-heure terriblement défectueuses telles que java.util.Date, java.util.Calendaret java.text.SimpleDateFormatsont maintenant héritées , supplantées par les classes java.time intégrées à Java 8 et versions ultérieures.
Basil Bourque

Réponses:

161

Le Dateconstructeur (cliquez sur le lien!) Accepte le temps longen millisecondes et non en secondes. Vous devez le multiplier par 1000 et vous assurer de le fournir en tant que long.

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

Cela montre ici

Dim 31 août 20:00:00 GMT-04: 00 2008

BalusC
la source
22
Ou bien, utilisez Date d = new Date(TimeUnit.SECONDS.toMillis(1220227200L));pour une solution plus propre et moins magique .
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.

Connaissez vos données

Les gens utilisent diverses précisions dans le suivi du temps sous forme de nombre depuis une époque . Ainsi, lorsque vous obtenez des nombres à interpréter comme un décompte depuis une époque, vous devez déterminer:

  • Quelle époque?
    De nombreuses dates d'époque ont été utilisées dans divers systèmes. L' heure POSIX / Unix est couramment utilisée , où l'époque est le premier moment de 1970 en UTC. Mais vous ne devez pas assumer cette époque.
  • Quelle précision?
    Parlons-nous des secondes, des millisecondes , des microsecondes ou des nanosecondes depuis l'époque?
  • Quel fuseau horaire?
    Habituellement, un décompte depuis l'époque est dans le fuseau horaire UTC / GMT, c'est-à-dire qu'il n'a aucun décalage de fuseau horaire. Mais parfois, lorsqu'il s'agit de programmeurs inexpérimentés ou ignorants de la date-heure, il peut y avoir un fuseau horaire implicite.

Dans votre cas, comme d'autres l'ont noté, vous semblez avoir eu quelques secondes depuis l'époque Unix. Mais vous passez ces secondes à un constructeur qui attend des millisecondes. La solution est donc de multiplier par 1000.

Leçons apprises:

  • Déterminez, ne supposez pas, la signification des données reçues.
  • Lisez le doc .

Graphique montrant diverses granularités de résolution dans les systèmes date-heure, y compris les secondes entières, les millisecondes, les microsecondes et les nanosecondes.

Vos données

Vos données semblent être en secondes entières. Si nous supposons une époque du début de 1970, et si nous supposons le fuseau horaire UTC, alors 1,220,227,200c'est le premier moment du premier jour de septembre 2008.

Joda-Time

Les classes java.util.Date et .Calendar fournies avec Java sont notoirement gênantes. Évite-les. Utilisez à la place soit la bibliothèque Joda-Time , soit le nouveau package java.time intégré à Java 8 (et inspiré de Joda-Time).

Notez que contrairement à juDate, un DateTimedans Joda-Time connaît vraiment son propre fuseau horaire attribué . Donc, dans l'exemple de code Joda-Time 2.4 vu ci-dessous, notez que nous analysons d'abord les millisecondes en utilisant l'hypothèse par défaut de UTC. Ensuite, deuxièmement, nous attribuons un fuseau horaire de Paris à ajuster. Même moment dans la chronologie de l'Univers, mais heure d'horloge murale différente . Pour la démonstration, nous nous ajustons à nouveau, à UTC. Il est presque toujours préférable de spécifier explicitement votre fuseau horaire souhaité / attendu plutôt que de compter sur une valeur implicite par défaut (souvent la cause de problèmes dans le travail de date-heure).

Nous avons besoin de millisecondes pour construire un DateTime. Alors, prenez votre saisie de secondes et multipliez par mille. Notez que le résultat doit être un 64 bits longcar nous déborderions d'un 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".

Envoyez ce nombre de millisecondes au constructeur. Ce constructeur particulier suppose que le décompte date de l'époque Unix de 1970. Ajustez donc le fuseau horaire comme vous le souhaitez, après la construction.

Utilisez des noms de fuseaux horaires appropriés , une combinaison de continent et de ville / région. N'utilisez jamais de codes à 3 ou 4 lettres tels ESTqu'ils ne sont ni normalisés ni uniques.

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

Pour une démonstration, ajustez à nouveau le fuseau horaire.

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

Dump dans la console. Notez à quel point la date est différente à Montréal, car la nouvelle journée a commencé en Europe mais pas encore en Amérique.

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

Lorsqu'il est exécuté.

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

Les créateurs de Joda-Time nous ont demandé de migrer vers son remplaçant, le framework java.time dès que possible. Bien que Joda-Time continue d'être activement pris en charge, tous les développements futurs seront effectués sur les classes java.time et leurs extensions dans le projet ThreeTen-Extra.

Le framework java-time est défini par JSR 310 et intégré à Java 8 et versions ultérieures. Les classes java.time ont été rétroportées vers Java 6 & 7 sur le projet ThreeTen-Backport et vers Android dans le projet ThreeTenABP .

An Instantest un moment sur la chronologie en UTC avec une résolution de nanosecondes. Son époque est le premier moment de 1970 à UTC.

Instant instant = Instant.ofEpochSecond( 1_220_227_200L );

Appliquez un offset-from-UTC ZoneOffset pour obtenir un OffsetDateTime.

Mieux encore, s'il est connu, appliquez un fuseau horaire ZoneIdpour obtenir un fichier ZonedDateTime.

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

Tableau de tous les types de date-heure en Java, à la fois modernes et hérités

Basil Bourque
la source
1
Salut mon pote. Excellente explication. Je recevais un nouveau DateTime (<nombre long>) de 1970 quand j'ai réalisé que je le
donnais
40

Il semble que vos longs soient des secondes et non des millisecondes. Le constructeur de date prend le temps en millisecondes, donc

Date d = new Date(timeInSeconds * 1000);
Codemwnci
la source
4
@ f1sh: Je n'ai pas voté contre, mais la réponse originale était différente. Il l'a édité dans un délai de grâce de 5 minutes.
BalusC
Merci pour la clarification. C'est le propre inconvénient que SO a ...: - /
f1sh
11

Définir uniquement l'heure en moulins sur l'objet Calendrier

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
la source
9

Ce sont probablement des horodatages en secondes et non en millisecondes, ce qui est requis pour le constructeur java new Date (long). Multipliez-les simplement par 1000 et vous devriez être bien.

Magnus hiver
la source
23
plus correctement 30000 millisecondes trop lent
SJuan76
5

Les valeurs longues correspondent très probablement aux horodatages d' époque et les valeurs sont:

1220227200 = lun, 01 sept. 2008 00:00:00 GMT

1220832000 = lun, 08 sept. 2008 00:00:00 GMT

1221436800 = Lun, 15 septembre 2008 00:00:00 GMT

On peut convertir ces valeurs longues en java.util.Date , en tenant compte du fait que java.util.Date utilise des millisecondes - comme indiqué précédemment, mais avec quelques défauts - comme ceci:

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

Maintenant, pour afficher correctement la date, on peut utiliser java.text.DateFormat comme illustré ci-après:

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

Voici les résultats de l'affichage de la valeur longue convertie en java.util.Date sans utiliser ni utiliser le 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.
la source
4

Essaye ça:

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

1220227200 correspond au 15 janvier 1980 (et en effet la nouvelle Date (1220227200) .toString () renvoie "Thu Jan 15 03:57:07 CET 1970"). Si vous passez une valeur longue à une date, c'est-à-dire avant le 01/01/1970, elle renverra en fait une date du 01/01/1970. Assurez-vous que vos valeurs ne sont pas dans cette situation (inférieures à 82800000).

Dragon Shivan
la source
2

Essayez ceci en ajustant le format de la date.

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

Remarque: Vérifiez pendant un cycle de 24 heures ou 12 heures.

abhimanyu
la source
0

Nouvelle date (nombre) renvoie une date en numbermillisecondes après le 1er janvier 1970. Il est probable que le format de la date n'indique pas les heures, les minutes et les secondes pour que vous puissiez voir que c'est juste un peu après le 1er janvier 1970.

Vous devez analyser la date en fonction du routage d'analyse correct. Je ne sais pas ce qu'est un 1220227200, mais s'il s'agit de secondes après le 1 janvier 1970, multipliez-le pour obtenir des millisecondes. Si ce n'est pas le cas, convertissez-le d'une manière ou d'une autre en millisecondes après 1970 (si vous souhaitez continuer à utiliser java.util.Date).

Edwin Buck
la source
0

Travaille pour moi. Vous voudrez probablement le multiplier par 1000, car ce que vous obtenez sont les secondes de 1970 et vous devez passer les millisecondes à partir du 1er janvier 1970

leifg
la source