使用mod_plsql时无法获取时区信息?

时间:2012-02-09 21:21:13

标签: oracle plsql 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 zonenew_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进程调用函数时,为什么无法获取本地时区缩写?

3 个答案:

答案 0 :(得分:0)

我想这不取决于您传递的日期参数。它可能取决于运行数据库服务器的操作系统设置。在JDeveloper中,它可能从您的计算机(OS)时区设置中获取。尝试在数据库服务器上执行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.

答案 1 :(得分:0)

您是否比较了本地计算机和服务器上的NLS_DATE_FORMAT?您可能会发现这里存在差异的组合,以及在传递日期时发生非法转换的可能性可能是您的问题。

答案 2 :(得分: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表中{{1}}列的值。通过使用提取,您将获得当前包含DST的缩写。