Nous utilisons des cookies pour vous garantir la meilleure expérience sur notre site. Si vous continuez à utiliser ce dernier, nous considèrerons que vous acceptez l'utilisation des cookies. J'ai compris ! ou En savoir plus !.
banniere

Le portail francophone de la géomatique


Toujours pas inscrit ? Mot de passe oublié ?
Nom d'utilisateur    Mot de passe              Toujours pas inscrit ?   Mot de passe oublié ?

Annonce

Printemps des cartes 2024

#1 Mon 22 January 2018 21:35

Lsam
Participant assidu
Date d'inscription: 27 Nov 2013
Messages: 157

[PostgreSQL] conversion d'une date française en ISO 8601

Bonjour,

J'ai une base de données PostgreSQL avec un champ de type texte contenant des dates "françaises" du type '15 Novembre 2017' et je voudrais les convertir en date du type 2017-11-15.

J'arrive bien à faire l'inverse :

Code:

=# set lc_time = 'fr_FR';

=# select to_char('2017-11-15'::date,'DD TMMonth YYYY');

     to_char      
------------------
 15 Novembre 2017

Mais impossible de faire l'inverse, à part en anglais :

Code:

=# show lc_time;
 lc_time 
---------
 fr_FR

=# select to_date('15 Novembre    2017','DD TMMonth YYYY');

ERREUR:  valeur « Novembre  » invalide pour « Month »
DÉTAIL : La valeur donnée ne correspond pas aux valeurs autorisées pour ce champ.

=# select to_date('15 November    2017','DD TMMonth YYYY');
  to_date   
------------
 2017-11-15

Je ne comprends pas pourquoi, ce n'est pas possible d'utiliser des dates françaises ?


LSam

Hors ligne

 

#2 Mon 22 January 2018 22:18

tumasgiu
Membre
Lieu: Ajaccio
Date d'inscription: 5 Jul 2010
Messages: 1132

Re: [PostgreSQL] conversion d'une date française en ISO 8601

Salut,

[edit]
j'ai lu trop rapidement votre question, ma première réponse ne faisait que
redire ce que vous savez déja, veuillez pardonnez.

Apparemment, c'est toujours dans la liste des choses à implémenter :

https://wiki.postgresql.org/wiki/Todo

Dernière modification par tumasgiu (Mon 22 January 2018 22:57)

Hors ligne

 

#3 Tue 23 January 2018 00:06

Lsam
Participant assidu
Date d'inscription: 27 Nov 2013
Messages: 157

Re: [PostgreSQL] conversion d'une date française en ISO 8601

Ok,

Effectivement : https://wiki.postgresql.org/wiki/Todo#C … Formatting

Je vais être obligé de traduire à la main à grands coups de case et replace, tant pis.

Merci pour l'info !

Hors ligne

 

#4 Tue 23 January 2018 10:35

tumasgiu
Membre
Lieu: Ajaccio
Date d'inscription: 5 Jul 2010
Messages: 1132

Re: [PostgreSQL] conversion d'une date française en ISO 8601

De rien.

Le mieux serait d'écrire une petite fonction,
et de la poster ici si vous en avez envie smile

Hors ligne

 

#5 Tue 23 January 2018 19:32

Nicolas Ribot
Membre
Lieu: Toulouse
Date d'inscription: 9 Sep 2005
Messages: 1536

Re: [PostgreSQL] conversion d'une date française en ISO 8601

Bonsoir,

Pourquoi des case ?
12 replace pour chaque mois, ca ne suffirait pas ?

Code:

with tmp as (
  values ('15 Novembre 2017'),
    ('05 Août 2016'),
    ('30 Juillet 2016')
) SELECT to_date(
    replace(
      replace(
        replace(column1, 'Novembre', 'November'),
        'Août', 'August'),
      'Juillet', 'July'),
      -- ...
    'DD Month YYYY')
from tmp;

Nico

Hors ligne

 

#6 Wed 24 January 2018 08:33

Lsam
Participant assidu
Date d'inscription: 27 Nov 2013
Messages: 157

Re: [PostgreSQL] conversion d'une date française en ISO 8601

Bonjour,

Oui c'est vrai mais je n'aime pas trop accumuler des replace à la suite, c'est plus difficile à lire pour moi. Je peaufine prochainement pour faire une petite fonction. wink

Merci à vous.

LSam

Dernière modification par Lsam (Wed 24 January 2018 08:33)

Hors ligne

 

#7 Mon 05 February 2018 12:08

Lsam
Participant assidu
Date d'inscription: 27 Nov 2013
Messages: 157

Re: [PostgreSQL] conversion d'une date française en ISO 8601

Bonjour,

Me revoici pour essayer d'écrire une fonction. C'est ma 1ère... j'ai pas mal cherché, mais je bute sur l'utilisation des tableaux. Soyez indulgents. ;-)

Voici ma fonction :

Code:

CREATE OR REPLACE FUNCTION correction_date(TEXT) 
RETURNS DATE
AS
$$
DECLARE
    date_ok date ;
    calendrier varchar[] := ARRAY[['janvier','january'],['février','february'],['mars','march'],['avril','april'],['mai','may'],['juin','june'],['juillet','july'],['août','august'],['septembre','september'],['octobre','october'],['novembre','november'],['décembre','december']] ;
    mois integer ;
    chaine text ;

BEGIN
---FOREACH mois IN ARRAY calendrier LOOP
FOR mois in 1..12 LOOP
    chaine := '^[0-9]{1,2} '||calendrier[mois][1]||' [0-9]{4}$'  ;
    CASE 
        WHEN $1 ~ chaine
            THEN date_ok = to_date(regexp_replace(lower($1), calendrier[mois][1], calendrier[mois][2]),'DD Month YYYY') ;
        ELSE date_ok = null ;
    END CASE ;
END LOOP ;

RETURN date_ok ;

END
$$ LANGUAGE plpgsql;

Le résultat est vide avec par exemple :

Code:

select correction_date('25 janvier 2014');
 correction_date 
-----------------
 
(1 ligne)

Je voudrais qu'une boucle examine chaque élément du tableau et effectue la recherche et remplacement de la valeur du mois par sa traduction anglaise. J'ai du mal à intégrer le tableau dans la boucle et dans mon expression régilière, et j'hésite entre l'utilisation de FOR...IN et de FOREACH...IN ARRAY...

Si une âme charitable pouvait m'aider à comprendre... merci ;-)

Merci

LSam

Dernière modification par Lsam (Mon 05 February 2018 12:08)

Hors ligne

 

#8 Mon 05 February 2018 12:54

Nicolas Ribot
Membre
Lieu: Toulouse
Date d'inscription: 9 Sep 2005
Messages: 1536

Re: [PostgreSQL] conversion d'une date française en ISO 8601

Bonjour,

Vous voulez vraiment passer par des tableaux pour cela ?

Une simple fn sql ne vous suffit pas ?

Code:

CREATE OR REPLACE FUNCTION correction_date(baddate TEXT)
  RETURNS DATE
AS
$$
SELECT to_date(
    replace(
        replace(
            replace(
                replace(
                    replace(
                        replace(
                            replace(
                                replace(
                                    replace(
                                        replace(
                                            replace(
                                                replace(lower(baddate), 'janvier', 'january'),
                                                'février', 'february'),
                                            'mars', 'march'),
                                        'avril', 'april'),
                                    'mai', 'may'),
                                'juin', 'june'),
                            'juillet', 'july'),
                        'août', 'august'),
                    'septembre', 'september'),
                'octobre', 'october'),
            'novembre', 'november'), 
        'décembre', 'december'),
    'DD Month YYYY')
$$
LANGUAGE sql;

select correction_date('25 janvier 2014');
select correction_date('31 DÉCEMBRE 2017');

avec éventuellement des cas pour mois avec accents.

Nicolas

Hors ligne

 

#9 Mon 05 February 2018 13:07

Nicolas Ribot
Membre
Lieu: Toulouse
Date d'inscription: 9 Sep 2005
Messages: 1536

Re: [PostgreSQL] conversion d'une date française en ISO 8601

Dans votre fonction, il faut faire un "RETURN date_ok;" qd vous avez trouvé la date. (THEN date_ok = ....)

Sinon la boucle passe au mois suivant. Votre fonction ne marche que pour le mois de décembre.

Nicolas

Hors ligne

 

#10 Mon 05 February 2018 14:48

Lsam
Participant assidu
Date d'inscription: 27 Nov 2013
Messages: 157

Re: [PostgreSQL] conversion d'une date française en ISO 8601

Merci Nicolas,

Pour les tableaux, c'était juste pour utiliser cette fonctionnalité que je trouve plus élégante dans mon cas (et c'est surtout pour apprendre au passage), même si je suis d'accord avec vous que j'aurais pu le régler, comme conseillé précédemment, par des replace.

Je réétudie le truc.

LSam

Hors ligne

 

#11 Mon 19 February 2018 15:41

Lsam
Participant assidu
Date d'inscription: 27 Nov 2013
Messages: 157

Re: [PostgreSQL] conversion d'une date française en ISO 8601

Bonjour,

J'ai avancé dans ma fonction de correction de date, qui va bien au-delà de ce que je souhaitais réaliser au début, puisque j'essaie de corriger toutes les dates saisies un peu n'importe comment dans un champ texte, y compris celles qui sont imprécises.

Mais du coup, je souhaiterais dans ma fonction ajouter un 2ème champ "Précision" qui serait rempli en fonction de l'incertitude de la valeur que je traite.

Par exemple :

- si la date à corriger est '21 mars 1985', ma fonction devrait renvoyer "Date" avec '1985-03-21' et "Précision" = 'jour'

- si la date à corriger est 'mars 1985', "Date" = '1985-03-01' et "Précision" = 'mois'

- si la date à corriger est 'été 1985', "Date" = '1985-05-01' et "Précision" = 'saison'

- et enfin si la date à corriger est '1985', "Date" = '1985-01-01' et "Précision" = 'année'

Comment je peux transcrire ça dans ma fonction, je suis un peu perdu dans la syntaxe des fonctions, notamment dès le début avec RETURNS ?

Voici ma fonction pour l'instant (désolé c'est imbuvable mais ça marche) :

Code:

CREATE OR REPLACE FUNCTION donnees.correction_date(TEXT,DATE) 
RETURNS DATE
AS
$$
DECLARE
    datearg text ;
    date_ok date ;
    calendrier varchar[] := ARRAY[['janvier','january'],['f.vrier','february'],['mars','march'],['avril','april'],['mai','may'],['juin','june'],['juillet','july'],['a..t','august'],['septembre','september'],['octobre','october'],['novembre','november'],['d.cembre','december']] ;
    mois integer ;
    extrdate text ; 
    correcdate text ;
    jjmmmmaaaa text ;
    jjmmaaaa text ;
    aaaammjj text ;
    mmmaaaa text ;
    mmaaaa text ;
    datesaisie date := $2 ;
    avanthier text ;
    hier text ;
    saisons text ;
    saison text ;

BEGIN

    datearg := lower(regexp_replace(regexp_replace($1,' {1,}',' ','g'),' {1,}$','')) ;
    avanthier := '.*avant( |\-)hier.*' ;
    hier := '.*hier.*' ;
    saisons := ARRAY['printemps','été','automne','hiver'] ;

--- si l'année ne figure pas en fin de colonne, on ajoute celle de la date de saisie
IF datearg ~ '.* {1,}[0-9]{2,}$'
    THEN datearg = datearg ;
    ELSE datearg = regexp_replace(datearg, '(.* {1,})[0-9]{2,}$','\1'||extract(year from $2)) ;
END IF ;

CASE
--- cas des dates relatives par rapport à la date de saisie
    WHEN datearg ~ avanthier
        THEN
            date_ok = datesaisie-2 ;
        RETURN date_ok ;
    WHEN datearg ~ hier
        THEN
            date_ok = datesaisie-1 ;
        RETURN date_ok ;
--- cas des heures avec omission de la date, a priori celle du jour de saisie
    WHEN datearg ~ '^[0-9]{1,2} {0,1}h$'
        THEN 
            date_ok = datesaisie ;
        RETURN date_ok ;
--- cas des années sans plus de précision
    WHEN datearg ~ '^[0-9]{4}$'
        THEN 
            date_ok = to_date(datearg||'-01-01','YYYY-MM-DD') ;
        RETURN date_ok ;
--- cas des saisons, avec indication de l'année
    WHEN string_to_array(lower(datearg),' ') && saisons
        THEN
            FOREACH saison SLICE 1 IN ARRAY saisons
            LOOP
            --- à finir
             ;
            END LOOP  ;
 
    ELSE
--- cas des dates avec au moins l'année et le mois
        FOR mois in 1..12 LOOP
            jjmmmmaaaa := '(^|.*)[0-9]{1,2} '||calendrier[mois][1]||' [0-9]{4}$'  ;
            jjmmaaaa := '(^|.*)[0-9]{1,2}(\.|\/|\-)[0]{0,1}'||mois||'(\.|\/|\-)[0-9]{4}$' ;
            aaaammjj := '^[0-9]{4}(\.|\/|\-)'||mois||'(\.|\/|\-)[0-9]{2}$' ;
            mmmaaaa := '(^|[^0-9]{0,})'||calendrier[mois][1]||' {0,}([0-9]{4})$' ;
            mmaaaa := '^[0-9]{1,2}(\/|\-|\.)[0-9]{4}$' ;
        
            CASE 
                WHEN datearg ~ jjmmmmaaaa
                    THEN 
                        extrdate := '(^|[^0-9]{1,}|.*au |.*le )([0-9]{1,2}) '||calendrier[mois][1]||' ([0-9]{4})$' ;
                        correcdate := '\2 '||calendrier[mois][2]||' \3' ;
                        date_ok = to_date(regexp_replace(datearg,extrdate, correcdate),'DD Month YYYY') ;
                    RETURN date_ok ;
                WHEN datearg ~ jjmmaaaa
                    THEN
                        extrdate := '(^|[^0-9]{1,}|.*au |.*le )([0-9]{1,2})(\.|\/|\-)[0]{0,1}'||mois||'(\.|\/|\-)([0-9]{4})$' ;
                        correcdate := '\2/'||mois||'/\5' ;
                        date_ok = to_date(regexp_replace(datearg,extrdate, correcdate),'DD/MM/YYYY') ;
                    RETURN date_ok ;
                WHEN datearg ~ mmaaaa
                    THEN
                        extrdate := '(0{0,1})'||mois||'(\.|\/|\-)([0-9]{4})$' ;
                        correcdate := '01/'||mois||'/\3' ;
                        date_ok = to_date(regexp_replace(datearg,extrdate, correcdate),'DD/MM/YYYY') ;
                    RETURN date_ok ;
                WHEN datearg ~ aaaammjj
                    THEN
                        extrdate := '^([0-9]{4})(\.|\/|\-)[0]{0,1}'||mois||'(\.|\/|\-)([0-9]{2})$' ;
                        correcdate := '\1-'||mois||'-\4' ;
                        date_ok = to_date(regexp_replace(datearg,extrdate, correcdate),'YYYY-MM-DD') ;
                    RETURN date_ok ;
                WHEN datearg ~ mmmaaaa
                    THEN
                        extrdate := '(^|.*[^0-9]{1,}) {0,}'||calendrier[mois][1]||' {0,}([0-9]{4})$' ;
                        correcdate := '\2-'||mois||'-01' ;
                        date_ok = to_date(regexp_replace(datearg,extrdate, correcdate),'YYYY-MM-DD') ;
                    RETURN date_ok ;
                    ELSE mois := mois+1 ;
                        IF mois > 12
                            THEN date_ok = null ;
                            RETURN date_ok ;
                        END IF ;
            END CASE ;
        END LOOP ;

END CASE ;

END
$$ LANGUAGE plpgsql ;

Dernière modification par Lsam (Mon 19 February 2018 15:43)

Hors ligne

 

Pied de page des forums

Powered by FluxBB