Почему функция с параметром типа date возвращает неверный результат?

Чтобы сделать код более читабельным, создал функцию по преобразованию даты в формат эпохи. Однако функция возвращает некорректное значение.

Что я делаю не так?

Сама функция:

create or replace function date2epoch (datein date) return number is
    epoch number;
begin
    epoch := round((to_date(datein, 'yyyy-mm-dd hh24:mi:ss') - 
                    to_date('1970-01-01', 'yyyy-mm-dd'))*24*60*60);
    return epoch;
end;

Вызываю её так:

declare
    dateout number;
begin
    select date2epoch(to_date('2020-01-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss')) into dateout 
    from dual;
    dbms_output.put_line ('Output:'||dateout);
end;

Output:-61536240000

А то что ожидаю, можно получить выполнив тот же самый простой SQL запрос:

select round ((to_date('2020-01-01', 'yyyy-mm-dd hh24:mi:ss')  
             - to_date('1970-01-01', 'yyyy-mm-dd'))*24*60*60) res from dual;

       RES
----------
1577836800

Свободный перевод вопроса PL/SQL function with date parameter returns wrong output от участника @honeybees


Ответы (1 шт):

Автор решения: 0xdb

что ожидаю, можно получить выполнив тот же самый простой SQL запрос

Запрос, который выполняет функция, не эквивалентен тому, который выполняется в SQL. Параметр datein уже датa, поэтому перед вызовом to_date (datein, ...), которая ожидает символьный аргумент, произойдёт преобразование в этот тип данных неявно.

Важно заметить: ни в коем случае не допускайте неявных преобразований типов данных зависящих от национальных настроек сессии.

То есть запрос, который действительно выполняет функция, выглядит так:

select round ((
    to_date (to_char (date'2020-01-01', 'rr-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss') 
  - to_date ('1970-01-01', 'yyyy-mm-dd'))*24*60*60) res from dual
/
          RES
-------------
 -61536240000

Исправленная функция вернёт ожидаемый результат:

create or replace function date2epoch (datein date) return number is
begin
    return (round ((datein - to_date ('1970-01-01', 'yyyy-mm-dd')))*24*60*60);
end;
/
select date2epoch (date'2020-01-01') from dual
/
DATE2EPOCH(DATE'2020-01-01')
----------------------------
                  1577836800
→ Ссылка