Hvis du har en god idé om alle de mulige datoformater, kan det være lettere at bruge brute force:
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;
/
Vær opmærksom på, at moderne versioner af Oracle er ret tilgivende med datokonvertering. Denne funktion håndterede datoer i formater, der ikke er på listen, med nogle interessante konsekvenser:
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>
Hvilket demonstrerer grænserne for automatiseret datarensning i lyset af slappe dataintegritetsregler. Syndens løn er korrupte data.
@AlexPoole rejser spørgsmålet om at bruge 'RR'
format. Dette element i datomasken blev introduceret som en Y2K kludge. Det er ret deprimerende, at vi stadig diskuterer det næsten to årtier inde i det nye årtusind.
Under alle omstændigheder er problemet dette. Hvis vi caster denne streng '161225'
til en dato, hvilket århundrede har den? Nå, 'yymmdd'
vil give 2016-12-15
. Fair nok, men hvad med '991225'
? Hvor sandsynligt er det, at den dato, vi virkelig ønsker, er 2099-12-15
? Det er her 'RR'
format kommer i spil. Grundlæggende angiver det århundredet som standard:tallene 00-49 er standard til 20, 50-99 som standard til 19. Dette vindue blev bestemt af Y2K-problemet:i 2000 var det mere sandsynligt, at '98
henvist til den seneste fortid end den nærmeste fremtid, og lignende logik anvendt på '02
. Derfor halvvejs i 1950. Bemærk, at dette er et fast punkt ikke et skydevindue. Efterhånden som vi bevæger os længere fra år 2000, jo mindre nyttigt bliver det omdrejningspunkt. Få mere at vide.
Uanset hvad, det vigtigste er, at 'RRRR' ikke spiller godt sammen med andre datoformater:to_date('501212', 'rrrrmmdd') hurls
ora-01843:ikke en gyldig måned. So, use
'RR'and test for it before using
'ÅÅÅÅ'. Så min reviderede funktion (med lidt oprydning) ser således ud:
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;
/
Nøglepunktet forbliver:Der er en grænse for, hvor smart vi kan lave denne funktion, når det kommer til fortolkning af datoer, så sørg for, at du leder med den bedste pasform. Hvis du synes, at de fleste af dine datesnore passer til dag-måned-år, så sæt det først; du vil stadig få nogle forkerte afstøbninger, men mindre end hvis du leder med år-måned-dag.