#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: 1160
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: 1160
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
Hors ligne
#5 Tue 23 January 2018 19:32
- Nicolas Ribot
- Membre
- Lieu: Toulouse
- Date d'inscription: 9 Sep 2005
- Messages: 1554
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.
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: 1554
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: 1554
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