The same is not working correctly ...
Of course it is working correctly. The manual:
If the year format specification is less than four digits, e.g. YYY
,
and the supplied year is less than four digits, the year will be
adjusted to be nearest to the year 2020, e.g. 95
becomes 1995.
So, 70
becomes 1970, but 69
becomes 2069.
Oracle has different rules for the format specifier RR
, which does not exist in Postgres. Basically, the year will be adjusted to be nearest to the year 2000 (the nearest century to the current date):
Workaround
Encapsulate the functionality in a function that switches the century according to the year number in the string. Since Postgres allows function overloading, you can even use the same function name to_date()
with different parameter types. See:
According to the documentation above, Oracle wraps around at YY = '50' and this function is equivalent until 2049:
CREATE OR REPLACE FUNCTION to_date(varchar, text)
RETURNS date
LANGUAGE sql STABLE AS
$func$
SELECT CASE WHEN right($1, 2) > '49' THEN
to_date(left($1, -2) || '19' || right($1, 2), 'DD-MON-YYYY')
ELSE
to_date(left($1, -2) || '20' || right($1, 2), 'DD-MON-YYYY')
END
$func$;
Only STABLE
, not IMMUTABLE
, because to_date is only STABLE
. Else you disable function inlining.
I chose varchar
for the first parameter to be different from the original, which uses text
.
If the year number is > 49, the function adds the 20th century (with '19') else, the 21st into the date string before conversion. The second parameter is ignored.
Call:
SELECT to_date('25-JUN-53' , 'DD-MON-YY') AS original
, to_date('25-JUN-53'::varchar, 'DD-MON-YY') AS patched1
, to_date('25-JUN-53'::varchar, 'DD-MON-RR') AS patched2
, to_date('25-JUN-53'::varchar, 'FOO-BAR') AS patched3
Our custom function ignores the 2nd parameter anyway.
Result:
original | patched1 | patched2 | patched3
------------+------------+------------+------------
2053-06-25 | 1953-06-25 | 1953-06-25 | 1953-06-25
db<>fiddle here
Old sqlddle
You might make it more sophisticated to work beyond 2049 and take the second parameter into consideration ...
A word of warning: function overloading over basic functions is better done with care. If that stays in your system somebody might get surprising results later.
Better create that function in a special schema and set the search_path
selectively so it only gets used when appropriate. You can as well use text
as parameter type in this case:
CREATE SCHEMA specialfunc;
CREATE OR REPLACE FUNCTION specialfunc.to_date(text, text) AS ...
Then:
SET search_path = specialfunc, pg_catalog;
SELECT to_date('25-JUN-53', 'DD-MON-YY') AS patched;
Or use a temporary function. See: