web-dev-qa-db-fra.com

Erreur Java.time.format.DateTimeParseException: impossible à analyser, texte non analysé trouvé à l'index 10

J'essaie de coller la prochaine chaîne à l'aide de LocalDateTime, mais j'obtiens toujours une erreur de texte non analysé:

Error Java.time.format.DateTimeParseException: Text '2016-08-18 14:27:15.103+02' could not be parsed, unparsed text found at index 10

Voici ma chaîne: convertDate: '2016-08-18 14: 27: 15.103 + 02'

Et mon code:

public static LocalDate conversorStringToLocalDateTime(String convertDate) throws ParseException {
    LocalDate dateTime =LocalDate.parse(convertDate);
    return dateTime;
}

Je suppose que ce n'est pas trop compliqué, acheter je ne peux pas voir l'erreur. Le + 02 dans la chaîne pourrait-il être la cause?

9
Asier Pomposo

tl; dr

OffsetDateTime odt = OffsetDateTime.parse ( "2016-08-18 14:27:15.103+02" , DateTimeFormatter.ofPattern ( "yyyy-MM-dd HH:mm:ss.SSSX" ) ) ;

Détails

Réponse de greg-449 est correct sur le problème (en utilisant un objet date uniquement pour une valeur date-heure) mais pas la solution.

Cette réponse utilise LocalDateTime qui jette inutilement des informations précieuses sur le offset-from-UTC . Un LocalDateTime ne pas représente un moment spécifique sur la chronologie, seulement une vague idée des moments possibles en fonction de l'ajustement dans un fuseau horaire particulier .

Le +02 est un offset-from-UTC signifiant "deux heures d'avance sur UTC ". Ainsi, en UTC, l'heure de la journée pour ce moment simultané est de 12 heures, 2 heures de moins que vos 14 heures. Cela représente un moment spécifique sur la chronologie. Ce décalage est l'information précieuse que vous jetez avec un LocalDateTime plutôt qu'un OffsetDateTime.

Le format de votre chaîne est au format SQL, qui est proche du format standard ISO 8601. Remplacez simplement l'espace au milieu par un T. Les classes Java.time utilisent les formats ISO 8601 par défaut, donc pas besoin de spécifier un modèle de formatage.

String input = "2016-08-18 14:27:15.103+02";
String inputModified = input.replace ( " " , "T" );

Malheureusement, Java 8 a un bug dans l'analyse des valeurs de décalage abrégées en une heure seulement ou des valeurs de décalage omettant les deux points entre les heures et les minutes. Corrigé dans Java 9. Mais dans Java 8, nous devons ajuster l'entrée.

// Workaround for Java 8 where 2-digit offset fails parsing. Fixed in Java 9.
int lengthOfAbbreviatedOffset = 3;
if ( inputModified.indexOf ( "+" ) == ( inputModified.length () - lengthOfAbbreviatedOffset ) ) {
    // If third character from end is a PLUS SIGN, append ':00'.
    inputModified = inputModified + ":00";
}
if ( inputModified.indexOf ( "-" ) == ( inputModified.length () - lengthOfAbbreviatedOffset ) ) {
    // If third character from end is a PLUS SIGN, append ':00'.
    inputModified = inputModified + ":00";
}

Maintenant, analysez.

OffsetDateTime odt = OffsetDateTime.parse ( inputModified );

Dump sur console. Notez comment nous avons transformé +02 en +02:00.

System.out.println ( "input: " + input + " | inputModified: " + inputModified + " | odt: " + odt );

entrée: 2016-08-18 14: 27: 15.103 + 02 | inputModified: 2016-08-18T14: 27: 15.103 + 02: 00 | odt: 2016-08-18T14: 27: 15.103 + 02: 00

Vous pouvez également spécifier un modèle de mise en forme. Le bogue d'analyse par décalage ne mord pas lors de l'utilisation de ce modèle de mise en forme.

    DateTimeFormatter f = DateTimeFormatter.ofPattern ( "yyyy-MM-dd HH:mm:ss.SSSX" );
    OffsetDateTime odt = OffsetDateTime.parse ( input , f );

Base de données

Venant de Postgres , vous devriez récupérer la valeur en tant qu'objet date-heure plutôt qu'en tant que chaîne.

Si votre pilote JDBC est conforme à JDBC 4.2, vous pouvez appeler ResultSet::getObject pour obtenir un Instant ou OffsetDateTime. Sinon, appelez ResultSet::getTimestamp pour obtenir un Java.sql.Timestamp, puis convertissez immédiatement en Java.time en appelant toInstant sur l'objet Timestamp.

Restez avec Java.time pour votre logique métier; utilisez les types Java.sql brièvement et uniquement pour l'échange avec la base de données.

7
Basil Bourque

Votre code utilise LocalDate qui analyse uniquement une date - pas une date et une heure, vous obtenez donc une erreur lorsque l'analyse trouve l'espace après la date.

Vous devez donc utiliser LocalDateTime mais LocalDateTime.parse(String) attend une date au format ISO qui n'est pas le format que vous utilisez.

Vous devez donc utiliser un DateTimeFormatter pour spécifier le format de votre chaîne d'entrée. Quelque chose comme:

DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSX");
LocalDateTime result = LocalDateTime.parse(convertDate, format);
5
greg-449