Aller au contenu

[Résolu] Problème de conversion de dates récupérées d'une base SQLite


Recommended Posts

Bonjour,

 

Après avoir parsé un fichier .plist et avoir enregistré des données de type date dans ma base de données SQLite, j'aimerais récupérer une donnée spécifique pour l'afficher. Rien de compliqué en soi, sauf que la donnée enregistrée dans la base est de ce type :

2012-06-05T06:00:00Z

Et la donnée affichée dans mon application est interprétée automatiquement comme cela dans ma TextView :

Tue Jun 05 06:00:00 UTC+00:00 2012

Déjà, je ne comprends pas pourquoi elle est interprétée de cette manière alors que c'est normalement du texte donc si vous avez une idée...

 

Ensuite vient la question du format, car grâce à un SimpleDateFormat, je peux normalement interpréter ma date (qui est bien stockée en String dans ma base de données), mais lors de l'interprétation, cela ne fonctionne pas. Si je prends un exemple basé sur une solution StackOverflow :

 

Cela fonctionne :

String str = "26/08/1994";

SimpleDateFormat inputFormatter = new SimpleDateFormat("dd/MM/yyyy");
SimpleDateFormat outputFormatter = new SimpleDateFormat("MM/dd");

try {
    Date date = inputFormatter.parse(str);
    String text = outputFormatter.format(date);
    Log.d("t", text);
} catch (ParseException e ) {
    e.printStackTrace();
}

Mais mon exemple de date ne fonctionne pas :

String str = "Tue Jun 05 06:00:00 UTC+00:00 2012";

SimpleDateFormat inputFormatter = new SimpleDateFormat("EEE MMM d HH:mm:ss z yyyy");
SimpleDateFormat outputFormatter = new SimpleDateFormat("MM/dd");

try {
    Date date = inputFormatter.parse(str);
    String text = outputFormatter.format(date);
    Log.d("t", text);
} catch (ParseException e ) {
    e.printStackTrace();
}

J'ai cette exception :

java.text.ParseException: Unparseable date: "Tue Jun 05 06:00:00 UTC+00:00 2012" (at offset 0)
W/System.err: at java.text.DateFormat.parse(DateFormat.java:626)

Est-ce que cela viendrait d'une erreur de format ?

 

Cela fait deux jours que j'essaye de résoudre le problème, mais pas moyen de trouver une solution, donc si vous avez déjà eu le soucis et/ou que vous avez une solution, je suis preneur !

 

Merci d'avance !

 

Modifié par jok
Lien vers le commentaire
Partager sur d’autres sites

Tu ne spécifies pas de Locale pour ton parser, donc il utilise la Locale par défaut de ton device (donc sûrement français), mais tu lui fournis une chaîne avec une date en anglais. De cette façon, ce sera mieux:

SimpleDateFormat inputFormatter = new SimpleDateFormat("EEE MMM d HH:mm:ss z yyyy", Locale.ENGLISH);
  • Like 1
Lien vers le commentaire
Partager sur d’autres sites

Merci pour vos réponses !

 

J'ai oublié de préciser dans mon message, mais j'ai bien essayé de spécifier la Locale (en English, mais aussi en US et en French au cas où), mais rien n'y fait. L'exception est la même sauf que j'ai "at offset 23" à la place du "at offset 0" dans le message d'erreur.

 

Aussi, en spécifiant la date en français, cela ne fonctionne pas non plus (j'ai toujours un "at offset 0" pour le coup).

 

Enfin, ma variable str est initialisée manuellement pour que vous compreniez ce que je récupère, mais c'est normalement récupéré depuis la base de données :

String str = dbh.getProduit(id).getDate(); // Avec dbh mon DatabaseHandler

J'ai même essayé de faire un str.trim() pour virer les éventuels espaces, mais rien n'y fait. :/

Lien vers le commentaire
Partager sur d’autres sites

Si en mettant une Locale différente, le message d'erreur est différent, c'est bien que la Locale a une influence ;) A l'offset 23, c'est sur la timezone que ça coince

Essaye ceci comme masque de parsing, car j'ai l'impression, d'après la doc, qu'il te manque une partie pour parser le décalage horaire

SimpleDateFormat inputFormatter = new SimpleDateFormat("EEE MMM d HH:mm:ss zZZZZZ yyyy", Locale.ENGLISH);
  • Like 1
Lien vers le commentaire
Partager sur d’autres sites

Je me doutais bien que ça venait du format... Et voilà, c'est pile ce zZZZZZ qu'il me manquait ! Merci !

 

Juste quelques questions avant de clôturer le topic :

- Est-ce qu'en passant la Locale en anglais dans le inputFormatter elle le sera aussi dans le outputFormatter ou cela dépend de la langue de l'appareil ?

- Est-ce que c'est possible (et conseillé) d'adapter la langue de l'application en fonction de celle de l'appareil ?

 

Encore merci !

Lien vers le commentaire
Partager sur d’autres sites

- La Locale est dépendante de l'instance de SimpleDateFormat, donc, si tu ne le spécifies pas lors de la construction du second, il prendra la valeur par défaut (celle de la machine)

- Oui, c'est conseillé, et c'est même ce que fait Android dès que tu utilises les ressources pour les libellés, etc...

  • Like 1
Lien vers le commentaire
Partager sur d’autres sites

  • 11 months later...

Bonjour,

 

Je tenais à continuer ce sujet (datant d'il y a un an déjà !) plutôt que d'en ouvrir un autre car j'ai un soucis dans la continuité de ce problème.

 

Pour résumer, j'ai une méthode de conversion de dates qui est censée convertir la chaîne de caractères que j'envoie en paramètre.

Le problème, c'est toujours avec cette fameuse TimeZone car selon l'appareil utilisé, elle est différente et peut faire planter la conversion. Par exemple sur deux tablettes :

- La Samsung Galaxy Tab 1 interprète en UTC+00:00,

- La Nexus 7 interprète en CEST ou CET selon son humeur la date qu'elle voit en entrée (?).

 

Le format de TimeZone (ou le nombre de Z) n'est donc pas identique !

 

Pour l'instant, voici la condition que je fais dans ma fonction pour contourner le problème :

public String convertDate(String inputDate) {
        String outputDate = null;

        SimpleDateFormat inputFormatter = new SimpleDateFormat();

        if(inputDate.contains("UTC")) {
            inputFormatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss 'UTC+00:00' yyyy", Locale.US);
        }
        else if(inputDate.contains("CEST")) {
            inputFormatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss 'CEST' yyyy", Locale.US);
        }
        else if(inputDate.contains("CET")) {
            inputFormatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss 'CET' yyyy", Locale.US);
        }

        SimpleDateFormat outputFormatter = new SimpleDateFormat("yyyyMMddHHmmss", Locale.FRANCE);

        try {
            Date d = inputFormatter.parse(inputDate);
            outputDate = outputFormatter.format(d);
        } catch (ParseException e ) {
            e.printStackTrace();
        }

        return outputDate;
    }

Sauf que j'imagine qu'il y a d'autres TimeZones et que ça va forcément planter sur d'autres appareils... Avez-vous déjà eu ce soucis ?

Lien vers le commentaire
Partager sur d’autres sites

Bonjour,

 

Sans doute qu'en réinjectant la TimeZone parsée dans le formatter, tu obtiendrais le résultat que tu souhaites:

public String convertDate(String inputDate) {
    String outputDate = null;
    SimpleDateFormat inputFormatter = new SimpleDateFormat("EEE MMM d HH:mm:ss zZZZZZ yyyy", Locale.ENGLISH);
    SimpleDateFormat outputFormatter = new SimpleDateFormat("yyyyMMddHHmmss", Locale.FRANCE);
    try {
        Date d = inputFormatter.parse(inputDate);
        outputFormatter.setTimeZone(inputFormatter.getTimeZone());
        outputDate = outputFormatter.format(d);
    } catch (ParseException e ) {
        e.printStackTrace();
    }
    return outputDate;
}

 

Mais ceci n'est qu'une solution de contournement d'une mauvaise utilisation des dates. Car, si je comprends bien en relisant depuis le début de ce fil de discussion, les dates que tu manipules proviennent de ta base de données. Et stocker en bdd une date sous forme de chaine de caractères est, AMHA, une TRES mauvaise idée. Il faut manipuler une date avec le type qui lui correspond (Date en Java, Integer avec SQLite) et s'abtraire ainsi de toute dépendance à une langue, une timezone ou tout formattage. Et la conversion de cette date en chaine de caractère ne devant se faire que lorsque c'est nécessaire, typiquement lorsqu'il faut présenter cette information à l'utilisateur.

  • Like 1
Lien vers le commentaire
Partager sur d’autres sites

Merci Chpil, j'avais déjà pensé à cette option qu'est de convertir ma date en Integer avant de la stocker dans ma base de données SQLite, et si tu dis que c'est la meilleure solution, je pense repartir sur cette option afin de ne plus être embêté par ce problème à l'avenir.

En revanche, comme la date que je récupère du fichier .plist a ce format : "2012-06-05T06:00:00Z", est-ce que :
- je peux procéder à une conversion avec SimpleDateFormat vers un Integer ?
- mon format de conversion serait alors celui du fichier (2012-06-05T06:00:00Z) ou celui de la machine (Tue Jun 05 06:00:00 UTC+00:00 2012) ?

 

J'avoue que j'ai encore du mal à comprendre ces différences d'interprétation entre les machines...

Lien vers le commentaire
Partager sur d’autres sites

SimpleDateFormat te permettra de faire une conversion d'une chaine de caractères en un objet Date, pas un entier. Ensuite, à partir de cet objet date, tu peux récupérer un entier (plus exactement un long, via getTime) que tu pourras ensuite stocker dans ta base.

Pour ce qui est du pattern de conversion, il faut que tu utilises celui qui correspond au format que as en entrée à parser. Si ta date dans le fichier a le format "2012-06-05T06:00:00Z", il faut que le format utilisé corresponde ...

  • Like 1
Lien vers le commentaire
Partager sur d’autres sites

Je comprends, mais c'est bien le problème que j'ai depuis le début, et en faisant ce test rapide, je vois que la date est déjà interprétée et ça ne passe pas partout.

Exemple de conversion :

// Fonctionne
String catalog_date = "2012-06-05T06:00:00Z";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH);
Date catalog_date_format = sdf.parse(catalog_date);
catalog_date_time = catalog_date_format.getTime();

CONSOLE : catalog_date = 2012-06-05T06:00:00Z
// Ne fonctionne pas
String catalog_date = str.objectForKey("Date").toString(); // On dirait que ma date est déjà convertie ici, car quand je l'affiche dans le Log, le format est différent...
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH);
Date catalog_date_format = sdf.parse(catalog_date);
long catalog_date_time = catalog_date_format.getTime();

CONSOLE : catalog_date = Mon Sep 01 11:07:20 UTC+00:00 2014

 
Et c'est cette interprétation aléatoire qui fait que je n'arrive pas à faire fonctionner les dates sur tous les appareils, car certains affichent des formats de TimeZone complètement différents (UTC, UTC+00:00, CET, CEST, etc.).

 

Je me demande du coup si ça vient d'Android ou de la bibliothèque dd-plist qui interprète la date... Si c'est le deuxième cas, je pense que je vais ouvrir un thread sur leur Google Group vu que je ne trouve pas l'info en cherchant sur Google. :/

Modifié par jok
Lien vers le commentaire
Partager sur d’autres sites

Effectivement, ça ne peut pas marcher si la date que tu récupères sous forme de chaîne de caractères n'a pas le même format à tous les coups. Très clairement, le problème est plutôt lié à la bibliothèque que tu utilises. A voir de ce côté là

  • Like 1
Lien vers le commentaire
Partager sur d’autres sites

Bonjour,
 
Je tiens à faire suite à mon soucis et à donner une solution au cas où certains auraient le même problème. De ce que j'ai pu remarquer, la bibliothèque dd-plist parse la date automatiquement au format de la tablette, malgré le format de date du fichier .plist.
 
Par exemple, dans mon fichier .plist, je récupère une date qui a ce format :

<date>2014-09-01T11:07:20Z</date>

Pour cela, je devrais normalement utiliser le code suivant (c'est ce que m'a conseillé un développeur de la bibliothèque) :

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
NSDate date = (NSDate)monDictionary.get("maBaliseDate");
string dateString = sdf.format(date);

Mais ce code produit une erreur de conversion, puisque ma variable "date" parait déjà formatée de la manière suivante dans mon Log :

Mon Sep 01 11:07:20 UTC+00:00 2014

Pour éviter donc d'avoir les problèmes de TimeZone que j'ai eu plus haut, j'ai réussi à récupérer la date en milli-secondes et à la stocker ainsi dans ma base de données en INTEGER (merci pour cette astuce Chpil). Voici comment procéder :

NSDate date = (NSDate)monDictionary.get("maBaliseDate");
long millis = date.getDate().getTime();

Ainsi, on peut par la suite formater la date avec un SimpleDateFormat sans avoir à prendre en compte les contraintes de chaque appareil, en l'occurrence la TimeZone dans mon cas.

Modifié par jok
Lien vers le commentaire
Partager sur d’autres sites

Rejoignez la conversation

Vous pouvez poster maintenant et vous enregistrez plus tard. Si vous avez un compte, connectez-vous maintenant pour poster.

Invité
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Répondre à ce sujet…

×   Collé en tant que texte enrichi.   Coller en tant que texte brut à la place

  Seulement 75 émoticônes maximum sont autorisées.

×   Votre lien a été automatiquement intégré.   Afficher plutôt comme un lien

×   Votre contenu précédent a été rétabli.   Vider l’éditeur

×   Vous ne pouvez pas directement coller des images. Envoyez-les depuis votre ordinateur ou insérez-les depuis une URL.

×
×
  • Créer...