2012-02-09 2 views
0

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

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 Application Server?

ответ

0

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

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.

0

Я думаю, это не зависит от параметра даты, который вы передаете. Вероятно, это зависит от настроек операционной системы, на которых работает сервер базы данных. В 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. 
+0

Выполнение этих запросов через sqlplus на сервере OAS, как пользователь, обслуживающий веб-страницы, не приводит к ошибкам. –

0

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