Prendre un thé
Tapoter des doights
Monsieur fantôme
Quelle heure est-il ?
BazinGa's Tips & tuto IT
BazinGa's - Tips & tuto IT

UltimateDateDetector – Détectez n’importe quelle date

Voici une petite fonction assez pratique. Qui n’a pas été embêter par une colonne au format texte et contenant des dates impossibles à formater correctement en raison du manque de structuration de la donnée ? Voici « enfin » une fonction vous permettant de nettoyer tout ça.

La sortie est au format texte, il faudra donc typer la données par la suite.
Les variables au début de définition de la fonction permettent de connaitre les séparateurs supportés.

Voici un tableau avec quelques exemples (dont un seul ne fonctionne pas, saurez vous le trouver ?) :

Valeur initialeValeur finaleCommentaire
2020/03/012020-03-01 00:00:00
2020/04/02 à 15h332020-04-02 15:33:00Les heures sont détectées
le 03/05/20202020-05-03 00:00:00Le texte ne pose pas de problème
06/07/2020, 12h152020-07-06 12:15:00Les virgules sont autorisées
4/08/20202020-08-04 00:00:00Pas besoin de 0 en début de nombre
07/9/2020,12h2020-09-07 12:00:00
09//08/20202020-08-09 00:00:00Les erreurs sont automatiquement corrigées
09/08/ 20202020-08-09 00:00:00
05/15/20202020-05-15 00:00:00Les dates américaines ne posent pas de problèmes
05/15 //20202020-05-15 00:00:00
17/102/20202020-01-01 00:00:00Erreur non identifiable : seul cas de date non reconnue
18/03/192019-03-18 00:00:00Les dates à deux chiffres sont reconnues (l’année 30 fait la limite : 2029 / 1930)
18/03/451945-03-18 00:00:00
45/03/181945-03-18 00:00:00Les dates à deux chiffres dans l’autre sens sont aussi détectées
10.10 2020 12/42-122020-10-10 12:42:12Séparateurs : point, espace, slash, tiret et divers textes
201210112012-10-11 00:00:00Identifié par défaut comme aaaammjj : attention aux dates américaines non reconnues
202010102020-10-10 00:00:00
202120202021-01-01 00:00:00
201220102010-12-20 00:00:00Identifié comme jjmmaaaa car l’inverse aurait impliqué un 20ème mois
101020202020-10-10 00:00:00
20202020-01-01 00:00:00L’année est complétée avec une date par défaut
11 novembre 20202020-11-11 00:00:00Les mois textuels sont supportés (accentués ou non)
Aout 20182018-08-01 00:00:00Le numéro du jour n’est pas obligatoire
Mai 451945-05-01 00:00:00L’année peut être sur deux chiffres
le 12 décembre1900-12-12 00:00:00Une année par défaut est appliquée si elle n’est pas détectée
j’arrive le 22 décembre 2020, 15h2020-12-22 15:00:00Les phrases sont supportées
le 6 octobre 2020 à 6h272020-10-13 06:27:00
Je m’appelle Arthur, j’ai 3 ans et je suis né le 5 juillet 1964 à 8h321964-07-05 08:32:00La date est détectée malgré la présence d’un autre nombre
july 14, 20202020-07-14 00:00:00Les dates anglaises sont supportées
maybe the 15 june 2020 @ 122020-06-15 12:00:00L’heure est détectée ici aussi
maybe the 16 august 2020 at 12 o’clock 15 minutes2020-08-16 12:15:00Le o’clock est également supporté
maybe the 16th august 2020 at 12 o’clock2020-08-16 12:00:00

Vous trouverez également une requête l’utilisant et vous montrant les performance de celle-ci :

SELECT 
	column1 AS "Valeur initiale",
	public.ab_UltimateDateDetector(column1,'null','',0) AS "Valeur finale",
	column2 AS "Commentaire"
FROM 
	(
		VALUES 
			('2020/03/01', ''),
			('2020/04/02 à 15h33', 'Les heures sont détectées'),
			('le 03/05/2020', 'Le texte ne pose pas de problème'),
			('06/07/2020, 12h15', 'Les virgules sont autorisées'),
			('4/08/2020', 'Pas besoin de 0 en début de nombre'),
			('07/9/2020,12h', ''),
			('09//08/2020', 'Les erreurs sont automatiquement corrigées'),
			('09/08/ 2020', ''),
			('05/15/2020', 'Les dates américaines ne posent pas de problèmes'),
			('05/15 //2020', ''),
			('17/102/2020', 'Erreur non identifiable : seul cas de date non reconnue'),
			('18/03/19', 'Les dates à deux chiffres sont reconnues (l''année 30 fait la limite : 2029 / 1930)'),
			('18/03/45', ''),
			('45/03/18', 'Les dates à deux chiffres dans l''autre sens sont aussi détectées'),
			('01-sept-18', 'Les dates à deux chiffres avec mois en lettre sont détectées'),
			('10.10 2020 12/42-12', 'Séparateurs : point, espace, slash, tiret et divers textes'),
			('20121011', 'Identifié par défaut comme aaaammjj : attention aux dates américaines non reconnues'),
			('20201010', ''),
			('20212020', ''),
			('20122010', 'Identifié comme jjmmaaaa car l''inverse aurait impliqué un 20ème mois'),
			('10102020', ''),
			('2020', 'L''année est complétée avec une date par défaut'),
			('11 novembre 2020', 'Les mois textuels sont supportés (accentués ou non)'),
			('Aout 2018', 'Le numéro du jour n''est pas obligatoire'),
			('Mai 45', 'L''année peut être sur deux chiffres'),
			('le 12 décembre', 'Une année par défaut est appliquée si elle n''est pas détectée'),
			('j''arrive le 22 décembre 2020, 15h', 'Les phrases sont supportées'),
			('le 6 octobre 2020 à 6h27', ''),
			('Je m''appelle Arthur, j''ai 3 ans et je suis né le 5 juillet 1964 à 8h32', 'La date est détectée malgré la présence d''un autre nombre'),
			('july 14, 2020', 'Les dates anglaises sont supportées'),
			('maybe the 15 june 2020 @ 12', 'L''heure est détectée ici aussi'),
			('maybe the 16 august 2020 at 12 o''clock 15 minutes', 'Le o''clock est également supporté'),
			('maybe the 16th august 2020 at 12 o''clock', '')
	) AS valeur
;
-- Fonction ab_UltimateDateDetector
CREATE OR REPLACE FUNCTION public.ab_UltimateDateDetector(date_to_format TEXT, output_format TEXT = null, flag TEXT = null, verbosity int = null)
RETURNS TEXT AS
$corps$

-- Auteur : Arthur Bazin - https://www.arthurbazin.com
-- Description
-- Cette fonction permet de détecter tout type de date et les retourne au format text suivant : aaaa-mm-jj hh:mm:ss.

-- Paramètres :
--		date_to_format : la date à formater
--		output_format : en cas de non correspondance, quelle valeur sortir :
--			null (défaut) = NULL,
--			empty = '',
--			same = valeur initiale
--		flag : restriction sur les formats à détecter (pour accélérer la fonction)
--		Tous les drapeaux peuvent être combinés pour rechercher plusieurs formats :
--			Type : (peuvent être combinés) ('' = 'td')
--				t : date avec heure
--				d : date sans heure
--			Format : (peuvent être combinés) ('' = 'IFEUT')
--				I : format ISO uniquement (2020/12/25)
--				F : format FR uniquement (25/12/2020)
--				E : format ENG uniquement (december 25th, 2020)
--				U : format US uniquement (2020/25/12 ou 12/25/2020)
--				T : format mois textuel (1er janvier 2020) (n''inclut pas les formats ENG)
--		verbosity : Niveau de verbosité de la fonction dans la sortie de la BDD (notice)
--			De 0 (défaut) à 3

	DECLARE
		-- Flag des tests
		flag_type TEXT := '';
		flag_format TEXT := '';

		-- Boucle d'expression régulière
		liste_regex record;

		-- Récupération regex
		rxm text[];

		-- Formatage date
			-- Suffixes
				-- Année
				suf_a text := 'années|année|ans|an|years|year|y| |\/|-|\.' ;
				-- Mois
				suf_m text := 'mois|month|m| |\/|-|\.' ;
				-- Jour
				suf_j text := 'jours|jour|j|days|day|d|st|nd|rd|th| |\/|-|\.' ;
				-- Heure
				suf_h text := 'heures|heure|h|ours|our|oclock|o''clock|o| |\/|-|:|\.' ;
				-- Minute
				suf_min text := 'minutes|minute|min|m| |\/|-|:|\.' ;
				-- Seconde
				suf_sec text := 'secondes|seconde|seconds|second|sec|s| |\/|-|:|\.' ;
			-- Séparateur
				-- date/horaire
				sep_d_h text := '-| |a|à|@|at|,' ;
			-- Répétition
				-- Répétition minimale du motif
				rep_min text := '1' ;
				-- Répétition maximale du motif
				rep_max text := '4' ;
			-- Variantes
				-- Janvier
				vari_m_ja text[] := ARRAY ['janvier|janv|january|jan', '01'] ;
				-- Février
				vari_m_fev text[] := ARRAY ['février|fevrier|fév|fev|february|feb', '02'] ;
				-- Mars
				vari_m_ma text[] := ARRAY ['mars|march|mar', '03'] ;
				-- Avril
				vari_m_av text[] := ARRAY ['avril|avr|av|april|apr|ap', '04'] ;
				-- Mai
				vari_m_mai text[] := ARRAY ['mai|may', '05'] ;
				-- Juin
				vari_m_juin text[] := ARRAY ['juin|june|jun', '06'] ;
				-- Juillet
				vari_m_juil text[] := ARRAY ['juillet|july|jul', '07'] ;
				-- Aout
				vari_m_aout text[] := ARRAY ['aout|août|aou|august|aug|au', '08'] ;
				-- Septembre
				vari_m_sept text[] := ARRAY ['septembre|september|sept|sep', '09'] ;
				-- Octobre
				vari_m_oct text[] := ARRAY ['octobre|october|oct', '10'] ;
				-- Novembre
				vari_m_nov text[] := ARRAY ['novembre|november|nov', '11'] ;
				-- Décembre
				vari_m_dec text[] := ARRAY ['decembre|décembre|december|dec', '12'] ;
			-- REGEX
				-- Année
				re_a text := '([0-2][0-9][0-9][0-9])(?: )*(?:' || suf_a || '){' || rep_min || ',' || rep_max || '}(?: )*' ;
				re_a_f text := '([0-2][0-9][0-9][0-9])(?: )*(?:' || suf_a || '){0,' || rep_max || '}(?: )*' ;
				re_a2 text := '([0-9][0-9])(?: )*(?:' || suf_a || '){' || rep_min || ',' || rep_max || '}(?: )*' ;
				re_a2_f text := '([0-9][0-9])(?: )*(?:' || suf_a || '){0,' || rep_max || '}(?: )*' ;
				-- Mois
				re_m text := '(0[1-9]|1[0-2]|[1-9])(?: )*(?:' || suf_m || '){' || rep_min || ',' || rep_max || '}(?: )*' ;
				re_m_f text := '(0[1-9]|1[0-2]|[1-9])(?: )*(?:' || suf_m || '){0,' || rep_max || '}(?: )*' ;
				-- Mois texte
				re_m_txt TEXT := '(' || vari_m_ja[1] || '|' || vari_m_fev[1] || '|' || vari_m_ma[1] || '|' || vari_m_av[1] || '|' || vari_m_mai[1] || '|' || vari_m_juin[1] || '|' || vari_m_juil[1] || '|' || vari_m_aout[1] || '|' || vari_m_sept[1] || '|' || vari_m_oct[1] || '|' || vari_m_nov[1] || '|' || vari_m_dec[1] || ')';
				-- Jour
				re_j text := '(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[1-9])(?: )*(?:' || suf_j || '){' || rep_min || ',' || rep_max || '}(?: )*' ;
				re_j_f text := '(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[1-9])(?: )*(?:' || suf_j || '){0,' || rep_max || '}(?: )*' ;
				re_j2 text := '(0[1-9]|1[0-9]|2[0-9]|3[0-1])(?: )*(?:' || suf_j || '){' || rep_min || ',' || rep_max || '}(?: )*' ;
				-- Heure
				re_h text := '(0[1-9]|1[0-9]|2[0-3]|[0-9]) *(?:' || suf_h || '){' || rep_min || ',' || rep_max || '}' ;
				re_h_f text := '(0[1-9]|1[0-9]|2[0-3]|[0-9]) *(?:' || suf_h || '){0,' || rep_max || '}' ;
				-- Minute
				re_min text := '([0-5][0-9]|[0-9])(?:' || suf_min || '){' || rep_min || ',' || rep_max || '}' ;
				re_min_f text := '([0-5][0-9]|[0-9])(?:' || suf_min || '){0,' || rep_max || '}' ;
				-- Seconde
				re_sec text := '([0-5][0-9]|[0-9])(?:' || suf_sec || '){0,' || rep_max || '}' ;
				--Séparateur date/horaire
				re_sep text := '(?: )*(?:' || sep_d_h || '){' || rep_min || ',' || rep_max || '}(?: )*' ;

		-- Valeurs finales
			-- Intermédiaires (valeur par défaut)
				-- Année
				fin_annee text := '1900' ;
				-- Mois
				fin_mois text := '01' ;
				-- Jour
				fin_jour text := '01' ;
				-- Heure
				fin_heure text := '00' ;
				-- Minute
				fin_min text := '00' ;
				-- Seconde
				fin_sec text := '00' ;

			-- Sortie
			formated_date TEXT;


	BEGIN

		-- Message d'information
		IF verbosity >= 1 THEN
			RAISE NOTICE USING MESSAGE =
				chr(10) ||
				$a$- - - - - - - - - - - - - - - - - - - - - - -$a$ || chr(10) ||
				$b$Démarrage traitement $b$ || chr(10) || chr(10)
			;
		END IF;



		-- Gestion paramètres
		IF output_format IS NULL OR output_format = ''
			THEN output_format = 'null';
		END IF;

		IF flag IS NULL OR flag = ''
			THEN flag = 'tdIFEUT';
		END IF;

		IF verbosity IS NULL
			THEN verbosity = 0;
		END IF;


		-- Traitement du paramètre flag
		IF flag LIKE '%t%' THEN flag_type = flag_type || 't'; END IF;
		IF flag LIKE '%d%' THEN flag_type = flag_type || 'd'; END IF;
		IF flag_type = '' THEN flag_type = 'dt'; END IF;
		IF flag LIKE '%I%' THEN flag_format = flag_format || 'I'; END IF;
		IF flag LIKE '%F%' THEN flag_format = flag_format || 'F'; END IF;
		IF flag LIKE '%E%' THEN flag_format = flag_format || 'E'; END IF;
		IF flag LIKE '%U%' THEN flag_format = flag_format || 'U'; END IF;
		IF flag LIKE '%T%' THEN flag_format = flag_format || 'T'; END IF;
		IF flag_format = '' THEN flag_format = 'IFEUT'; END IF;



		-- Message d'information
		IF verbosity >= 3 THEN
			RAISE NOTICE USING MESSAGE =
				$a$Paramètres :$a$ || chr(10) ||
				$b$	output_format : $b$ || output_format || chr(10) ||
				$c$	flag : $c$ || flag || $d$ - flag_type : $d$ || flag_type || $e$ - flag_format : $e$ || flag_format || chr(10) ||
				$f$	verbosity : $f$ || verbosity::text || chr(10) || chr(10)
			;
		END IF;



		-- Message d'information
		IF verbosity >= 1 THEN
			RAISE NOTICE USING MESSAGE = $a$Valeur traitée : '$a$ || date_to_format::TEXT || $b$'$b$ || chr(10)
			;
		END IF;

		-- Pour chaque motif REGEX possible
		-- Chaque élément est composé de :
		--		Une description du motif
		--		Un motif REGEX
		--		L'ordre de récupération des valeurs
		--		Les flags associés
		FOR liste_regex IN (
				SELECT
					column1 AS exemple,
					column2 AS regex_recherche,
					column3 AS ordre_valeur,
					column4 AS flag
				FROM
					(
						VALUES
							(
								'2020/01/01 23:59:59',
								re_a || re_m || re_j_f || re_sep || re_h || re_min || re_sec,
								ARRAY['annee','mois','jour','heure','min','sec'],
								'tI'
							),
							(
								'2020/21/01 23:59:59',
								re_a || re_j || re_m_f || re_sep || re_h || re_min || re_sec,
								ARRAY['annee','jour','mois','heure','min','sec'],
								'tU'
							),
							(
								'01/01/2020 23:59:59',
								re_j || re_m || re_a_f || re_sep || re_h || re_min || re_sec,
								ARRAY['jour','mois','annee','heure','min','sec'],
								'tF'
							),
							(
								'01/21/2020 23:59:59',
								re_m || re_j || re_a_f || re_sep || re_h || re_min || re_sec,
								ARRAY['mois','jour','annee','heure','min','sec'],
								'tU'
							),
							(
								'2020/01/01 23:59',
								re_a || re_m || re_j_f || re_sep || re_h || re_min_f,
								ARRAY['annee','mois','jour','heure','min'],
								'tI'
							),
							(
								'2020/21/01 23:59',
								re_a || re_j || re_m_f || re_sep || re_h || re_min_f,
								ARRAY['annee','jour','mois','heure','min'],
								'tU'
							),
							(
								'01/01/2020 23:59',
								re_j || re_m || re_a_f || re_sep || re_h || re_min_f,
								ARRAY['jour','mois','annee','heure','min'],
								'tF'
							),
							(
								'01/21/2020 23:59',
								re_m || re_j || re_a_f || re_sep || re_h || re_min_f,
								ARRAY['mois','jour','annee','heure','min'],
								'tU'
							),
							(
								'2020/01/01 23',
								re_a || re_m || re_j_f || re_sep || re_h_f,
								ARRAY['annee','mois','jour','heure'],
								'tI'
							),
							(
								'2020/21/01 23',
								re_a || re_j || re_j_f || re_sep || re_h_f,
								ARRAY['annee','jour','mois','heure'],
								'tU'
							),
							(
								'01/01/2020 23',
								re_j || re_m || re_a_f || re_sep || re_h_f,
								ARRAY['jour','mois','annee','heure'],
								'tF'
							),
							(
								'01/21/2020 23',
								re_m || re_j || re_a_f || re_sep || re_h_f,
								ARRAY['mois','jour','annee','heure'],
								'tU'
							),
							(
								'2020/01/01',
								re_a || re_m || re_j_f,
								ARRAY['annee','mois','jour'],
								'dI'
							),
							(
								'2020/21/01',
								re_a || re_j || re_m_f,
								ARRAY['mois','jour','annee'],
								'dU'
							),
							(
								'01/01/2020',
								re_j || re_m || re_a_f,
								ARRAY['jour','mois','annee'],
								'dF'
							),
							(
								'01/21/2020',
								re_m || re_j || re_a_f,
								ARRAY['mois','jour','annee'],
								'dU'
							),
							(
								'01/01/45',
								re_j2 || re_m || re_a2_f,
								ARRAY['jour','mois','annee'],
								'dF'
							),
							(
								'45/01/01',
								re_a2 || re_m || re_j_f,
								ARRAY['annee','mois','jour'],
								'dF'
							),
							(
								'01-sept-45',
								re_j2 || re_m_txt || '(?:' || suf_m || '){' || rep_min || ',' || rep_max || '}(?: )*' || re_a2_f,
								ARRAY['jour','mois','annee'],
								'dF'
							),
							(
								'20200101',
								'([0-2][0-9][0-9][0-9])(0[1-9]|1[0-2])(0[1-9]|1[0-9]|2[0-9]|3[0-1])',
								ARRAY['annee','mois','jour'],
								'dI'
							),
							(
								'01012020',
								'(0[1-9]|1[0-9]|2[0-9]|3[0-1])(0[1-9]|1[0-2])([0-2][0-9][0-9][0-9])',
								ARRAY['jour','mois','annee'],
								'dF'
							),
							(
								'20200101000000',
								'([0-2][0-9][0-9][0-9])(0[1-9]|1[0-2])(0[1-9]|1[0-9]|2[0-9]|3[0-1])(0[1-9]|1[0-9]|2[0-3])([0-5][0-9])([0-5][0-9])',
								ARRAY['annee','mois','jour','heure','min','sec'],
								'tI'
							),
							(
								'01012020000000',
								'(0[1-9]|1[0-9]|2[0-9]|3[0-1])(0[1-9]|1[0-2])([0-2][0-9][0-9][0-9])(0[1-9]|1[0-9]|2[0-3])([0-5][0-9])([0-5][0-9])',
								ARRAY['jour','mois','annee','heure','min','sec'],
								'tF'
							),
							(
								'1 janvier 2020 à 15h30m12s',
								'(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[1-9])' || '(?: |st|nd|rd|th)*' || re_m_txt || '(?: )*' || '([0-2][0-9][0-9][0-9])' || re_sep || re_h || re_min || re_sec,
								ARRAY['jour','mois','annee','heure', 'min', 'sec'],
								'tT'
							),
							(
								'1 janvier 2020 à 15h30m',
								'(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[1-9])' || '(?: |st|nd|rd|th)*' || re_m_txt || '(?: )*' || '([0-2][0-9][0-9][0-9])' || re_sep || re_h || re_min_f,
								ARRAY['jour','mois','annee','heure', 'min'],
								'tT'
							),
							(
								'1 janvier 2020 à 15h',
								'(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[1-9])' || '(?: |st|nd|rd|th)*' || re_m_txt || '(?: )*' || '([0-2][0-9][0-9][0-9])' || re_sep || re_h_f,
								ARRAY['jour','mois','annee','heure'],
								'tT'
							),
							(
								'1 janvier 2020',
								'(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[1-9])' || '(?: |st|nd|rd|th)*' || re_m_txt || '(?: )*' || '([0-2][0-9][0-9][0-9])',
								ARRAY['jour','mois','annee'],
								'dT'
							),
							(
								'1 janvier',
								'(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[1-9])' || '(?: |st|nd|rd|th)*' || re_m_txt,
								ARRAY['jour','mois'],
								'dT'
							),
							(
								'janvier 2020',
								re_m_txt || '(?: )*' || re_a_f,
								ARRAY['mois','annee'],
								'dT'
							),
							(
								'january 1st, 2020 at 12h30min18s',
								re_m_txt || '(?: )*' || '(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[1-9])' || '(?: |st|nd|rd|th)*' || '[, ]*' || '([0-2][0-9][0-9][0-9])' || re_sep || re_h || re_min || re_sec,
								ARRAY['mois','jour','annee','heure','min','sec'],
								'tE'
							),
							(
								'january 1st, 2020 at 12h30min',
								re_m_txt || '(?: )*' || '(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[1-9])' || '(?: |st|nd|rd|th)*' || '[, ]*' || '([0-2][0-9][0-9][0-9])' || re_sep || re_h || re_min_f,
								ARRAY['mois','jour','annee','heure','min'],
								'tE'
							),
							(
								'january 1st, 2020 at 12h',
								re_m_txt || '(?: )*' || '(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[1-9])' || '(?: |st|nd|rd|th)*' || '[, ]*' || '([0-2][0-9][0-9][0-9])' || re_sep || re_h_f,
								ARRAY['mois','jour','annee','heure'],
								'tE'
							),
							(
								'january 1st, 2020',
								re_m_txt || '(?: )*' || '(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[1-9])' || '(?: |st|nd|rd|th)*' || '[, ]*' || '([0-2][0-9][0-9][0-9])',
								ARRAY['mois','jour','annee'],
								'dE'
							),
							(
								'janvier 45',
								re_m_txt || '(?: )*' || re_a2_f,
								ARRAY['mois','annee'],
								'dT'
							),
							(
								'2020',
								'(?:.* )?' || re_a_f || '(?: .*)?',
								ARRAY['annee'],
								'dIFUET'
							)
					) AS valeur
				WHERE
					(regexp_split_to_array(column4, '')) && (regexp_split_to_array(flag_type, ''))
				AND
					(regexp_split_to_array(column4, '')) && (regexp_split_to_array(flag_format, ''))
			)

		-- Pour chaque élément de la liste des motifs REGEX possible
		LOOP

			-- On démarre une transaction pour capturer les erreurs
			BEGIN

				-- On récupère le résultat de la recherche REGEX
				rxm = regexp_matches(date_to_format, liste_regex.regex_recherche, 'i');

				-- Message d'information
				IF verbosity >= 3 THEN
					RAISE NOTICE USING MESSAGE =
						$a$Format testé : $a$ || liste_regex.exemple || chr(10) ||
						$b$	REGEX recherche : $b$ || liste_regex.regex_recherche
					;
				END IF;


				-- Si la recherche REGEX donne un résultat
				IF rxm IS NOT NULL THEN

					-- Message d'information
					IF verbosity >= 2 THEN
						RAISE NOTICE USING MESSAGE =
							chr(10) ||
							$a$Valeurs identifiées : $a$ || array_to_string(rxm,' | ') || chr(10) ||
							$b$	Ordre des valeurs : $b$ || array_to_string(liste_regex.ordre_valeur,' | ')
							;
					END IF;


					-- On boucle sur le nombre d'éléments retrouvés pour traiter chaque élément : année, mois, jour, heure, minute, seconde
					FOR i IN 1..array_length(rxm, 1) BY 1

					LOOP

						-- Si l'élément du tableau rxm existe
						IF rxm[i] IS NOT NULL THEN

							-- On défini l'élément comme étant "tel partie" de la date par rapport à la valeur ayant la même position dans le tableau liste_regex.ordre_valeur

							IF liste_regex.ordre_valeur[i] = 'annee' THEN

								-- Si l'année est sur 2 chiffres
								IF length(rxm[i]) = 2 THEN
									IF rxm[i]::integer > 29 THEN
										fin_annee = '19' || rxm[i]::TEXT;
									ELSE
										fin_annee = '20' || rxm[i]::TEXT;
									END IF;
								ELSE
									fin_annee = lpad(rxm[i]::text,4,'0');
								END IF;

							END IF;

							IF liste_regex.ordre_valeur[i] = 'mois' THEN
								-- Cas particulier des mois : ils peuvent être au format texte : on test donc chaque valeur posible pour récupérer le numéro du mois

								IF regexp_matches(rxm[i], '(' || vari_m_ja[1] || ')', 'i' ) IS NOT NULL THEN
									fin_mois = vari_m_ja[2];
								ELSIF regexp_matches(rxm[i], '(' || vari_m_fev[1] || ')', 'i' ) IS NOT NULL THEN
									fin_mois = vari_m_fev[2];
								ELSIF regexp_matches(rxm[i], '(' || vari_m_ma[1] || ')', 'i' ) IS NOT NULL THEN
									fin_mois = vari_m_ma[2];
								ELSIF regexp_matches(rxm[i], '(' || vari_m_av[1] || ')', 'i' ) IS NOT NULL THEN
									fin_mois = vari_m_av[2];
								ELSIF regexp_matches(rxm[i], '(' || vari_m_mai[1] || ')', 'i' ) IS NOT NULL THEN
									fin_mois = vari_m_mai[2];
								ELSIF regexp_matches(rxm[i], '(' || vari_m_juin[1] || ')', 'i' ) IS NOT NULL THEN
									fin_mois = vari_m_juin[2];
								ELSIF regexp_matches(rxm[i], '(' || vari_m_juil[1] || ')', 'i' ) IS NOT NULL THEN
									fin_mois = vari_m_juil[2];
								ELSIF regexp_matches(rxm[i], '(' || vari_m_aout[1] || ')', 'i' ) IS NOT NULL THEN
									fin_mois = vari_m_aout[2];
								ELSIF regexp_matches(rxm[i], '(' || vari_m_sept[1] || ')', 'i' ) IS NOT NULL THEN
									fin_mois = vari_m_sept[2];
								ELSIF regexp_matches(rxm[i], '(' || vari_m_oct[1] || ')', 'i' ) IS NOT NULL THEN
									fin_mois = vari_m_oct[2];
								ELSIF regexp_matches(rxm[i], '(' || vari_m_nov[1] || ')', 'i' ) IS NOT NULL THEN
									fin_mois = vari_m_nov[2];
								ELSIF regexp_matches(rxm[i], '(' || vari_m_dec[1] || ')', 'i' ) IS NOT NULL THEN
									fin_mois = vari_m_dec[2];
								ELSE
									fin_mois = lpad(rxm[i]::text,2,'0');
								END IF;
							END IF;

							IF liste_regex.ordre_valeur[i] = 'jour' THEN
								fin_jour = lpad(rxm[i]::text,2,'0');
							END IF;

							IF liste_regex.ordre_valeur[i] = 'heure' THEN
								fin_heure = lpad(rxm[i]::text,2,'0');
							END IF;

							IF liste_regex.ordre_valeur[i] = 'min' THEN
								fin_min = lpad(rxm[i]::text,2,'0');
							END IF;

							IF liste_regex.ordre_valeur[i] = 'sec' THEN
								fin_sec = lpad(rxm[i]::text,2,'0');
							END IF;

						END IF;

					END LOOP;

					-- La date est construite en assemblant les différents résultats
					formated_date = fin_annee || '-' || fin_mois || '-' || fin_jour || ' ' || fin_heure || ':' || fin_min || ':' || fin_sec;

					--RAISE NOTICE USING MESSAGE = formated_date;

					-- On sort de la boucle
					EXIT;

				END IF;

				-- On capture l'erreur si la recherche de REGEX à posé problème (surtout utile en debug)
				EXCEPTION WHEN OTHERS THEN

					RAISE NOTICE USING MESSAGE =
						chr(10) ||
						$a$		/!\ Erreur traitement /!\$a$ || chr(10) ||
						$b$		/!\ Code erreur : $b$ || SQLSTATE || $c$ - Message : $c$ || SQLERRM
					;
			END;

		END LOOP;


		-- Gestion de la valeur de sortie
		-- Si aucun résultat n'a été trouvé
		IF formated_date IS NULL THEN

			-- Message d'information
			IF verbosity >= 1 THEN
				RAISE NOTICE USING MESSAGE =
					chr(10) ||
					$a$Aucun motif de date identifié$a$
				;
			END IF;

			-- Le résultat est défini par rapport au paramètre "output_format"
			IF output_format = 'empty' THEN
				formated_date = '';
			ELSIF output_format = 'same' THEN
				formated_date = date_to_format;
			END IF;
		ELSE
			-- Message d'information
			IF verbosity >= 1 THEN
				RAISE NOTICE USING MESSAGE =
					chr(10) ||
					$a$Date extraite : $a$ || formated_date
				;
			END IF;
		END IF;

		-- Message d'information
		IF verbosity >= 1 THEN
			RAISE NOTICE USING MESSAGE =
				chr(10) ||
				$a$Fin du traitement $a$ || chr(10) ||
				$b$- - - - - - - - - - - - - - - - - - - - - - -$b$ || chr(10) ||
				chr(10)
			;
		END IF;

		-- Retour final
		RETURN formated_date;

	END

$corps$
LANGUAGE plpgsql
;


Cet article vous a plu ?

N'hésitez pas à le partager, il interessera surement certains de vos contacts.

Les thèmes suivants contiennent des articles en lien avec celui-ci, allez faire un tour :

BDDPostgreSQLProgrammationSQL datedatetimefonctionformatagetime

50%