同样的工作不正常......
当然它工作正常。 The manual:
如果年份格式规范少于四位,例如YYY,
并且提供的年份小于四位数,年份将是
调整为最接近年份 2020,例如95 变为 1995。
所以,70 变为 1970,但 69 变为 2069。
Oracle 对格式说明符RR 有不同的规则,Postgres 中不存在这种规则。基本上,年份会被调整到最接近年份2000(离当前日期最近的世纪):
解决方法
将功能封装在一个根据字符串中的年份编号切换世纪的函数中。由于 Postgres 允许函数重载,您甚至可以使用相同的函数名称 to_date() 和不同的参数类型。见:
根据上面的文档,Oracle 在 YY = '50' 处回绕,这个函数在 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$;
只有STABLE,而不是IMMUTABLE,因为to_date 只是STABLE。否则你禁用函数内联。
我选择varchar作为第一个参数与原来的不同,它使用text。
如果年份数字 > 49,则函数将 20 世纪(带有 '19')添加到转换前的日期字符串中,否则将 21 日添加到日期字符串中。第二个参数被忽略。
呼叫:
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
我们的自定义函数无论如何都会忽略第二个参数。
结果:
original | patched1 | patched2 | patched3
------------+------------+------------+------------
2053-06-25 | 1953-06-25 | 1953-06-25 | 1953-06-25
db小提琴here
旧sqlddle
您可能会使其在 2049 之后工作更复杂,并考虑第二个参数...
警告:在基本函数之上的函数重载最好小心。如果它留在你的系统中,以后可能会有人得到令人惊讶的结果。
最好在特殊模式中创建该函数并有选择地设置search_path,以便仅在适当时使用它。在这种情况下,您也可以使用text 作为参数类型:
CREATE SCHEMA specialfunc;
CREATE OR REPLACE FUNCTION specialfunc.to_date(text, text) AS ...
然后:
SET search_path = specialfunc, pg_catalog;
SELECT to_date('25-JUN-53', 'DD-MON-YY') AS patched;
或使用临时功能。见: