web-dev-qa-db-fra.com

date d'analyse simpledateformat avec le littéral 'Z'

J'essaie d'analyser une date qui ressemble à ceci:

2010-04-05T17:16:00Z

C'est une date valide par http://www.ietf.org/rfc/rfc3339.txt . Le littéral "Z" "implique que UTC Est le point de référence préféré pour l'heure spécifiée".

Si j'essaye de l'analyser en utilisant SimpleDateFormat et ce modèle:

yyyy-MM-dd'T'HH:mm:ss

Il sera analysé comme un lun. 05 avr. 17:16:00 EDT 2010

SimpleDateFormat est incapable d'analyser la chaîne avec ces modèles:

yyyy-MM-dd'T'HH:mm:ssz
yyyy-MM-dd'T'HH:mm:ssZ

Je peux explicitement configurer TimeZone à utiliser sur SimpleDateFormat pour obtenir le résultat attendu, mais je ne pense pas que cela devrait être nécessaire. Y a-t-il quelque chose qui me manque? Existe-t-il un autre analyseur de date?

69
DanInDC

Dans le modèle, l'inclusion d'un composant date-heure 'z' indique que le format du fuseau horaire doit être conforme au fuseau horaire Général "standard", les exemples étant Pacific Standard Time; PST; GMT-08:00

Un «Z» indique que le fuseau horaire est conforme à la norme de fuseau horaire RFC 822 , par ex. -0800.

Je pense que vous avez besoin d'un DatatypeConverter ...

@Test
public void testTimezoneIsGreenwichMeanTime() throws ParseException {
    final Calendar calendar = javax.xml.bind.DatatypeConverter.parseDateTime("2010-04-05T17:16:00Z");
    TestCase.assertEquals("gotten timezone", "GMT+00:00", calendar.getTimeZone().getID());
}
30
Paul McKenzie

Java n'analyse pas correctement les dates ISO.

Semblable à la réponse de McKenzie.

Il suffit de corriger la Z avant d'analyser.

Code

String string = "2013-03-05T18:05:05.000Z";
String defaultTimezone = TimeZone.getDefault().getID();
Date date = (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).parse(string.replaceAll("Z$", "+0000"));

System.out.println("string: " + string);
System.out.println("defaultTimezone: " + defaultTimezone);
System.out.println("date: " + (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).format(date));

Résultat

string: 2013-03-05T18:05:05.000Z
defaultTimezone: America/New_York
date: 2013-03-05T13:05:05.000-0500
48
Alex

La date que vous analysez est au format ISO8601.

Dans Java 7, le modèle à utiliser pour lire et appliquer le suffixe de fuseau horaire doit indiquer yyyy-MM-dd'T'HH:mm:ssX

34
Dave Patterson

tl; dr

Instant.parse ( "2010-04-05T17:16:00Z" )

Norme ISO 8601

Votre chaîne est conforme à la norme ISO 8601 (la RFC 3339 mentionnée étant un profil).

Évitez j.u.Date

Les classes Java.util.Date et .Calendar fournies avec Java sont notoirement gênantes. Évite-les.

Utilisez plutôt la bibliothèque Joda-Time ou le nouveau package Java.time dans Java 8. Ils utilisent tous deux ISO 8601 par défaut pour analyser et générer des représentations sous forme de chaîne des valeurs date-heure. 

Java.time

La structure Java.time intégrée à Java 8 et versions ultérieures supplante les anciennes classes problématiques Java.util.Date/.Calendar. Les nouvelles classes s’inspirent du très réussi framework Joda-Time , destiné à lui succéder, de concept similaire mais de nouvelle architecture. Défini par JSR 310 . Etendu par le projet ThreeTen-Extra . Voir le Tutorial .

La classe Instant dans Java.time représente un moment sur le scénario dans le fuseau horaire UTC .

La Z à la fin de votre chaîne de saisie signifie Zulu qui signifie UTC. Une telle chaîne peut être directement analysée par la classe Instant, sans qu'il soit nécessaire de spécifier un formateur.

String input = "2010-04-05T17:16:00Z";
Instant instant = Instant.parse ( input );

Dump à la console.

System.out.println ( "instant: " + instant );

instant: 2010-04-05T17: 16: 00Z

À partir de là, vous pouvez appliquer un fuseau horaire ( ZoneId ) pour ajuster cette Instant en une ZonedDateTime . Recherchez Stack Overflow pour discussion et exemples.

Si vous devez utiliser un objet Java.util.Date , vous pouvez convertir en appelant les nouvelles méthodes de conversion ajoutées aux anciennes classes telles que la méthode statique Java.util.Date.from( Instant ) .

Java.util.Date date = Java.util.Date.from( instant );

Joda-Time

Exemple dans Joda-Time 2.5.

DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" ):
DateTime dateTime = new DateTime( "2010-04-05T17:16:00Z", timeZone );

Convertir en UTC.

DateTime dateTimeUtc = dateTime.withZone( DateTimeZone.UTC );

Convertissez-le en Java.util.Date si nécessaire.

Java.util.Date date = dateTime.toDate();
19
Basil Bourque

Selon la dernière ligne de la table MODÈLES DE DATE ET D'HEURE de la API Java 7

X Fuseau horaire ISO 8601 fuseau horaire -08; -0800; -08: 00

Pour le fuseau horaire ISO 8601, vous devez utiliser: 

  • X pour (-08 ou Z), 
  • XX pour (-0800 ou Z),
  • XXX pour (-08: 00 ou Z);

donc pour analyser votre "2010-04-05T17: 16: 00Z", vous pouvez utiliser l'un ou l'autre "aaaa-MM-dd'T'HH: mm: ssX" ou "aaaa-MM-dd'T'HH: mm: ssXX" ou "yyyy-MM-dd'T'H: mm: ssXXX "

    System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX").parse("2010-04-05T17:16:00Z"));
    System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXX").parse("2010-04-05T17:16:00Z"));
    System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").parse("2010-04-05T17:16:00Z"));

imprimera correctement 'Mon Apr 05 13:16:00 EDT 2010'

12
Legna

Le 'X' ne fonctionne que si des secondes partielles ne sont pas présentes: c'est-à-dire le modèle SimpleDateFormat de

"aaaa-MM-jj'HH: mm: ssX"

Va correctement analyser

"2008-01-31T00: 00: 00Z"

mais

"aaaa-MM-jj'H'HH: mm: ss.SX"

Ne pas analyser

"2008-01-31T00: 00: 00.000Z"

Triste mais vrai, une date-heure avec des secondes partielles ne semble pas être une date ISO valide: http://en.wikipedia.org/wiki/ISO_8601

6
Sandy McPherson

Le fuseau horaire doit être quelque chose comme "GMT + 00: 00" ou 0000 pour être correctement analysé par SimpleDateFormat - vous pouvez remplacer Z par cette construction.

3
Cornel Creanga

Je fournis une autre réponse trouvée par api-client-library par Google

try {
    DateTime dateTime = DateTime.parseRfc3339(date);
    dateTime = new DateTime(new Date(dateTime.getValue()), TimeZone.getDefault());
    long timestamp = dateTime.getValue();  // get date in timestamp
    int timeZone = dateTime.getTimeZoneShift();  // get timezone offset
} catch (NumberFormatException e) {
    e.printStackTrace();
}

Guide d'installation,
https://developers.google.com/api-client-library/Java/google-api-Java-client/setup#download

Voici la référence de l'API,
https://developers.google.com/api-client-library/Java/google-http-Java-client/reference/1.20.0/com/google/api/client/util/DateTime

Code source de DateTime Class,
https://github.com/google/google-http-Java-client/blob/master/google-http-client/src/main/Java/com/google/api/client/util/DateTime .Java

DateTime tests unitaires,
https://github.com/google/google-http-Java-client/blob/master/google-http-client/src/test/Java/com/google/api/client/util/DateTimeTest .Java # L121

2
Johnny

En ce qui concerne JSR-310, un autre projet d’intérêt pourrait être threetenbp .

JSR-310 fournit une nouvelle bibliothèque de date et heure pour Java SE 8. Ce projet est le port de retour pour Java SE 6 et 7.

Si vous travaillez sur un projet Android, vous pouvez extraire la librairie ThreeTenABP .

compile "com.jakewharton.threetenabp:threetenabp:${version}"

JSR-310 était inclus dans Java 8 en tant que package Java.time. *. Il remplace complètement les API de date et de calendrier défaillantes sous Java et Android. JSR-310 a été rétroporté sur Java 6 par son créateur, Stephen Colebourne, à partir duquel cette bibliothèque est adaptée.

2
JJD

Le projet restlet comprend une classe InternetDateFormat capable d'analyser les dates RFC 3339.

Restlet InternetDateFormat

Cependant, vous voudrez peut-être simplement remplacer le «Z» final par «UTC» avant de l’analyser.

2
Marcus Adams

Sous Java 8, utilisez le paramètre prédéfini DateTimeFormatter.ISO_DATE_TIME.

 DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
 ZonedDateTime result = ZonedDateTime.parse("2010-04-05T17:16:00Z", formatter);

Je suppose que c'est le moyen le plus simple

1
JavaBohne

Depuis Java 8, utilisez simplement ZonedDateTime.parse("2010-04-05T17:16:00Z")

0