You can use a function to check whether dates are valid by converting them to a string and back and add this to a CHECK
constraint to your date columns to ensure all dates are valid.
However, you should not need to do this as you should be mandating that arbitrary code is not executed on your systems and all the application code should include input validation so that only sanitized values are inserted into the database.
An example:
Oracle Setup:
CREATE TABLE Dates (
d DATE
);
CREATE FUNCTION isValidDate( dt IN DATE ) RETURN NUMBER
IS
d DATE;
BEGIN
d := TO_DATE( TO_CHAR( dt, 'fxYYYY-MM-DD HH24:MI:SS' ), 'fxYYYY-MM-DD HH24:MI:SS' );
RETURN 1;
EXCEPTION
WHEN OTHERS THEN
RETURN 0;
END;
Insert Dates:
declare
d DATE;
FUNCTION createUnvalidatedDate(
centuries INT := 0,
years INT := 0,
months INT := 0,
days INT := 0,
hours INT := 0,
minutes INT := 0,
seconds INT := 0
) RETURN DATE
IS
dt DATE;
hex_string CHAR(14);
BEGIN
hex_string := LPAD( TO_CHAR( centuries + 100, 'fmXX' ), 2, '0' )
|| LPAD( TO_CHAR( years + 100, 'fmXX' ), 2, '0' )
|| LPAD( TO_CHAR( months, 'fmXX' ), 2, '0' )
|| LPAD( TO_CHAR( days, 'fmXX' ), 2, '0' )
|| LPAD( TO_CHAR( hours + 1, 'fmXX' ), 2, '0' )
|| LPAD( TO_CHAR( minutes + 1, 'fmXX' ), 2, '0' )
|| LPAD( TO_CHAR( seconds + 1, 'fmXX' ), 2, '0' );
dbms_stats.convert_raw_value(hextoraw(hex_string), dt);
RETURN dt;
END;
begin
d := createUnvalidatedDate( 19, 0, 5, 127, 126, 118, 87 );
INSERT INTO Dates ( d ) VALUES ( d );
d := createUnvalidatedDate( 0, 0, 0, 0, 0, 0, 0 );
INSERT INTO Dates ( d ) VALUES ( d );
d := createUnvalidatedDate( 20, 19, 6, 24, 10, 28, 30 );
INSERT INTO Dates ( d ) VALUES ( d );
end;
/
Check Validity:
SELECT d, isValidDate( d ) AS valid
FROM Dates;
Outputs:
D | VALID
:-------------------- | ----:
1900-5-127T126:118:87 | 0
0-0-0T0:0:0 | 0
2019-6-24T10:28:30 | 1
Which shows that the first two values are invalid and the last one is a valid date.
db<>fiddle here