Comment puis-je créer une date locale Java 8 à partir d'une longue période en millisecondes?

218

J'ai une API externe qui me renvoie des dates en longs, représentées en millisecondes depuis le début de l'époque.

Avec l'ancienne API Java de style, je construirais simplement un à Datepartir de celui-ci avec

Date myDate = new Date(startDateLong)

Quel est l'équivalent dans les classes LocalDate/ Java 8 LocalDateTime?

Je souhaite convertir le point dans le temps représenté par le longa LocalDatedans mon fuseau horaire local actuel.

Vihung
la source
6
Eh bien, vous devez commencer par déterminer le fuseau horaire qui vous intéresse. Une valeur "millisecondes depuis l'époque" vous donne un instant dans le temps ... qui pourrait faire référence à différentes dates dans différents fuseaux horaires. Gardez à l'esprit que cela java.util.Daten'a jamais vraiment été un rendez LocalDate-vous - c'était aussi un instant dans le temps.
Jon Skeet
2
Vérifiez cette question: stackoverflow.com/questions/21242110/… , qui couvre la conversion de java.util.DateenLocalDate
hotzst
3
Remarque: ce Q & A est également utile pour ceux qui essaient de convertir File.lastModified()(epoch millis) en LocalDate(Time).
kevinarpe

Réponses:

403

Si vous disposez des millisecondes depuis l'époque et que vous souhaitez les convertir en date locale à l'aide du fuseau horaire local actuel, vous pouvez utiliser

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

mais gardez à l'esprit que même le fuseau horaire par défaut du système peut changer, donc la même longvaleur peut produire des résultats différents lors des exécutions suivantes, même sur la même machine.

De plus, gardez à l'esprit que LocalDate, contrairement à java.util.Date, représente vraiment une date, pas une date et une heure.

Sinon, vous pouvez utiliser LocalDateTime:

LocalDateTime date =
    LocalDateTime.ofInstant(Instant.ofEpochMilli(longValue), ZoneId.systemDefault());
Holger
la source
2
+1 de ma part pour une explication plus détaillée. Soit dit en passant, même une zone non système peut changer (par tzupdater-tool ou par jdk-change) et donc produire des résultats différents avant et après.
Meno Hochschild
2
@Meno Hochschild: Je ne me concentrais pas sur les fuseaux horaires codés en dur, mais plutôt sur la comparaison avec les fuseaux horaires spécifiés par l'utilisateur, lus à partir d'un fichier de configuration ou de variables d'environnement, où le programmeur suppose naturellement que cela peut changer. Les fuseaux horaires codés en dur ressemblent en effet beaucoup au système par défaut; le programmeur est tenté de penser qu'ils ne changent jamais…
Holger
2
@Demigod LocalDateTime.ofEpochSecond(…)nécessite un réel ZoneOffset, mais ZoneId.systemDefault()renvoie un ZoneId. Un ZoneIdpeut correspondre à différents décalages, selon le moment auquel vous vous référez. C'est ce LocalDateTime.ofInstantque vous faites, en convertissant le spécifié en ZoneIdfonction du fourni Instant.
Holger
2
Epoch est défini comme UTC et doit donc être indépendant du fuseau horaire, donc le ZoneId doit toujours être UTC.
PlexQ
2
@PlexQ Le fuseau horaire spécifié n'est pas pertinent pour l'Epoch, qui est en effet indépendant du fuseau horaire, mais pour la sémantique du LocalDateou résultant LocalDateTime. Vous pouvez spécifier n'importe quel fuseau horaire de votre choix, à condition qu'il soit cohérent avec l'utilisation ultérieure de ces objets de résultat. Pensez à ce qui se passe lorsque vous traitez plusieurs objets créés par différentes méthodes. Les cas d'utilisation typiques pour la date ou les heures locales incluent le fuseau horaire par défaut du système, par exemple LocalDateTime.now()LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneId.systemDefault())
Holger
37

Vous pouvez commencer avec Instant.ofEpochMilli (long) :

LocalDate date =
  Instant.ofEpochMilli(startDateLong)
  .atZone(ZoneId.systemDefault())
  .toLocalDate();
Meno Hochschild
la source
5
+1 pour avoir été explicite sur le fuseau horaire. S'il est omis, le fuseau horaire par défaut actuel de la JVM est implicitement appliqué pour déterminer la date. Pour un moment donné, la date varie dans le monde par fuseau horaire alors qu'un nouveau jour se lève plus tôt dans l'est.
Basil Bourque du
12

Je pense que j'ai une meilleure réponse.

new Timestamp(longEpochTime).toLocalDateTime();
Abhijeet
la source
nouveau Timestamp (ts) .toLocalDateTime (). toLocalDate ()
Stepan Yakovenko
5
Je veux dire - si cela ne vous dérange pas d'importer javal.sql.Timestamp, qui, étant donné la nature monolithique de Java, je suppose que c'est bien parce que tout cela fait partie de la JVM ... mais se sent un peu malodorant, mais je l'aime toujours mieux car il a reconnu que l'époque est fondamentalement en UTC.
PlexQ
1
La Timestampclasse est mal conçue et dépassée depuis longtemps. Votre code utilisera le paramètre de fuseau horaire de la JVM, mais comme ce paramètre peut être modifié par une autre partie de votre programme ou un autre programme fonctionnant dans la même JVM, nous ne pouvons pas être tout à fait sûr de ce qu'il est.
Ole VV
1
Il est toujours préférable d'être explicite sur le fuseau horaire utilisé. L'utilisation de l'ancien java.sql.Timestamp présente l'inconvénient d'avoir le fuseau horaire du système appliqué implicitement, ce qui provoque généralement une confusion parmi les développeurs.
Ruslan
3

Et d'autres choses de côté les fuseaux horaires, une alternative très simple new Date(startDateLong)pourrait êtreLocalDate.ofEpochDay(startDateLong / 86400000L)

Michael Piefel
la source
6
Je pense que vous devriez au moins expliquer ce que signifie le 86400000L.
BAERUS
3
J'ai pensé qu'il était très facile de voir que c'était le nombre de millisecondes par jour.
Michael Piefel
7
Pour certains, c'est le cas, et j'ai pensé que cela aurait du sens, mais sans recalculer le nombre de ms par jour, je ne serais pas sûr. Pour parler de moi-même, je ne connais pas si bien ce numéro que je sais automatiquement ce qu'il représente.
BAERUS
Notez également que la réponse acceptée est vraiment la meilleure réponse, elle semble juste écrasante. Mon simple piratage suffit juste dans de nombreux cas. C'est dommage qui java.timen'inclut pas DateTimeConstantscomme Joda l'a fait.
Michael Piefel
2
java.util.concurrent.TimeUnit.MILLISECONDS.toDays(startDateLong)
Vadzim
1

remplacez now.getTime () par votre valeur longue.

//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
la source
-6

Dans un cas spécifique où votre horodatage epoch seconds provient de SQL ou est lié à SQL d'une manière ou d'une autre, vous pouvez l'obtenir comme ceci:

long startDateLong = <...>

LocalDate theDate = new java.sql.Date(startDateLong).toLocalDate();
M. Prokhorov
la source
2
Cela ne correspond pas vraiment à la question posée
Ketan R
@KetanR, je ne suis pas d'accord. La question est "comment obtenir un LocalDatede epoch-millis", et je montre comment, en utilisant java.sql.Datepour la sténographie. Cette approche est logique dans le code qui traite déjà avec JDBC dans une certaine mesure, et cela fonctionne très bien. Si vous n'êtes toujours pas convaincu, expliquez en quoi cela n'est pas lié à la question initiale.
M. Prokhorov
2
Si vous lisez la question, elle indique "API externe qui me renvoie des dates comme longues" et vous expliquez comment cette conversion peut être effectuée si vous recevez une date longue de SQL. Votre réponse explique un cas très spécifique de la conversion de date, mais ce n'est pas vraiment pertinent pour la question qui a été posée ed. Votre explication pourrait être une réponse valable à une autre question connexe.
Ketan R
@KetanR, si l'on reçoit une longue date de SQL, je conseillerais de changer son schéma pour qu'il ne reçoive plus de dates sous une telle forme. Cependant, si l'on reçoit des dates sous forme d'horodatages millisecondes ailleurs (l'API externe) et utilise immédiatement ces dates pour effectuer des requêtes JDBC, l' java.sql.Dateapproche est parmi les plus courtes disponibles, au niveau du code, et je dirais que ce n'est pas du tout utile aller bien Instantavec tous les objets temporels intermédiaires lorsque le résultat final est le même.
M. Prokhorov
2
Comme je l'ai déjà dit et cela ressort de votre dernière explication, votre réponse est correcte, mais pas pour la question en question La question dit: "Je souhaite convertir le point dans le temps représenté par le long en LocalDate dans mon fuseau horaire local actuel. "votre réponse dit:" recevez les dates sous forme d'horodatages millisimétriques et utilisez immédiatement ces dates pour effectuer des requêtes JDBC ". Je ne comprends pas ce qui n'est pas clair ici?
Ketan R