J'essaie de convertir une chaîne au format ISO 8601 en un java.util.Date
.
J'ai trouvé que le modèle yyyy-MM-dd'T'HH:mm:ssZ
était conforme à ISO8601 s'il était utilisé avec un paramètre régional (comparer l'échantillon).
Cependant, en utilisant le java.text.SimpleDateFormat
, je ne peux pas convertir la chaîne correctement formatée 2010-01-01T12:00:00+01:00
. Je dois d'abord le convertir en 2010-01-01T12:00:00+0100
, sans les deux-points.
Ainsi, la solution actuelle est
SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.GERMANY);
String date = "2010-01-01T12:00:00+01:00".replaceAll("\\+0([0-9]){1}\\:00", "+0$100");
System.out.println(ISO8601DATEFORMAT.parse(date));
ce qui n'est évidemment pas si gentil. Suis-je en train de manquer quelque chose ou y at-il une meilleure solution?
Réponse
Grâce au commentaire de JuanZe, j'ai trouvé la magie Joda-Time , elle est également décrite ici .
Donc, la solution est
DateTimeFormatter parser2 = ISODateTimeFormat.dateTimeNoMillis();
String jtdate = "2010-01-01T12:00:00+01:00";
System.out.println(parser2.parseDateTime(jtdate));
Ou plus simplement, utilisez l'analyseur par défaut via le constructeur:
DateTime dt = new DateTime( "2010-01-01T12:00:00+01:00" ) ;
Pour moi, c'est sympa.
Réponses:
Malheureusement, les formats de fuseau horaire disponibles pour SimpleDateFormat (Java 6 et versions antérieures) ne sont pas conformes à ISO 8601 . SimpleDateFormat comprend les chaînes de fuseau horaire comme "GMT + 01: 00" ou "+0100", ce dernier selon la RFC # 822 .
Même si Java 7 a ajouté la prise en charge des descripteurs de fuseau horaire selon ISO 8601, SimpleDateFormat n'est toujours pas en mesure d'analyser correctement une chaîne de date complète, car il ne prend pas en charge les parties facultatives.
Le reformatage de votre chaîne d'entrée à l'aide de l'expression rationnelle est certainement une possibilité, mais les règles de remplacement ne sont pas aussi simples que dans votre question:
La solution la plus simple consiste peut-être à utiliser le convertisseur de type de données dans JAXB, car JAXB doit être capable d'analyser la chaîne de date ISO8601 conformément à la spécification du schéma XML.
javax.xml.bind.DatatypeConverter.parseDateTime("2010-01-01T12:00:00Z")
vous donnera unCalendar
objet et vous pouvez simplement utiliser getTime () dessus, si vous avez besoin d'unDate
objet.Vous pourriez probablement aussi utiliser Joda-Time , mais je ne sais pas pourquoi vous devriez vous en préoccuper.
la source
La voie qui est bénie par la documentation Java 7 :
Vous pouvez trouver plus d'exemples dans la section Exemples sur javadoc SimpleDateFormat .
UPD 13/02/2020: Il existe une toute nouvelle façon de le faire dans Java 8
la source
java.time
cadre de Java 8, inspiré de Joda-Time , remplaçant les classes java.util.Date, .Calendar et SimpleDateFormat gênantes.string1
etstring2
ne savez pas ce que vous obtiendrez.D'accord, cette question est déjà répondue, mais je laisserai quand même tomber ma réponse. Cela pourrait aider quelqu'un.
Je cherchais une solution pour Android (API 7).
javax.xml
ne fonctionneront pas sur Android API 7.J'ai fini par implémenter cette classe simple. Il ne couvre que la forme la plus courante des chaînes ISO 8601, mais cela devrait suffire dans certains cas (lorsque vous êtes certain que l'entrée sera dans ce format).
Note sur les performances: j'instancie chaque fois SimpleDateFormat pour éviter un bogue dans Android 2.1. Si vous êtes aussi étonné que moi, voyez cette énigme . Pour les autres moteurs Java, vous pouvez mettre l'instance en cache dans un champ statique privé (en utilisant ThreadLocal, pour être sûr pour les threads).
la source
s = s.substring(0, 22) + s.substring(23);
- je ne vois pas l'intérêt de celajava.time
L' API java.time (intégrée à Java 8 et versions ultérieures) rend cela un peu plus facile.
Si vous savez que l'entrée est en UTC , comme le
Z
(pour Zulu) à la fin, laInstant
classe peut analyser.Si votre entrée peut être une autre valeur de décalage par rapport à UTC plutôt que UTC indiquée par le
Z
(Zulu) à la fin, utilisez laOffsetDateTime
classe pour analyser.Ensuite, extrayez un
Instant
et convertissez-lejava.util.Date
en appelantfrom
.la source
LocalDateTime
etZoneId
etatZone
. Ce simple paquebot fera:java.util.Date date = Date.from( ZonedDateTime.parse( "2014-12-12T10:39:40Z" ).toInstant() );
Date.from(Instant.parse("2014-12-12T10:39:40Z" ));
c'est suffisant.OffsetDateTime
suffirait pour analyser ISO8601 (qui ne contient pas d'informations sur le fuseau horaire mais uniquement un décalage).Instant
l'analyse. Bien qu'elle ne soit pas suffisante pour cette question particulière, il s'agit d'une distinction importante qui mérite d'être soulignée. J'ai donc ajouté un deuxième exemple de code. Oups, je viens de remarquer que ce n'est pas à l'origine ma réponse; J'espère qu'Adam l'approuve.La bibliothèque Jackson-databind a également la classe ISO8601DateFormat qui fait cela (implémentation réelle dans ISO8601Utils .
la source
2015-08-11T13:10:00
. Je comprendsString index out of range: 19
. En regardant le code, il semble qu'il nécessite la spécification des millisecondes et du fuseau horaire. Ceux-ci devraient être facultatifs.[yyyy-MM-dd|yyyyMMdd][T(hh:mm[:ss[.sss]]|hhmm[ss[.sss]])]?[Z|[+-]hh:mm]]
. En d'autres termes, les millisecondes sont facultatives mais le fuseau horaire est obligatoire.new DateTime("2015-08-11T13:10:00").toDate()
tl; dr
Utilisation de java.time
Le nouveau package java.time dans Java 8 et versions ultérieures a été inspiré par Joda-Time.
La
OffsetDateTime
classe représente un moment sur la timeline avec un décalage par rapport à UTC mais pas un fuseau horaire.L'appel
toString
génère une chaîne au format standard ISO 8601:Pour voir la même valeur à travers l'objectif de l'UTC, extrayez un
Instant
ou ajustez le décalage de+01:00
à00:00
.…ou…
Ajustez dans un fuseau horaire si vous le souhaitez. Un fuseau horaire est un historique des valeurs de décalage par rapport à UTC pour une région, avec un ensemble de règles pour gérer les anomalies telles que l'heure d'été (DST). Appliquez donc un fuseau horaire plutôt qu'un simple décalage dans la mesure du possible.
À propos de java.time
Le framework java.time est intégré à Java 8 et versions ultérieures. Ces classes supplantent les anciens gênants hérités des classes date-heure tels que
java.util.Date
,Calendar
, etSimpleDateFormat
.Le projet Joda-Time , désormais en mode maintenance , conseille la migration vers les classes java.time .
Pour en savoir plus, consultez le didacticiel Oracle . Et recherchez Stack Overflow pour de nombreux exemples et explications. La spécification est JSR 310 .
Vous pouvez échanger des objets java.time directement avec votre base de données. Utilisez un pilote JDBC compatible avec JDBC 4.2 ou version ultérieure. Pas besoin de chaînes, pas besoin de
java.sql.*
cours.Où obtenir les classes java.time?
Le projet ThreeTen-Extra étend java.time avec des classes supplémentaires. Ce projet est un terrain d'essai pour de futurs ajouts possibles à java.time. Vous trouverez peut - être des classes utiles ici, comme
Interval
,YearWeek
,YearQuarter
et plus .la source
Pour Java version 7
Vous pouvez suivre la documentation Oracle: http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
X - est utilisé pour le fuseau horaire ISO 8601
la source
La solution DatatypeConverter ne fonctionne pas sur toutes les machines virtuelles. Ce qui suit fonctionne pour moi:
J'ai trouvé que joda ne fonctionne pas hors de la boîte (en particulier pour l'exemple que j'ai donné ci-dessus avec le fuseau horaire à une date, qui devrait être valide)
la source
Je pense que nous devrions utiliser
pour Date
2010-01-01T12:00:00Z
la source
À partir de Java 8, il existe une toute nouvelle façon officiellement prise en charge pour ce faire:
la source
Z
comme décalage, nous n'avons pas besoin de le spécifier explicitement. JustementInstant i = Instant.parse(s);
. La chaîne dans la question avait+01:00
, auquel casDateTimeFormatter.ISO_INSTANT
ne fonctionne pas (du moins pas sur mon Java 11).ISO_OFFSET_DATE_TIME
pour formater les dates avec des décalages, comme+01:00
( docs.oracle.com/javase/8/docs/api/java/time/format/… )Une autre façon très simple d'analyser les horodatages ISO8601 consiste à utiliser
org.apache.commons.lang.time.DateUtils
:la source
java.time
Notez que dans Java 8, vous pouvez utiliser la classe java.time.ZonedDateTime et sa
parse(CharSequence text)
méthode statique .la source
Instant
etZonedDateTime
sont appropriés ici, nonZonedDateTime
.La solution de contournement pour Java 7+ utilise SimpleDateFormat:
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.US);
Ce code peut analyser le format ISO8601 comme:
2017-05-17T06:01:43.785Z
2017-05-13T02:58:21.391+01:00
Mais sur Java6,
SimpleDateFormat
ne comprend pas leX
caractère et jetteraIllegalArgumentException: Unknown pattern character 'X'
Nous devons normaliser la date ISO8601 au format lisible en Java 6 avec
SimpleDateFormat
.Méthode ci-dessus pour remplacer [
Z
avec+0000
] ou [+01:00
avec+0100
] lorsqu'une erreur se produit dans Java 6 (vous pouvez détecter la version Java et remplacer l'instruction try / catch avec if).la source
Date
etSimpleDateFormat
sont mal conçues, déroutantes et imparfaites. Ils sont désormais hérités, supplantés par les classes java.time intégrées à Java 8 et versions ultérieures. Pour Java 6 et Java 7, une grande partie de la fonctionnalité java.time est rétroportée dans le projet ThreeTen-Backport . Il vaut bien mieux ajouter cette bibliothèque à votre application que d'utiliser ces classes héritées. Solution monoligne en java.time:OffsetDateTime.parse( "2010-01-01T12:00:00+01:00" )
J'ai rencontré le même problème et l' ai résolu par le code suivant.
Plus tôt, j'utilisais
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault());
Mais plus tard, j'ai trouvé que la principale cause de l'exception était le
yyyy-MM-dd'T'HH:mm:ss.SSSZ
,J'ai donc utilisé
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());
Cela a bien fonctionné pour moi.
la source
Vous pouvez également utiliser la classe suivante -
Lien vers Java Doc - Hiérarchie pour le package org.springframework.extensions.surf.maven.plugin.util
la source
Java a une douzaine de façons différentes d'analyser une date-heure, comme le démontrent les excellentes réponses ici. Mais étonnamment, aucune des classes horaires de Java n'implémente complètement ISO 8601!
Avec Java 8, je recommanderais:
Cela gérera des exemples à la fois en UTC et avec un décalage, comme "2017-09-13T10: 36: 40Z" ou "2017-09-13T10: 36: 40 + 01: 00". Il fera l'affaire pour la plupart des cas d'utilisation.
Mais il ne prendra pas en charge des exemples tels que "2017-09-13T10: 36: 40 + 01", qui est une date-heure ISO 8601 valide.
Il ne traitera pas uniquement la date, par exemple "13/09/2017".
Si vous devez les gérer, je suggère d'utiliser d'abord une expression régulière pour flairer la syntaxe.
Il y a une belle liste d'exemples ISO 8601 ici avec beaucoup de cas d'angle: https://www.myintervals.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/ I'm pas au courant de toute classe Java qui pourrait faire face à tous.
la source
OffsetDateTime
fera et correspond conceptuellement à une date-heure avec un décalage mieux.OffsetDateTime
gère les exemples que vous manipulez avecZonedDateTime
. Je crois qu'il ne gère aucun des exemples quiZonedDateTime
ne le font pas. En ce sens, ce n'est pas une amélioration (mais pas pire non plus). Désolé, je n'étais pas parfaitement clair.Apache Jackrabbit utilise le format ISO 8601 pour les dates persistantes, et il existe une classe d'assistance pour les analyser:
org.apache.jackrabbit.util.ISO8601
Livré avec jackrabbit-jcr-commons .
la source
Comme d'autres l'ont mentionné, Android n'a pas un bon moyen de prendre en charge l'analyse / le formatage des dates ISO 8601 à l'aide des classes incluses dans le SDK. J'ai écrit ce code plusieurs fois, j'ai donc finalement créé un Gist qui comprend une classe DateUtils qui prend en charge le formatage et l'analyse des dates ISO 8601 et RFC 1123. Le Gist comprend également un cas de test montrant ce qu'il prend en charge.
https://gist.github.com/mraccola/702330625fad8eebe7d3
la source
SimpleDateFormat pour JAVA 1.7 a un modèle sympa pour le format ISO 8601.
Classe SimpleDateFormat
Voici ce que j'ai fait:
la source
Z
dans la chaîne de format n'est pas le fuseau horaire ISO 8601, vous devez utiliserX
(ouXX
ouXXX
) si vous voulez un fuseau horaire ISO 8601Fais-le comme ça:
Voici la sortie:
Mer.19 octobre 15:15:36 CST 2016
la source
Utilisez une chaîne comme
LocalDate.parse(((String) data.get("d_iso8601")),DateTimeFormatter.ISO_DATE)
la source
Je suis surpris que pas une seule bibliothèque java ne prenne en charge tous les formats de date ISO 8601 selon https://en.wikipedia.org/wiki/ISO_8601 . Joda DateTime supportait la plupart d'entre eux, mais pas tous et j'ai donc ajouté une logique personnalisée pour les gérer tous. Voici ma mise en œuvre.
la source
Un petit test qui montre comment analyser une date dans ISO8601 et que LocalDateTime ne gère pas les DST.
la source
java.util.Date
,java.util.Calendar
etjava.text.SimpleDateFormat
sont désormais héritées , supplantées par les classes java.time intégrées à Java 8 et versions ultérieures. Voir Tutoriel par Oracle .LocalDateTime
ne gère pas l'heure d'été (DST) car elle ne gère pas du tout un fuseau horaire. Pour cela, nous avons besoinZonedDateTime
. ProposerDate
etSimpleDateFormat
est - à mon humble avis mauvais.J'avais un besoin similaire: j'avais besoin de pouvoir analyser n'importe quelle date conforme à ISO8601 sans connaître le format exact à l'avance, et je voulais une solution légère qui fonctionnerait également sur Android.
Lorsque j'ai recherché mes besoins sur Google, je suis tombé sur cette question et j'ai remarqué qu'AFAIU, aucune réponse ne correspondait parfaitement à mes besoins. J'ai donc développé jISO8601 et l' ai poussé sur maven central.
Ajoutez simplement en vous
pom.xml
:et puis vous êtes prêt à partir:
J'espère que cela vous aidera.
la source
Pour simplement formater une date comme celle-ci, les éléments suivants ont fonctionné pour moi dans une application basée sur Java 6. Il y a une
DateFormat
classeJacksonThymeleafISO8601DateFormat
dans le projet thymeleaf qui insère les deux points manquants:https://github.com/thymeleaf/thymeleaf/blob/40d27f44df7b52eda47d1bc6f1b3012add6098b3/src/main/java/org/thymeleaf/standard/serializer/StandardJavaScriptSerializer.java
Je l'ai utilisé pour la compatibilité du format de date ECMAScript.
la source
Fonction de base Courtoisie: @wrygiel.
Cette fonction peut convertir le format ISO8601 en date Java qui peut gérer les valeurs de décalage. Selon la définition de l'ISO 8601, le décalage peut être mentionné dans différents formats.
Cette classe a des méthodes statiques pour convertir
Exemples de chaînes ISO8601
}
la source
Cela a semblé fonctionner le mieux pour moi:
J'avais besoin de convertir des chaînes de date JavaScript en / en Java. J'ai trouvé les travaux ci-dessus avec la recommandation. Il y avait quelques exemples d'utilisation de SimpleDateFormat qui étaient proches mais ils ne semblaient pas être le sous-ensemble recommandé par:
http://www.w3.org/TR/NOTE-datetime
et pris en charge par PLIST et JavaScript Strings et ce qui est ce dont j'avais besoin.
Cela semble être la forme la plus courante de chaîne ISO8601 et un bon sous-ensemble.
Les exemples qu'ils donnent sont:
J'ai aussi une version rapide:
...
Je ne l'ai pas évalué, mais je suppose que ce sera assez rapide. Cela semble fonctionner. :)
la source
Je pense que ce que beaucoup de gens veulent faire, c'est analyser les chaînes de date JSON. Si vous arrivez sur cette page, il y a de fortes chances que vous souhaitiez convertir une date JSON JavaScript en date Java.
Pour montrer à quoi ressemble une chaîne de date JSON:
La chaîne de date JSON est 2013-12-14T01: 55: 33.412Z.
Les dates ne sont pas couvertes par les spécifications JSON, mais ce qui précède est un format ISO 8601 très spécifique, tandis que ISO_8601 est beaucoup plus grand et c'est un simple sous-ensemble, bien que très important.
Voir http://www.json.org Voir http://en.wikipedia.org/wiki/ISO_8601 Voir http://www.w3.org/TR/NOTE-datetime
En l'occurrence, j'ai écrit un analyseur JSON et un analyseur PLIST qui utilisent tous les deux ISO-8601 mais pas les mêmes bits.
J'ai écrit deux façons de le faire pour mon projet. Un standard, un rapide.
Encore une fois, la chaîne de date JSON est une implémentation très spécifique de l'ISO 8601 ....
(J'ai posté l'autre dans l'autre réponse qui devrait fonctionner pour les dates PLIST, qui sont un format ISO 8601 différent).
La date JSON est la suivante:
Les fichiers PLIST (ASCII non GNUNext) utilisent également ISO 8601 mais pas de millisecondes donc ... toutes les dates ISO-8601 ne sont pas identiques. (Au moins, je n'en ai pas encore trouvé un qui utilise des milis et l'analyseur que j'ai vu ignorer complètement le fuseau horaire OMG).
Maintenant, pour la version rapide (vous pouvez le trouver à Boon).
Notez que Reflection.toCharArray utilise dangereux s'il est disponible mais par défaut à string.toCharArray sinon.
(Vous pouvez le retirer de l'exemple en remplaçant Reflection.toCharArray (string) par string.toCharArray ()).
IsJsonDate est implémenté comme suit:
Quoi qu'il en soit ... je suppose que bon nombre de personnes qui viennent ici .. pourraient rechercher la chaîne de date JSON et bien qu'il s'agisse d'une date ISO-8601, elle est très spécifique et nécessite une analyse très spécifique.
Voir https://github.com/RichardHightower/boon Boon a un analyseur PLIST (ASCII) et un analyseur JSON.
L'analyseur JSON est l'analyseur JSON Java le plus rapide que je connaisse.
Vérifié indépendamment par les gars de Gatling Performance.
https://github.com/gatling/json-parsers-benchmark
Il possède l'analyseur JSON le plus rapide pour les flux, lecteurs, octets [], char [], CharSequence (StringBuilder, CharacterBuffer) et String.
Voir plus de repères sur:
https://github.com/RichardHightower/json-parsers-benchmark
la source
Instant.parse( "2013-12-14T01:55:33.412Z" )