Nous essayons d'analyser la chaîne DateTime ISO 8601 suivante avec décalage de fuseau horaire:
final String input = "2022-03-17T23:00:00.000+0000";
OffsetDateTime.parse(input);
LocalDateTime.parse(input, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
Les deux approches échouent (ce qui est logique car OffsetDateTime
utilise également le DateTimeFormatter.ISO_OFFSET_DATE_TIME
) À cause des deux points dans le décalage du fuseau horaire.
Java.time.format.DateTimeParseException: le texte '2022-03-17T23: 00: 00.000 + 0000' n'a pas pu être analysé à l'index 23
Mais selon Wikipedia il existe 4 formats valides pour un décalage de fuseau horaire:
<time>Z
<time>±hh:mm
<time>±hhmm
<time>±hh
D'autres frameworks/langages peuvent analyser cette chaîne sans aucun problème, par exemple Javascript Date()
ou Jacksons ISO8601Utils
(ils discutent de ce problème ici )
Maintenant, nous pourrions écrire notre propre DateTimeFormatter
avec un RegEx complexe, mais à mon avis, la bibliothèque Java.time
Devrait être capable d'analyser cette chaîne ISO 8601 valide par défaut car elle est valide.
Pour l'instant, nous utilisons Jacksons ISO8601DateFormat
, Mais nous préférons utiliser la bibliothèque officielle date.time
Pour travailler avec. Quelle serait votre approche pour résoudre ce problème?
Si vous souhaitez analyser tous les formats valides de décalages (Z
, ±hh:mm
, ±hhmm
et ±hh
), une alternative consiste à utiliser un Java.time.format.DateTimeFormatterBuilder
avec des motifs optionnels (malheureusement, il semble qu'il n'y ait pas de lettre de motif unique pour tous les faire correspondre):
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
// date/time
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
// offset (hh:mm - "+00:00" when it's zero)
.optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
// offset (hhmm - "+0000" when it's zero)
.optionalStart().appendOffset("+HHMM", "+0000").optionalEnd()
// offset (hh - "Z" when it's zero)
.optionalStart().appendOffset("+HH", "Z").optionalEnd()
// create formatter
.toFormatter();
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000+0000", formatter));
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000+00", formatter));
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000+00:00", formatter));
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000Z", formatter));
Les quatre cas ci-dessus l'analyseront pour 2022-03-17T23:00Z
.
Vous pouvez également définir un modèle de chaîne unique si vous le souhaitez, à l'aide de []
pour délimiter les sections facultatives:
// formatter with all possible offset patterns
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS[xxx][xx][X]");
Ce formateur fonctionne également pour tous les cas, tout comme le formateur précédent ci-dessus. Vérifiez le javadoc pour obtenir plus de détails sur chaque modèle.
Remarques:
.SSS
). D'autre part, ISO_LOCAL_DATE_TIME
est plus flexible: les secondes et les nanosecondes sont facultatives, et il accepte également de 0 à 9 chiffres après la virgule décimale. Choisissez celui qui convient le mieux à vos données d'entrée.Vous n'avez pas besoin d'écrire une expression rationnelle complexe - vous pouvez créer un DateTimeFormatter
qui fonctionnera facilement avec ce format:
DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX", Locale.ROOT);
OffsetDateTime odt = OffsetDateTime.parse(input, formatter);
Cela acceptera également "Z" au lieu de "0000". Il acceptera pas "+00: 00" (avec les deux-points ou similaire. C'est surprenant compte tenu de la documentation, mais si votre valeur a toujours le décalage UTC sans les deux-points, cela devrait être correct.