Функция PL / SQL с параметром даты возвращает неправильный вывод - PullRequest
1 голос
/ 12 апреля 2020

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

Что я получаю
Функция

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

Я вызываю функцию с помощью:

declare
    date_out number;
begin
select date_to_epoch(to_date('2020-01-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss')) into date_out from dual;
DBMS_OUTPUT.PUT_LINE('Output:' || date_out);
end;

возвращает: -62134128000

Что я ожидаю
Я получаю ожидаемый результат при выполнении той же операции в простой инструкции 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) from dual;

возврат: 1577836800

Ответы [ 2 ]

3 голосов
/ 12 апреля 2020

Ваш входной параметр уже является датой, поэтому вы не должны использовать to_date() для него. Плохие вещи случаются, когда вы делаете это.

Я бы написал ваш код следующим образом:

create or replace function date_to_epoch(date_in in date)
return number
is
    epoch_out number;
begin
    epoch_out := round((date_in - date '1970-01-01')*24*60*60);
    return epoch_out;
end;

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

create or replace function date_to_epoch(date_in in date)
return number
is
begin
   return round((date_in - date '1970-01-01')*24*60*60);
end;

В этой демонстрации на DB Fiddle код дает:

Output:1577836800
1 голос
/ 13 апреля 2020

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

Функция TO_DATE имеет подпись:

TO_DATE( date_string, format_model, nls_param )

Где все аргументы ожидается, что будет иметь строковый тип данных.

Вы не передаете строку в качестве первого аргумента; вы передаете тип данных DATE. Oracle попытается помочь вам и преобразует DATE, который вы передаете, в строку, неявно вызывая TO_CHAR, используя параметр сеанса формата даты текущего сеанса NLS.

Итак, ваша функция эффективна:

create or replace function date_to_epoch(
  date_in in date
) return number
is
  epoch_out number;
begin
  epoch_out := round(
                 ( to_date(
                     TO_CHAR(
                       date_in,
                       ( SELECT value
                         FROM   NLS_SESSION_PARAMETERS
                         WHERE  parameter = 'NLS_DATE_FORMAT' )
                     ),
                     'yyyy-mm-dd hh24:mi:ss'
                   )
                   -
                   to_date(
                     '1970-01-01',
                     'yyyy-mm-dd'
                   )
                 )*24*60*60
               );
  return epoch_out;
end;

Чтобы исправить это, вам нужно просто использовать ввод даты в качестве даты, а не пытаться преобразовать то, что уже является датой, в дату:

CREATE FUNCTION date_to_epoch(
  date_in IN DATE
) RETURN NUMBER DETERMINISTIC
IS
BEGIN
  RETURN ROUND( ( date_in - DATE '1970-01-01' )*24*60*60 );
END date_to_epoch;

Однако вы также необходимо убедиться, что ваши даты находятся в часовом поясе UT C и если они не конвертированы в UT C, перед вычислением эпохи:

CREATE FUNCTION date_to_epoch(
  date_in  IN DATE,
  timezone IN VARCHAR2 DEFAULT 'UTC'
) RETURN NUMBER DETERMINISTIC
IS
BEGIN
  RETURN ROUND(
    ( CAST(
        FROM_TZ( date_in, timezone ) -- Convert to a timestamp in the correct TZ
        AT TIME ZONE 'UTC'           -- Change to the UTC TZ
        AS DATE                      -- Cast back to a date
      )
      - DATE '1970-01-01'
    )*24*60*60
  );
END date_to_epoch;
/

Итак:

SELECT date_to_epoch( DATE '1970-01-01' )        AS utc_epoch,
       date_to_epoch( DATE '1970-01-01', 'PST' ) AS pst_epoch
FROM   DUAL;

выходы:

UTC_EPOCH | PST_EPOCH
--------: | --------:
        0 |     28800

дБ <> скрипка здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...