web-dev-qa-db-fra.com

Comment convertir String en Date sans connaître le format?

J'ai un problème. J'essaie de convertir certaines chaînes en date et je ne connais pas le format dans lequel la date arrive.

Il peut s'agir de yyyy.mm.dd hh:mm:ss ou MM.dd.yy hh:mm:ss et ainsi de suite.

Comment puis-je convertir ces chaînes en Date? J'ai essayé ceci:

DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
Date d = (Date)formatter.parse(someDate);

Mais quand j'ai imprimé quelque date, il a été imprimé comme ceci: 2010-08-05 12: 42: 48.638 CEST ce qui signifie yyyy.mm.dd hh:mm:ss, mais lorsque j'ai exécuté le code ci-dessus, l'objet de date est maintenant devenu Sat Jan 31 00:42:48 CET 11, ce qui est pour le moins étrange.

Des idées comment je peux correctement formater des chaînes à ce jour?

37
Shervin Asgari

Vous ne pouvez pas!

Si vous avez la date 2010-08-05, cela peut être soit le 5 août 2010, soit le 8 mai 2010 - vous avez besoin de connaître le format de la date (ou au moins privilégier un format par-dessus) pour les différencier.

42
Justin

Je suis d'accord avec Kragen pour dire que dans le cas général, il n'y a pas de solution correcte. Toutefois, si les conditions suivantes sont remplies, vous pouvez utiliser la solution ci-dessous:

  1. Vous avez un ensemble de tous les formats possibles

  2. Il n'y a pas d'ambiguïté entre les formats; aucune expression de date ne peut être analysée avec succès par deux d'entre elles.

Considérez la solution suivante qui itère sur une liste de formats possibles. Cette solution utilise ThreadLocal , afin de rendre l'analyse de la date efficace dans un environnement multi-thread (rappelez-vous que SimpleDateFormat n'est pas thread-safe):

public class FlexibleDateParser {
    private List<ThreadLocal<SimpleDateFormat>> threadLocals = new  ArrayList<ThreadLocal<SimpleDateFormat>>();

    public FlexibleDateParser(List<String> formats, final TimeZone tz){
        threadLocals.clear();
        for (final String format : formats) {
            ThreadLocal<SimpleDateFormat> dateFormatTL = new ThreadLocal<SimpleDateFormat>() {
                protected SimpleDateFormat initialValue() {
                    SimpleDateFormat sdf = new SimpleDateFormat(format);
                    sdf.setTimeZone(tz); 
                    sdf.setLenient(false);
                    return sdf;
                }
            };
            threadLocals.add(dateFormatTL);
        }       
    }

    public Date parseDate(String dateStr) throws ParseException {
        for (ThreadLocal<SimpleDateFormat> tl : threadLocals) {
            SimpleDateFormat sdf = tl.get();
            try {
                return sdf.parse(dateStr);
            } catch (ParseException e) {
                // Ignore and try next date parser
            }
        }
        // All parsers failed
        return null;
    }       
}
10
Eyal Schneider

Comme indiqué précédemment, vous devez au moins disposer d'une liste ordonnée de candidats modèles. Une fois que vous avez cela, Apache DateUtils a une méthode parseDate(String dateString, String[] patterns) qui vous permet d’essayer facilement une liste de modèles sur votre chaîne de date et de l’analyser par la première qui correspond:

public static Date parseDate(String str,
                         String[] parsePatterns)
                  throws ParseException

Analyse une chaîne représentant une date en essayant différents analyseurs.

L'analyse analysera chaque modèle d'analyse à son tour. Une analyse n'est considérée comme réussie que si elle analyse la totalité de la chaîne d'entrée. Si aucun modèle d'analyse ne correspond, une exception ParseException est levée.

L'analyseur sera indulgent vers la date analysée. 

7
oksayt

Voici une solution simple et rapide basée sur les formats de date américains.

public Date parseDate(String strDate) throws Exception
{
    if (strDate != null && !strDate.isEmpty())
    {
        SimpleDateFormat[] formats =
                new SimpleDateFormat[] {new SimpleDateFormat("MM-dd-yyyy"), new SimpleDateFormat("yyyyMMdd"),
                        new SimpleDateFormat("MM/dd/yyyy")};

        Date parsedDate = null;

        for (int i = 0; i < formats.length; i++)
        {
            try
            {
                parsedDate = formats[i].parse(strDate);
                return parsedDate;
            }
            catch (ParseException e)
            {
                continue;
            }
        }
    }
    throw new Exception("Unknown date format: '" + strDate + "'");
}
5
bjoern

Votre problème est lié à l'internationalisation. Comme Kragen a répondu, vous ne pouvez pas simplement analyser la date dans un format inconnu. Bien que vous puissiez analyser tous les paramètres régionaux et analyser quelque chose , vous ne pouvez pas savoir s'il a été correctement analysé.

Juste un petit fond i18n: 

Q: Pouvez-vous me dire à quel jour mois et année cette date se réfère:

09/11/10?

A: Sans connaître les lieux, vous ne pouvez pas. Cela pourrait être n'importe quoi. 11 septembre aux Etats-Unis. 9 novembre en Grande-Bretagne. Etc.

4
Paweł Dyda

Si c'est un protocole; définir le format - peut-être ISO qui irrite tout le monde sauf nous en Suède ...

Si cela provient des utilisateurs; Laissez-les définir leurs paramètres régionaux. Si vous pouvez le faire, affichez la date analysée au format complet pour que l’utilisateur puisse la vérifier, comme le 10 novembre 2009. 

1
KarlP

Ma seule hypothèse est que vous devriez d'abord rassembler des statistiques pour déterminer le format. 

Si vous avez de la chance, vous aurez une date du type "2010/08/13" qui peut être analysée sans ambiguïté.

0
Alexander Malakhov