Conversion D'une chaîne conforme à la norme ISO 8601 en java.util.Date

j'essaie de convertir une chaîne formatée ISO 8601 en une chaîne formatée java.util.Date .

j'ai trouvé le modèle yyyy-MM-dd'T'HH:mm:ssZ conforme à la norme ISO8601 s'il est utilisé avec une Locale (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 le côlon.

donc, 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", "+00");
System.out.println(ISO8601DATEFORMAT.parse(date));

ce qui n'est évidemment pas très gentil. Ai-je raté quelque chose ou est-il une meilleure solution?


réponse

grâce au commentaire de JuanZe, j'ai trouvé le Joda-Time magie, il est aussi décrit 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 gentil.

555
demandé sur wittich 2010-02-04 20:52:39

25 réponses

malheureusement, les formats de fuseaux horaires disponibles pour SimpleDateFormat (Java 6 et versions antérieures) ne sont pas conformes à ISO 8601 . SimpleDateFormat comprend des chaînes de fuseaux horaires comme " GMT+01:00 "ou" +0100", ce dernier selon RFC # 822 .

même si Java 7 a ajouté la prise en charge des descripteurs de fuseaux horaires selon ISO 8601, SimpleDateFormat n'est toujours pas capable de bien analyser une date complète chaîne, comme il n'a pas de support pour les pièces en option.

reformater votre chaîne de caractères en utilisant regexp est certainement une possibilité, mais les règles de remplacement ne sont pas aussi simples que dans votre question:

  • certains fuseaux horaires ne sont pas des heures complètes de repos UTC , de sorte que la chaîne ne se termine pas nécessairement par": 00".
  • ISO8601 permet seulement le nombre d'heures à inclure dans le fuseau horaire, donc "+01" est équivalent à" +01:00 "
  • ISO8601 permet l'utilisation de "Z" pour indiquer UTC au lieu de "+00:00".

la solution la plus simple est peut-être d'utiliser le convertisseur de type de données dans JAXB, puisque JAXB doit être capable d'analyser la chaîne de date ISO8601 selon la spécification de schéma XML. javax.xml.bind.DatatypeConverter.parseDateTime("2010-01-01T12:00:00Z") vous donnera un objet Calendar et vous pouvez simplement utiliser getTime() dessus, si vous avez besoin d'un objet Date .

vous pourriez utilisez probablement Joda-Time aussi, mais je ne sais pas pourquoi vous devriez vous en préoccuper.

429
répondu jarnbjo 2014-03-08 17:50:49

D'accord, cette question est déjà répondue, mais je vais laisser tomber ma réponse de toute façon. Il pourrait aider quelqu'un.

je cherchais une solution pour Android (API 7).

  • Joda était hors de question - il est énorme et souffre de l'initialisation lente. Il semble également qu'il s'agisse d'une surenchère majeure dans ce but précis.
  • les réponses concernant javax.xml ne fonctionneront pas sur L'API Android 7.

a fini par mettre en œuvre cette classe simple. Il ne couvre que la forme la plus courante des chaînes ISO 8601, mais cela devrait suffire dans certains cas (quand vous êtes sûr que l'entrée sera dans ce format).

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * Helper class for handling a most common subset of ISO 8601 strings
 * (in the following format: "2008-03-01T13:00:00+01:00"). It supports
 * parsing the "Z" timezone, but many other less-used features are
 * missing.
 */
public final class ISO8601 {
    /** Transform Calendar to ISO 8601 string. */
    public static String fromCalendar(final Calendar calendar) {
        Date date = calendar.getTime();
        String formatted = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
            .format(date);
        return formatted.substring(0, 22) + ":" + formatted.substring(22);
    }

    /** Get current date and time formatted as ISO 8601 string. */
    public static String now() {
        return fromCalendar(GregorianCalendar.getInstance());
    }

    /** Transform ISO 8601 string to Calendar. */
    public static Calendar toCalendar(final String iso8601string)
            throws ParseException {
        Calendar calendar = GregorianCalendar.getInstance();
        String s = iso8601string.replace("Z", "+00:00");
        try {
            s = s.substring(0, 22) + s.substring(23);  // to get rid of the ":"
        } catch (IndexOutOfBoundsException e) {
            throw new ParseException("Invalid length", 0);
        }
        Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(s);
        calendar.setTime(date);
        return calendar;
    }
}

Performance note: j'instancie new SimpleDateFormat chaque fois que les moyens de les éviter bug en Android 2.1. Si vous êtes comme étonné comme je l'étais, voir cette énigme . Pour les autres moteurs Java, vous pouvez mettre en cache l'instance dans un champ statique privé (en utilisant ThreadLocal, pour être sûr du thread).

191
répondu wrygiel 2017-05-23 12:10:47

Le chemin qui est béni par Java 7 documentation :

DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
String string1 = "2001-07-04T12:08:56.235-0700";
Date result1 = df1.parse(string1);

DateFormat df2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
String string2 = "2001-07-04T12:08:56.235-07:00";
Date result2 = df2.parse(string2);

vous pouvez trouver d'autres exemples dans la section exemples à SimpleDateFormat javadoc .

176
répondu Antonio 2015-11-17 20:24:47

de java.time

Le de java.L'API de temps (intégrée dans Java 8 et plus tard), rend cela un peu plus facile.

si vous savez que l'entrée est dans UTC , tel que le Z (pour Zoulou) sur la fin, le Instant classe peut parse.

java.util.Date date = Date.from( Instant.parse( "2014-12-12T10:39:40Z" ));

si votre entrée peut être une autre offset-from-UTC valeurs plutôt que UTC indiqué par le Z (Zoulou) à la fin, utilisez le OffsetDateTime classe à analyser.

OffsetDateTime odt = OffsetDateTime.parse( "2010-01-01T12:00:00+01:00" );

puis extraire un Instant , et convertir en un java.util.Date en appelant from .

Instant instant = odt.toInstant();  // Instant is always in UTC.
java.util.Date date = java.util.Date.from( instant );
69
répondu Adam 2017-04-18 09:57:46

Le Jackson-databind bibliothèque a aussi ISO8601DateFormat classe qui fait que (la mise en oeuvre du ISO8601Utils .

ISO8601DateFormat df = new ISO8601DateFormat();
Date d = df.parse("2010-07-28T22:25:51Z");
61
répondu david_p 2013-07-05 14:23:43

tl; dr

OffsetDateTime.parse ( "2010-01-01T12:00:00+01:00" )

utilisant java.time

La nouvelle de java.time paquet en Java 8 et plus tard a été inspiré par Joda-Time.

la classe OffsetDateTime représente un moment sur la ligne de temps avec un offset-from-UTC mais pas un fuseau horaire.

OffsetDateTime odt = OffsetDateTime.parse ( "2010-01-01T12:00:00+01:00" );

appelant toString génère une chaîne de caractères au format standard ISO 8601:

2010-01-01T12: 00+01 :00

pour voir la même valeur à travers la lentille de UTC, extraire un Instant ou ajuster l'offset de +01:00 à 00:00 .

Instant instant = odt.toInstant();  

... ou ...

OffsetDateTime odtUtc = odt.withOffsetSameInstant( ZoneOffset.UTC );

ajuster dans un fuseau horaire si désiré. Un fuseau horaire est un historique des valeurs de offset-from-UTC pour une région, avec un ensemble de règles pour traiter les anomalies telles que L'heure avancée (HNT). Ainsi, appliquez un fuseau horaire plutôt qu'un simple décalage chaque fois que c'est possible.

ZonedDateTime zonedDateTimeMontréal = odt.atZoneSameInstant( ZoneId.of( "America/Montreal" ) );

à Propos de de java.heure

Le de java.time framework est construit dans Java 8 et plus tard. Ces classes remplacent les anciennes héritées classes de date-heure telles que comme java.util.Date , Calendar , & SimpleDateFormat .

le Joda-Time projet, maintenant dans mode de maintenance , conseille la migration vers le java.temps des classes.

pour en savoir plus, voir le Oracle Tutorial . Et rechercher le débordement de la pile pour de nombreux exemples et explications. La spécification est JSR 310 .

vous pouvez échanger java.temps objets directement avec votre base de données. Utiliser un JDBC driver conforme à JDBC 4.2 ou plus tard. Pas besoin de Chaînes, pas besoin de classes java.sql.* .

où obtenir le java.les classes de temps?

Le ThreeTen-Extra le projet s'étend java.temps avec des cours supplémentaires. Ce projet est un terrain d'expérimentation pour d'éventuelles futures additions à java.temps. Vous pouvez trouver ici quelques cours utiles tels que: Interval , YearWeek , YearQuarter , et plus .


33
répondu Basil Bourque 2018-05-23 02:09:06

pour la version Java 7

vous pouvez suivre la documentation D'Oracle: http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

X-est utilisé pour le fuseau horaire ISO 8601

TimeZone tz = TimeZone.getTimeZone("UTC");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
df.setTimeZone(tz);
String nowAsISO = df.format(new Date());

System.out.println(nowAsISO);

DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
//nowAsISO = "2013-05-31T00:00:00Z";
Date finalResult = df1.parse(nowAsISO);

System.out.println(finalResult);
26
répondu d.danailov 2014-04-08 14:20:28

la solution DatatypeConverter ne fonctionne pas dans tous les Vm. Les œuvres suivantes pour moi:

javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar("2011-01-01Z").toGregorianCalendar().getTime()

j'ai trouvé que joda ne fonctionne pas de la boîte (spécifiquement pour l'exemple que j'ai donné ci-dessus avec le fuseau horaire sur une date, qui devrait être valide)

20
répondu James Scriven 2013-01-09 11:15:04

je pense qu'on devrait utiliser

DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")

pour la Date 2010-01-01T12:00:00Z

18
répondu Toby 2013-12-23 13:56:05

une autre façon très simple d'analyser les horodateurs ISO8601 est d'utiliser org.apache.commons.lang.time.DateUtils :

import static org.junit.Assert.assertEquals;

import java.text.ParseException;
import java.util.Date;
import org.apache.commons.lang.time.DateUtils;
import org.junit.Test;

public class ISO8601TimestampFormatTest {
  @Test
  public void parse() throws ParseException {
    Date date = DateUtils.parseDate("2010-01-01T12:00:00+01:00", new String[]{ "yyyy-MM-dd'T'HH:mm:ssZZ" });
    assertEquals("Fri Jan 01 12:00:00 CET 2010", date.toString());
  }
}
8
répondu tmandry 2013-08-22 14:05:35

de java.temps

notez qu'en Java 8, Vous pouvez utiliser le java.temps.ZonedDateTime de la classe et de ses statique parse(CharSequence text) la méthode.

6
répondu Martin Rust 2014-07-20 16:59:08

j'ai affronté le même problème et l'ai résolu par le code suivant .

 public static Calendar getCalendarFromISO(String datestring) {
    Calendar calendar = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault()) ;
    SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());
    try {
        Date date = dateformat.parse(datestring);
        date.setHours(date.getHours() - 1);
        calendar.setTime(date);

        String test = dateformat.format(calendar.getTime());
        Log.e("TEST_TIME", test);

    } catch (ParseException e) {
        e.printStackTrace();
    }

    return calendar;
}

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é la cause principale de l'exception était le yyyy-MM-dd'T'HH:mm:ss.SSSZ ,

donc j'ai utilisé

SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());

ça a bien marché pour moi .

4
répondu Abhay Kumar 2015-07-10 09:05:26

vous pouvez Également utiliser la classe suivante -

org.springframework.extensions.surf.util.ISO8601DateFormat


Date date = ISO8601DateFormat.parse("date in iso8601");

Lien vers la Java Doc - Hiérarchie Pour le Package org.springframework.extension.surf.maven.plugin.jusqu'à

4
répondu Sergey Palyukh 2016-07-28 09:30:16

Apache Jackrabbit utilise le format ISO 8601 pour les dates persistantes, et il y a une classe helper pour les analyser:

org.Apache.jackrabbit.util.ISO8601

vient avec jackrabbit-jcr-commons .

3
répondu Alexander Klimetschek 2013-04-22 10:28:33

comme D'autres l'ont mentionné Android n'a pas une bonne façon de prendre en charge parsing/formatage ISO 8601 dates en utilisant des classes incluses dans le SDK. J'ai écrit ce code plusieurs fois donc j'ai finalement créé un Gist qui inclut 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 d'essai montrant ce qu'il supporte.

https://gist.github.com/mraccola/702330625fad8eebe7d3

3
répondu Matt Accola 2015-06-20 05:01:12

la solution 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 X caractère et lancera

IllegalArgumentException: Unknown pattern character 'X'

Nous avons besoin de normaliser la date ISO8601 au format lisible en Java 6 avec SimpleDateFormat .

public static Date iso8601Format(String formattedDate) throws ParseException {
    try {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.US);
        return df.parse(formattedDate);
    } catch (IllegalArgumentException ex) {
        // error happen in Java 6: Unknown pattern character 'X'
        if (formattedDate.endsWith("Z")) formattedDate = formattedDate.replace("Z", "+0000");
        else formattedDate = formattedDate.replaceAll("([+-]\d\d):(\d\d)\s*$", "");
        DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
        return df1.parse(formattedDate);
    }
}

méthode ci-dessus pour remplacer [ Z par +0000 ] ou [ +01:00 par +0100 ] lorsque L'erreur se produit dans Java 6 (Vous pouvez détecter la version Java et remplacer try/catch par IF statement).

3
répondu Khang .NT 2017-05-16 09:42:19

SimpleDateFormat pour JAVA 1.7 a un motif cool pour le format ISO 8601.

Classe SimpleDateFormat

voici ce que j'ai fait:

Date d = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ",
         Locale.ENGLISH).format(System.currentTimeMillis());
2
répondu Eesha 2016-07-28 09:28:28

Java a une douzaine de façons différentes pour analyser une date-heure, comme les excellentes réponses ici démontrent. Mais un peu étonnamment, aucune des classes de temps de Java n'implémente complètement ISO 8601!

avec Java 8, je recommande:

ZonedDateTime zp = ZonedDateTime.parse(string);
Date date = Date.from(zp.toInstant());

qui traitera les exemples à la fois en UTC et avec un offset, comme "2017-09-13T10: 36: 40Z" ou "2017-09-13T10:36:40+01:00". Il le fera pour la plupart des cas d'utilisation.

mais il ne traitera pas les exemples comme "2017-09-13T10:36: 40+01", Qui est une date-heure ISO 8601 valide.

Il ne traitera pas seulement de la date, par exemple"2017-09-13".

si vous devez les gérer, je suggère d'utiliser un regex pour renifler la syntaxe.

il y a une belle liste D'exemples ISO 8601 ici avec beaucoup de cas de coin: https://www.myintervals.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck / i'm Je ne suis pas au courant d'une classe de Java qui pourrait faire face à tous.

2
répondu Daniel Winterstein 2017-09-13 11:22:54

utilisez une chaîne comme LocalDate.parse(((String) data.get("d_iso8601")),DateTimeFormatter.ISO_DATE)

1
répondu Stepan 2017-07-18 14:57:35

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 aussi sur Android.

quand j'ai googlé mes besoins, je suis tombé sur cette question, et j'ai remarqué que AFAIU, aucune réponse ne correspond complètement à mes besoins. Alors j'ai développé jISO8601 et je l'ai poussé sur maven central.

il suffit d'ajouter en vous pom.xml :

<dependency>
  <groupId>fr.turri</groupId>
  <artifactId>jISO8601</artifactId>
  <version>0.2</version>
</dependency>

et alors vous êtes bon pour aller:

import fr.turri.jiso8601.*;
...
Calendar cal = Iso8601Deserializer.toCalendar("1985-03-04");
Date date = Iso8601Deserializer.toDate("1985-03-04T12:34:56Z");

espère que ça aidera.

0
répondu gturri 2016-01-29 17:30:57

pour simplement formater une date comme celle-ci ce qui suit a fonctionné pour moi dans une application basée sur Java 6. Il y a une DateFormat classe JacksonThymeleafISO8601DateFormat dans le projet thymeleaf qui insère le colon manquant:

https://github.com/thymeleaf/thymeleaf/blob/40d27f44df7b52eda47d1bc6f1b3012add6098b3/src/main/java/org/thymeleaf/standard/serializer/StandardJavaScriptSerializer.java

Je l'ai utilisé pour le format Date ECMAScript de compatibilité.

0
répondu ekip 2016-10-09 14:29:20

Faire comme ceci:

public static void main(String[] args) throws ParseException {

    String dateStr = "2016-10-19T14:15:36+08:00";
    Date date = javax.xml.bind.DatatypeConverter.parseDateTime(dateStr).getTime();

    System.out.println(date);

}

Voici la sortie:

Wed Oct 19 15:15: 36 CST 2016

0
répondu yinhaomin 2016-10-19 07:04:30

fonction de Base courtoisie: @wrygiel.

cette fonction peut convertir le format ISO8601 en date Java qui peut gérer les valeurs offset. Conformément à la définition de la norme ISO 8601 , l'offset peut être mentionné dans différents formats.

±[hh]:[mm]
±[hh][mm]
±[hh]

Eg:  "18:30Z", "22:30+04", "1130-0700", and "15:00-03:30" all mean the same time. - 06:30PM UTC

Cette classe possède des méthodes statiques pour convertir

  • ISO8601 chaîne à Date(fuseau horaire Local) objet
  • date à ISO8601 string
  • L'heure D'été est automatiquement calc

exemple de chaîne ISO8601

/*       "2013-06-25T14:00:00Z";
         "2013-06-25T140000Z";
         "2013-06-25T14:00:00+04";
         "2013-06-25T14:00:00+0400";
         "2013-06-25T140000+0400";
         "2013-06-25T14:00:00-04";
         "2013-06-25T14:00:00-0400";
         "2013-06-25T140000-0400";*/


public class ISO8601DateFormatter {

private static final DateFormat DATE_FORMAT_1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
private static final DateFormat DATE_FORMAT_2 = new SimpleDateFormat("yyyy-MM-dd'T'HHmmssZ");
private static final String UTC_PLUS = "+";
private static final String UTC_MINUS = "-";

public static Date toDate(String iso8601string) throws ParseException {
    iso8601string = iso8601string.trim();
    if(iso8601string.toUpperCase().indexOf("Z")>0){
        iso8601string = iso8601string.toUpperCase().replace("Z", "+0000");
    }else if(((iso8601string.indexOf(UTC_PLUS))>0)){
        iso8601string = replaceColon(iso8601string, iso8601string.indexOf(UTC_PLUS));
        iso8601string = appendZeros(iso8601string, iso8601string.indexOf(UTC_PLUS), UTC_PLUS);
    }else if(((iso8601string.indexOf(UTC_MINUS))>0)){
        iso8601string = replaceColon(iso8601string, iso8601string.indexOf(UTC_MINUS));
        iso8601string = appendZeros(iso8601string, iso8601string.indexOf(UTC_MINUS), UTC_MINUS);
    }

    Date date = null;
    if(iso8601string.contains(":"))
        date = DATE_FORMAT_1.parse(iso8601string);
    else{
        date = DATE_FORMAT_2.parse(iso8601string);
    }
    return date;
}

public static String toISO8601String(Date date){
    return DATE_FORMAT_1.format(date);
}

private static String replaceColon(String sourceStr, int offsetIndex){
    if(sourceStr.substring(offsetIndex).contains(":"))
        return sourceStr.substring(0, offsetIndex) + sourceStr.substring(offsetIndex).replace(":", "");
    return sourceStr;
}

private static String appendZeros(String sourceStr, int offsetIndex, String offsetChar){
    if((sourceStr.length()-1)-sourceStr.indexOf(offsetChar,offsetIndex)<=2)
        return sourceStr + "00";
    return sourceStr;
}

}

-1
répondu AKh 2013-06-25 23:28:06

cela a semblé mieux fonctionner pour moi:

public static Date fromISO8601_( String string ) {

    try {
            return new SimpleDateFormat ( "yyyy-MM-dd'T'HH:mm:ssXXX").parse ( string );
    } catch ( ParseException e ) {
        return Exceptions.handle (Date.class, "Not a valid ISO8601", e);
    }


}

j'avais besoin de convertir en/de javascript date strings en Java. J'ai trouvé les travaux ci-dessus avec la recommandation. Il y avait quelques exemples utilisant SimpleDateFormat qui étaient proches mais ils ne semblaient pas être le sous-ensemble comme recommandé par:

http://www.w3.org/TR/NOTE-datetime

et pris en charge par des chaînes de caractères PLIST et JavaScript et telles que est ce qu'il me fallait.

cela semble être la forme la plus courante de chaîne ISO8601 là-bas, et un bon sous-ensemble.

les exemples qu'ils donnent sont:

1994-11-05T08:15:30-05:00 corresponds 
November 5, 1994, 8:15:30 am, US Eastern Standard Time.

 1994-11-05T13:15:30Z corresponds to the same instant.

j'ai aussi une version rapide:

final static int SHORT_ISO_8601_TIME_LENGTH =  "1994-11-05T08:15:30Z".length ();
                                            // 01234567890123456789012
final static int LONG_ISO_8601_TIME_LENGTH = "1994-11-05T08:15:30-05:00".length ();


public static Date fromISO8601( String string ) {
    if (isISO8601 ( string )) {
        char [] charArray = Reflection.toCharArray ( string );//uses unsafe or string.toCharArray if unsafe is not available
        int year = CharScanner.parseIntFromTo ( charArray, 0, 4 );
        int month = CharScanner.parseIntFromTo ( charArray, 5, 7 );
        int day = CharScanner.parseIntFromTo ( charArray, 8, 10 );
        int hour = CharScanner.parseIntFromTo ( charArray, 11, 13 );

        int minute = CharScanner.parseIntFromTo ( charArray, 14, 16 );

        int second = CharScanner.parseIntFromTo ( charArray, 17, 19 );

        TimeZone tz ;

         if (charArray[19] == 'Z') {

             tz = TimeZone.getTimeZone ( "GMT" );
         } else {

             StringBuilder builder = new StringBuilder ( 9 );
             builder.append ( "GMT" );
             builder.append( charArray, 19, LONG_ISO_8601_TIME_LENGTH - 19);
             String tzStr = builder.toString ();
             tz = TimeZone.getTimeZone ( tzStr ) ;

         }
         return toDate ( tz, year, month, day, hour, minute, second );

    }   else {
        return null;
    }

}

...

public static int parseIntFromTo ( char[] digitChars, int offset, int to ) {
    int num = digitChars[ offset ] - '0';
    if ( ++offset < to ) {
        num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
        if ( ++offset < to ) {
            num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
            if ( ++offset < to ) {
                num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                if ( ++offset < to ) {
                    num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                    if ( ++offset < to ) {
                        num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                        if ( ++offset < to ) {
                            num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                            if ( ++offset < to ) {
                                num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                                if ( ++offset < to ) {
                                    num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return num;
}


public static boolean isISO8601( String string ) {
      boolean valid = true;

      if (string.length () == SHORT_ISO_8601_TIME_LENGTH) {
          valid &=  (string.charAt ( 19 )  == 'Z');

      } else if (string.length () == LONG_ISO_8601_TIME_LENGTH) {
          valid &=  (string.charAt ( 19 )  == '-' || string.charAt ( 19 )  == '+');
          valid &=  (string.charAt ( 22 )  == ':');

      } else {
          return false;
      }

    //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
    // "1 9 9 4 - 1 1 - 0 5 T 0 8 : 1 5 : 3 0 - 0 5 : 0 0

    valid &=  (string.charAt ( 4 )  == '-') &&
                (string.charAt ( 7 )  == '-') &&
                (string.charAt ( 10 ) == 'T') &&
                (string.charAt ( 13 ) == ':') &&
                (string.charAt ( 16 ) == ':');

    return valid;
}

Je ne l'ai pas référencé, mais je pense que ce sera assez rapide. Il semble fonctionner. :)

@Test
public void testIsoShortDate() {
    String test =  "1994-11-05T08:15:30Z";

    Date date = Dates.fromISO8601 ( test );
    Date date2 = Dates.fromISO8601_ ( test );

    assertEquals(date2.toString (), date.toString ());

    puts (date);
}

@Test
public void testIsoLongDate() {
    String test =  "1994-11-05T08:11:22-05:00";

    Date date = Dates.fromISO8601 ( test );
    Date date2 = Dates.fromISO8601_ ( test );

    assertEquals(date2.toString (), date.toString ());

    puts (date);
}
-1
répondu RickHigh 2013-12-14 00:32:36

je pense que ce que beaucoup de gens veulent faire c'est Parser JSON date strings. Il ya une bonne chance si vous venez à cette page que vous pourriez vouloir convertir une date JavaScript JSON à une date Java.

pour montrer à quoi ressemble une chaîne de date JSON:

    var d=new Date();
    var s = JSON.stringify(d);

    document.write(s);
    document.write("<br />"+d);


    "2013-12-14T01:55:33.412Z"
    Fri Dec 13 2013 17:55:33 GMT-0800 (PST)

la chaîne de datation JSON est 2013-12-14T01: 55: 33.412 Z.

Les Dates

ne sont pas couvertes par JSON spec per say, mais ce qui précède est un format ISO 8601 très spécifique, alors que ISO_8601 est beaucoup plus grand et c'est un simple sous-ensemble, bien qu'il soit très important.

voir http://www.json.org Voir http://en.wikipedia.org/wiki/ISO_8601 Voir http://www.w3.org/TR/NOTE-datetime

il se trouve que j'ai écrit un analyseur JSON et un analyseur PLIST qui utilisent tous les deux ISO-8601 mais pas les mêmes bits.

/*
    var d=new Date();
    var s = JSON.stringify(d);

    document.write(s);
    document.write("<br />"+d);


    "2013-12-14T01:55:33.412Z"
    Fri Dec 13 2013 17:55:33 GMT-0800 (PST)


 */
@Test
public void jsonJavaScriptDate() {
    String test =  "2013-12-14T01:55:33.412Z";

    Date date = Dates.fromJsonDate ( test );
    Date date2 = Dates.fromJsonDate_ ( test );

    assertEquals(date2.toString (), "" + date);

    puts (date);
}

j'ai écrit deux façons de faire ceci pour mon projet. Un standard, un rapide.

encore une fois, JSON date string est une implémentation très spécifique de la norme ISO 8601....

(j'ai posté l'autre dans l'autre réponse qui devrait fonctionner pour les dates de PLIST, qui sont un format différent ISO 8601).

la date JSON est la suivante:

public static Date fromJsonDate_( String string ) {

    try {

        return new SimpleDateFormat ( "yyyy-MM-dd'T'HH:mm:ss.SSSXXX").parse ( string );
    } catch ( ParseException e ) {
        return Exceptions.handle (Date.class, "Not a valid JSON date", e);
    }


}

PLIST files (ASCII non GNUNext) utilise aussi ISO 8601 mais pas de millisecondes... les dates ISO-8601 ne sont pas toutes les mêmes. (À au moins, je n'ai pas encore trouvé un qui utilise milis et l'analyseur que j'ai vu sauter le fuseau horaire tout à fait OMG).

Maintenant, pour la version rapide (vous pouvez le trouver dans Boon).

public static Date fromJsonDate( String string ) {

    return fromJsonDate ( Reflection.toCharArray ( string ), 0, string.length () );

}

Notez cette réflexion.toCharArray utilise unsafe si disponible mais par défaut à string.toCharArray si pas.

(vous pouvez le retirer de l'exemple en remplaçant la réflexion.toCharArray (string) avec string.toCharArray ()).

public static Date fromJsonDate( char[] charArray, int from, int to ) {

    if (isJsonDate ( charArray, from, to )) {
        int year = CharScanner.parseIntFromTo ( charArray, from + 0, from + 4 );
        int month = CharScanner.parseIntFromTo ( charArray,  from +5,  from +7 );
        int day = CharScanner.parseIntFromTo ( charArray,  from +8,  from +10 );
        int hour = CharScanner.parseIntFromTo ( charArray,  from +11,  from +13 );

        int minute = CharScanner.parseIntFromTo ( charArray,  from +14,  from +16 );

        int second = CharScanner.parseIntFromTo ( charArray,  from +17,  from +19 );

        int miliseconds = CharScanner.parseIntFromTo ( charArray,  from +20,  from +23 );

        TimeZone tz = TimeZone.getTimeZone ( "GMT" );


        return toDate ( tz, year, month, day, hour, minute, second, miliseconds );

    }   else {
        return null;
    }

}

La isJsonDate est mis en œuvre comme suit:

public static boolean isJsonDate( char[] charArray, int start, int to ) {
    boolean valid = true;
    final int length = to -start;

    if (length != JSON_TIME_LENGTH) {
        return false;
    }

    valid &=  (charArray [ start + 19 ]  == '.');

    if (!valid) {
        return false;
    }


    valid &=  (charArray[  start +4 ]  == '-') &&
            (charArray[  start +7 ]  == '-') &&
            (charArray[  start +10 ] == 'T') &&
            (charArray[  start +13 ] == ':') &&
            (charArray[  start +16 ] == ':');

    return valid;
}

en tout cas... ma conjecture est que très peu de gens qui viennent ici.. pourrait être à la recherche de la chaîne de Date JSON et bien qu'il s'agisse D'une date ISO-8601, il s'agit d'une date très spécifique qui nécessite une analyse très spécifique.

public static int parseIntFromTo ( char[] digitChars, int offset, int to ) {
    int num = digitChars[ offset ] - '0';
    if ( ++offset < to ) {
        num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
        if ( ++offset < to ) {
            num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
            if ( ++offset < to ) {
                num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                if ( ++offset < to ) {
                    num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                    if ( ++offset < to ) {
                        num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                        if ( ++offset < to ) {
                            num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                            if ( ++offset < to ) {
                                num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                                if ( ++offset < to ) {
                                    num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return num;
}

voir https://github.com/RichardHightower/boon Boon a un analyseur PLIST (ASCII) et un analyseur JSON.

le JSON parser est L'analyseur Java le plus rapide que je connaisse.

vérifié indépendamment par les Gatling Performance dudes.

https://github.com/gatling/json-parsers-benchmark

Benchmark                               Mode Thr     Count  Sec         Mean   Mean error        Units
BoonCharArrayBenchmark.roundRobin      thrpt  16        10    1   724815,875    54339,825    ops/s
JacksonObjectBenchmark.roundRobin      thrpt  16        10    1   580014,875   145097,700    ops/s
JsonSmartBytesBenchmark.roundRobin     thrpt  16        10    1   575548,435    64202,618    ops/s
JsonSmartStringBenchmark.roundRobin    thrpt  16        10    1   541212,220    45144,815    ops/s
GSONStringBenchmark.roundRobin         thrpt  16        10    1   522947,175    65572,427    ops/s
BoonDirectBytesBenchmark.roundRobin    thrpt  16        10    1   521528,912    41366,197    ops/s
JacksonASTBenchmark.roundRobin         thrpt  16        10    1   512564,205   300704,545    ops/s
GSONReaderBenchmark.roundRobin         thrpt  16        10    1   446322,220    41327,496    ops/s
JsonSmartStreamBenchmark.roundRobin    thrpt  16        10    1   276399,298   130055,340    ops/s
JsonSmartReaderBenchmark.roundRobin    thrpt  16        10    1    86789,825    17690,031    ops/s

il possède l'analyseur JSON le plus rapide pour streams, readers, bytes[], char[], CharSequence (StringBuilder, CharacterBuffer), et String.

voir plus de points de repère à:

https://github.com/RichardHightower/json-parsers-benchmark

-2
répondu RickHigh 2013-12-14 02:48:34