web-dev-qa-db-fra.com

Conversion d'une chaîne de temps au format ISO 8601

J'essaye de créer une chaîne dans un format comme 2015-08-20T08: 26: 21.000Z
au 2015-08-20T08: 26: 21Z

Je sais que cela peut être fait avec certaines techniques de fractionnement de chaîne, mais je me demande s’il existe une solution élégante pour cela (avec un minimum de modifications de code).

Les deux éléments ci-dessus sont des chaînes de temps, la dernière dont j'ai besoin est Date dans ISO 8601. http://tools.ietf.org/html/rfc3339#section-5.6

J'ai essayé quelques questions similaires, telles que convertir une chaîne de date en millisecondes en Java mais elles ne résolvent pas le but recherché. 

Aussi essayé d'utiliser: 

SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZ");
String nowAsString = df.format(new Date());

Mais il ne fait toujours pas de conversions de chaîne à chaîne. Obtenir l'erreur suivante:

23: 04: 13,829 WARN [RuntimeExceptionMapper] a capturé une exception RuntimeException: {}: Java.lang.IllegalArgumentException: Impossible de formater un objet donné en tant que date

Y a-t-il une bibliothèque que quelqu'un peut suggérer?

Merci. 

7
CodeMonkey

tl; dr

Instant.parse( "2015-08-20T08:26:21.000Z" )
       .toString()

2015-08-20T08: 26: 21Z

Formateur de date-heure

Si vous souhaitez uniquement éliminer le .000, utilisez des objets date-heure pour analyser la valeur de votre chaîne d'entrée, puis générez une nouvelle représentation sous forme de chaîne de cette valeur date-heure dans un format différent.

ISO 8601

Soit dit en passant, si tel est votre objectif, le titre de la question n’a aucun sens car les deux chaînes mentionnées dans la première phrase sont valides ISO 8601 chaînes formatées.

  • 2015-08-20T08:26:21.000Z
  • 2015-08-20T08:26:21Z

Java.time

Java 8 et versions ultérieures ont le nouveau package Java.time . Ces nouvelles classes supplantent les anciennes classes Java.util.Date/.Calendar & Java.text.SimpleDateFormat. Ces anciennes classes étaient déroutantes, gênantes et défectueuses.

Instant

Si tout ce que vous voulez, c'est le fuseau horaire UTC, vous pouvez utiliser la classe Instant . Cette classe représente un point de la timeline sans égard à un fuseau horaire particulier (essentiellement le temps UTC).

DateTimeFormatter.ISO_INSTANT

L’appel d’un toString d’Instant génère une représentation sous forme de chaîne de la valeur date-heure à l'aide d'une instance DateTimeFormatter.ISO_INSTANT formatter. Ce formateur est automatiquement flexible sur la fraction de seconde. Si la valeur a une seconde entière, aucune décimale n'est générée (apparemment ce que la Question souhaite). Pendant une fraction de seconde, les chiffres apparaissent par groupes de 3, 6 ou 9, selon les besoins, pour représenter la valeur avec une résolution allant jusqu'à la nanoseconde. Remarque: ce format peut dépasser la limite de millisecondes ISO 8601 (3 décimales).

Exemple de code

Voici un exemple de code dans Java 8 Update 51.

String output = Instant.parse( "2015-08-20T08:26:21.000Z" ).toString( );
System.out.println("output: " + output );

sortie: 2015-08-20T08: 26: 21Z

Passage à une fraction de seconde, .08

String output = Instant.parse( "2015-08-20T08:26:21.08Z" ).toString( );

sortie: 2015-08-20T08: 26: 21.080Z

Si vous êtes intéressé par un fuseau horaire autre que UTC, créez un objet ZonedDateTime à partir de cette Instant.

ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , ZoneId.of( "America/Montreal" ) ) ;
10
Basil Bourque

La conversion d'une date String de formatage inconnu en une date String qui utilise un formatage connu peut être effectuée à l'aide de deux objets DateFormat, l'un configuré de manière dynamique pour analyser le format de la variable String et l'autre pour générer la sortie formatée String. Dans votre cas, le formatage String d'entrée n'est pas spécifié et doit être fourni par l'appelant. Toutefois, le formatage String de sortie peut être configuré pour utiliser le formatage ISO 8601 sans entrée supplémentaire. Généralement, une sortie de date String formatée ISO 8601 nécessite deux entrées fournies par l'appelant: une String contenant la date formatée et une autre String contenant le format SimpleDateFormat

Voici la conversion décrite en tant que code Java (j’ai délibérément omis d’effectuer des contrôles et des validations nuls, ajoutez-les en fonction de votre code):

private String formatDateAsIso8601(final String inputDateAsString, final String inputStringFormat) throws ParseException {

     final DateFormat iso8601DateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'", Locale.ENGLISH);
     iso8601DateFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));

     final DateFormat inputDateFormatter = new SimpleDateFormat(inputStringFormat, Locale.ENGLISH);
     final Date inputDate = inputDateFormatter.parse(inputDateAsString);

     return iso8601DateFormatter.format(inputDate);
}

Si vous souhaitez modifier cette méthode, veuillez noter que SimpleDateFormat n'est pas thread-safe et que vous ne devriez pas l'utiliser à partir d'un contexte statique sans solution de contournement pour le code multithread (ThreadLocal est couramment utilisé pour effectuer une telle solution de contournement pour SimpleDateFormat) . 

Un "gotcha" supplémentaire est l'utilisation d'une Locale lors de la construction des objets SimpleDateFormat - ne supprimez pas la configuration Locale. Il n’est pas prudent d’autoriser le système à choisir d’utiliser la valeur par défaut Locale car elle est spécifique à l’utilisateur/à la machine. Si vous lui permettez d'utiliser la variable Locale par défaut, vous courez le risque de rencontrer des bogues transitoires car votre ordinateur de développement utilise une variable Locale différente de la variable Locale de votre utilisateur final. Vous n’êtes pas obligé d’utiliser ma sélection anglaise sous Locale, il est tout à fait correct d’utiliser une langue différente (vous devez comprendre les règles de cette Locale et modifier le code selon vos besoins). La spécification de Locale et l'utilisation de la valeur par défaut du système sont incorrectes et risquent de vous faire passer de nombreuses heures frustrantes à tenter de diagnostiquer un bogue évasif.

Veuillez comprendre que cette solution n’est pas idéale à partir de Java 8 et de l’inclusion des classes basées sur JodaTime, telles que Instant. J'ai choisi de répondre en utilisant des API obsolètes, car c'étaient là ce qui semblait vous préoccuper dans votre question. Si vous utilisez Java 8, je vous conseille vivement d’apprendre et d’utiliser les nouvelles classes car elles constituent une amélioration de presque tous les moyens imaginables.

2
Emily Mabrey

Votre format n'est pas correct essayez ceci: -

try {
        String s = "2015-08-20T08:26:21.000Z";
         SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
    Date d = df.parse(s);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
        System.out.println(sdf.format(d));
    } catch (ParseException e) {
        e.printStackTrace();
    }
2
karim mohsen