Si vous avez une bonne idée de tous les formats de date possibles, il peut être plus simple d'utiliser la force brute :
create or replace function clean_date
( p_date_str in varchar2)
return date
is
l_dt_fmt_nt sys.dbms_debug_vc2coll := sys.dbms_debug_vc2coll
('DD-MON-YYYY', 'DD-MON-YY', 'DD-MM-YYYY', 'MM-DD-YYYY', 'YYYY-MM-DD'
, 'DD/MM/YYYY', 'MM/DD/YYYY', 'YYYY/MM/DD', 'DD/MM/YY', 'MM/DD/YY');
return_value date;
begin
for idx in l_dt_fmt_nt.first()..l_dt_fmt_nt.last()
loop
begin
return_value := to_date(p_date_str, l_dt_fmt_nt(idx));
exit;
exception
when others then null;
end;
end loop;
if return_value is null then
raise no_data_found;
end if;
return return_value;
exception
when no_data_found then
raise_application_error(-20000, p_date_str|| ' is unknown date format');
end clean_date;
/
Sachez que les versions modernes d'Oracle sont assez indulgentes avec la conversion de date. Cette fonction gérait les dates dans des formats qui ne sont pas dans la liste, avec des conséquences intéressantes :
SQL> select clean_date('20160817') from dual;
CLEAN_DAT
---------
17-AUG-16
SQL> select clean_date('160817') from dual;
CLEAN_DAT
---------
16-AUG-17
SQL>
Ce qui démontre les limites du nettoyage automatisé des données face à des règles d'intégrité des données laxistes. Le salaire du péché est une donnée corrompue.
@AlexPoole soulève la question de l'utilisation du 'RR'
format. Cet élément du masque de date a été introduit en tant que kludge Y2K. Il est plutôt déprimant que nous en parlions encore presque deux décennies après le début du nouveau millénaire.
Quoi qu'il en soit, le problème est le suivant. Si nous castons cette chaîne '161225'
à une date de quel siècle a-t-elle ? Eh bien, 'yymmdd'
donnera 2016-12-15
. D'accord, mais qu'en est-il de '991225'
? Quelle est la probabilité que la date que nous voulons vraiment soit 2099-12-15
? C'est là que le 'RR'
le format entre en jeu. Fondamentalement, il utilise par défaut le siècle :les numéros 00-49 par défaut sont 20, 50-99 par défaut sont 19. Cette fenêtre a été déterminée par le problème Y2K :en 2000, il était plus probable que '98
fait référence au passé récent plutôt qu'au futur proche, et une logique similaire s'applique à '02
. D'où le point à mi-chemin de 1950. Notez qu'il s'agit d'un point fixe pas une fenêtre coulissante. Plus nous nous éloignons de l'an 2000, moins ce point pivot devient utile. En savoir plus.
Quoi qu'il en soit, le point clé est que 'RRRR' ne fonctionne pas bien avec les autres formats de date :to_date('501212', 'rrrrmmdd') hurls
ora-01843 :pas un mois. So, use
'RR'and test for it before using
'AAAA''. Ma fonction révisée (avec quelques modifications) ressemble donc à ceci :
create or replace function clean_date
( p_date_str in varchar2)
return date
is
l_dt_fmt_nt sys.dbms_debug_vc2coll := sys.dbms_debug_vc2coll
('DD-MM-RR', 'MM-DD-RR', 'RR-MM-DD', 'RR-DD-MM'
, 'DD-MM-YYYY', 'MM-DD-YYYY', 'YYYY-MM-DD', 'YYYY-DD-MM');
return_value date;
begin
for idx in l_dt_fmt_nt.first()..l_dt_fmt_nt.last()
loop
begin
return_value := to_date(p_date_str, l_dt_fmt_nt(idx));
exit;
exception
when others then null;
end;
end loop;
if return_value is null then
raise no_data_found;
end if;
return return_value;
exception
when no_data_found then
raise_application_error(-20000, p_date_str|| ' is unknown date format');
end clean_date;
/
Le point clé demeure :il y a une limite à la façon dont nous pouvons rendre cette fonction intelligente lorsqu'il s'agit d'interpréter les dates, alors assurez-vous de diriger avec le meilleur ajustement. Si vous pensez que la plupart de vos chaînes de date correspondent à jour-mois-année, mettez cela en premier ; vous aurez toujours quelques mauvais lancers, mais moins que si vous menez avec année-mois-jour.