web-dev-qa-db-fra.com

Impossible d'obtenir ZonedDateTime de TemporalAccessor à l'aide de DateTimeFormatter et ZonedDateTime dans Java 8

J'ai récemment migré vers Java 8 pour, espérons-le, gérer plus facilement les heures locales et zonées.

Cependant, je suis confronté à un problème simple, à mon avis, lors de l'analyse d'une date simple.

public static ZonedDateTime convertirAFecha(String fecha) throws Exception {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
            ConstantesFechas.FORMATO_DIA).withZone(
            obtenerZonaHorariaServidor());

    ZonedDateTime resultado = ZonedDateTime.parse(fecha, formatter);
    return resultado;
}

Dans mon cas:

  • la fecha est '15/06/2014 '
  • ConstantesFechas.FORMATO_DIA est 'jj/MM/aaaa'
  • obtenerZonaHorariaServidor renvoie ZoneId.systemDefault ()

Donc, ceci est un exemple simple. Cependant, l'analyse renvoie cette exception:

Java.time.format.DateTimeParseException: Text '15/06/2014' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor: {},ISO resolved to 2014-06-15 of type Java.time.format.Parsed

Des conseils? J'ai essayé différentes combinaisons d'analyse et d'utilisation de TemporalAccesor, mais sans succès jusqu'à présent.

Meilleures salutations

33
Faliorn

Je ne sais pas pourquoi cela ne fonctionne pas (probablement parce que votre entrée n'a pas d'informations sur l'heure/le fuseau horaire). Un moyen simple consiste à analyser votre date en tant que LocalDate d'abord (sans informations sur l'heure ou le fuseau horaire) puis de créer un ZonedDateTime:

public static ZonedDateTime convertirAFecha(String fecha) {
  DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
  LocalDate date = LocalDate.parse(fecha, formatter);

  ZonedDateTime resultado = date.atStartOfDay(ZoneId.systemDefault());
  return resultado;
}
33
assylias

Ceci est un bug, voir JDK-bug-log . Selon ces informations, le problème a été résolu pour Java 9 et Java 8u20. Essayez de télécharger la dernière Java 8 - Aujourd'hui le 12/05/2014: Il existe une version à accès anticipé 8u2 disponible.

MISE À JOUR:

Personnellement, je pense que, puisque vous n'avez et n'attendez que "jj/mm/aaaa" comme modèle, vous devez utiliser LocalDate comme type principal comme @assylias l'a déjà proposé. En ce qui concerne votre contexte, il est presque certain qu'un échec de la conception d'utiliser ZonedDateTime. Que voulez-vous faire avec des objets de ce type? Je ne peux considérer les calculs de fuseau horaire spécialisés que comme un cas d'utilisation. Et vous ne pouvez même pas stocker directement ces objets ZonedDateTime- dans une base de données, donc ce type est beaucoup moins utile que beaucoup de gens le croient.

Ce que j'ai décrit comme votre problème de cas d'utilisation est en effet un nouvel aspect introduit avec Java-8 par rapport à l'ancienne classe GregorianCalendar (qui est un type tout-en-un). Les utilisateurs doivent commencer à réfléchir au choix du type temporel approprié à leurs problèmes et à leurs cas d'utilisation.

15
Meno Hochschild

En termes simples, la ligne

ZonedDateTime.parse('2014-04-23', DateTimeFormatter.ISO_OFFSET_DATE_TIME)

lève une exception:

Text '2014-04-23' could not be parsed at index 10
Java.time.format.DateTimeParseException: Text '2014-04-23' could not be parsed at index 10

Cela ressemble à un bug pour moi.

J'ai utilisé cette solution de contournement:

String dateAsStr = '2014-04-23';
if (dateAsStr.length() == 10) {
    dateAsStr += 'T00:00:00';
}
ZonedDateTime.parse(dateAsStr, DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.systemDefault()));
5
stokito

Juste un exemple de conversions, je pense que certaines personnes obtiendront l'exception ci-dessous

(Java.time.DateTimeException: Unable to obtain LocalDateTime from TemporalAccessor: 2014-10-24T18:22:09.800Z of type Java.time.Instant)

s'ils essaient

LocalDateTime localDateTime = LocalDateTime.from(new Date().toInstant());

pour résoudre le problème, veuillez passer dans Zone -

LocalDateTime localDateTime = LocalDateTime.from(new Date()
        .toInstant().atZone(ZoneId.of("UTC")));
2
Dahar Youssef

Si vous venez de Google:

Au lieu de faire:

ZonedDateTime.from(new Date().toInstant());

Essaye ça:

ZonedDateTime.ofInstant(new Date(), ZoneId.of("UTC")); 
2
anon58192932