Не можете получить информацию о часовом поясе при использовании mod_plsql?

Я написал функцию для преобразования даты в метку времени Unix. Функция написана для работы независимо от текущего статуса DST (например, EST или EDT). Это функция:

function unix_time_from_date(in_date in date) return number
as
  ut number     := 0;
  tz varchar2(8) := '';
begin  
  -- Get the local timezone from the passed in date
  -- Assuming the date supplied is for the local time zone
  select
    extract(
      timezone_abbr from cast(in_date as timestamp with local time zone)
    )
  into tz
  from dual;

  -- Get the Unix timestamp
  select
    (new_time(in_date, tz, 'GMT') - to_date('01-JAN-1970', 'DD-MM-YYYY')) * (
    86400)
  into ut
  from dual;

  return ut;
end unix_time_from_date;

Эта функция прекрасно работает, когда я выполняю ее от клиента, такого как JDeveloper. Из того, что я понял, это связано с тем, что клиент предоставляет информацию о часовом поясе для первого запроса. Однако, если я использую функцию внутри процедуры, которая вызывается со страницы mod_plsql, я получаю сообщение об ошибке. ORA-01857: not a valid time zone, Эта ошибка выбрасывается из new_time функция, потому что tz установлен в 'UNK',

Итак, я реализовал обход этой проблемы следующим образом:

function unix_time_from_date(in_date in date) return number
as
  ut number     := 0;
  tz varchar2(8) := '';
begin  
  -- Get the local timezone from the passed in date
  -- Assuming the date supplied is for the local time zone
  select
    extract(
      timezone_abbr from cast(in_date as timestamp with local time zone)
    )
  into tz
  from dual;

  if tz = 'UNK' then
    select
      extract(
        timezone_abbr from cast(sysdate as timestamp with local time zone)
      )
    into tz
    from dual;
  end if;

  -- Get the Unix timestamp
  select
    (new_time(in_date, tz, 'GMT') - to_date('01-JAN-1970', 'DD-MM-YYYY')) * (
    86400)
  into ut
  from dual;

  return ut;
end unix_time_from_date;

За исключением того, что это по-прежнему не удается с tz устанавливается на 'UNK', Кто-нибудь знает, что здесь может происходить? Почему я не могу получить сокращение местного часового пояса, когда функция вызывается из процесса сервера приложений Oracle?

3 ответа

Решение

Как написано, функция не работает, когда в вызывающей ее сессии не установлена ​​информация о часовом поясе. Поэтому вам нужно явно указать исходный часовой пояс. Следующая функция решает эту проблему (и исправляет тип возвращаемого значения):

function unix_time_from_date
    (
      in_date   in date,
      in_src_tz in varchar2 default 'America/New_York'
    )
  return integer
as
  ut      integer       := 0;
  tz      varchar2(8)   := '';
  tz_date timestamp with time zone;
  tz_stmt varchar2(255);
begin
  -- Get the local time zone abbreviation from the passed in date
  tz_stmt := 'select systimestamp at time zone ''' || in_src_tz || ''' from dual';
  execute immediate tz_stmt into tz_date;
  select
    extract(timezone_abbr from tz_date)
  into tz
  from dual;

  -- Get the Unix timestamp
  select
    (new_time(in_date, tz, 'GMT') - to_date('01-JAN-1970', 'DD-MM-YYYY')) * (86400)
  into ut
  from dual;

  return ut;
end unix_time_from_date;

Обратите внимание на добавление второго параметра в функцию. Этот параметр, in_src_tz, используется, чтобы указать, какой часовой пояс in_date параметр в. Значение in_src_tz должен быть одним из часовых поясов, перечисленных в tzname столбец v$timezone_names Таблица.

Кроме того, вы не можете просто выбрать значение tzabbrev столбец в v$timezone_names таблица из-за часового пояса, имеющего несколько сокращений. Используя выдержку, вы получите текущую аббревиатуру с учетом DST.

Вы сравнили NLS_DATE_FORMAT на вашем локальном компьютере и сервере? Вы можете обнаружить, что комбинация различий в этом и вероятность того, что в момент передачи даты происходит непредвиденное преобразование, могут быть вашей проблемой.

Я думаю, это не зависит от параметра даты, который вы передаете. Вероятно, это зависит от настроек операционной системы, в которой работает сервер базы данных. В JDeveloper это возможно из настроек часового пояса вашего компьютера (ОС). Попробуйте выполнить ssh на сервере БД и запустите первые два запроса в вашем скрипте (используйте фактическую дату в формате "DD-MON-YY" для первого запроса). Оба должны возвращать "UNK". UNK (неизвестно), вероятно, потому что возвращено более одного часового пояса. Примеры: в следующих примерах предположим, что текущим часовым поясом является CST (центральное время США).

SELECT NEW_TIME(SYSDATE, 'CST', 'GMT') FROM DUAL --returns the date in London.

SELECT TO_CHAR(NEW_TIME(SYSDATE, 'CST', 'GMT'),'HH24:MI') FROM DUAL --returns the time, based on the 24-hour clock, in London.

SELECT TO_CHAR(NEW_TIME(SYSDATE + (14 / 24), 'PST', 'PST'),'DD-MON-YY HH24:MI') FROM DUAL --returns the date and time in China. 

SELECT TO_CHAR(NEW_TIME(SYSDATE + (diff / 24), ‘GMT’, ‘GMT’),’DD-MON-YY HH24:MI’) FROM DUAL; --returns the date and time of your office.
Другие вопросы по тегам