5

我需要将 sysdate 和时间转换为特定的时区,如 EST。我不能假设我当前的时区。

如何在plsql中转换它?请帮我。

4

7 回答 7

7

假设您有一个TIMESTAMP WITH TIME ZONE(例如systimestamp),您可以使用该AT TIME ZONE语法。例如,我可以systimestamp通过指定不同的时区名称来获取当前时区并将其转换为 UTC (GMT)、东部和太平洋时区。

SQL> ed
Wrote file afiedt.buf

  1  select systimestamp at time zone 'UTC' current_time_in_utc,
  2         systimestamp at time zone 'Us/Eastern' current_time_in_est,
  3         systimestamp at time zone 'US/Pacific' current_time_in_pst
  4*   from dual
SQL> /

CURRENT_TIME_IN_UTC
---------------------------------------------------------------------------
CURRENT_TIME_IN_EST
---------------------------------------------------------------------------
CURRENT_TIME_IN_PST
---------------------------------------------------------------------------
26-APR-12 05.36.11.802000 PM UTC
26-APR-12 01.36.11.802000 PM US/EASTERN
26-APR-12 10.36.11.802000 AM US/PACIFIC
于 2012-04-26T17:37:14.037 回答
3

Oracle 已经有一个时区表:

SELECT tzname, tzabbrev from V$TIMEZONE_NAMES
SELECT TZ_OFFSET('US/Eastern') FROM DUAL;

获取 EPT 中的当前时间以用于 SQL 语句:

select to_timestamp(to_char(TRUNC(LOCALTIMESTAMP - 5/1440, 'MI'),'mm/dd/yyyy hh24:mi'),'mm/dd/yyyy hh24:mi') FROM DUAL;

Oracle 的 11g SQL 参考非常好,可在此处在线获取:http: //docs.oracle.com/cd/B28359_01/server.111/b28286/toc.htm

您可以快速查找以下功能,我相信您会发现这些功能会有所帮助:

  • 当前时间戳
  • 数据库时区
  • 本地时间戳
  • 截断(日期)
  • 会话时区
  • sys_extract_utc
  • 系统时间戳
  • to_timestamp
  • to_timestamp_tz
  • tz_offset

    更改会话集 TIME_ZONE = '+00:00'; -- 您现在将看到 UTC 时间而不是 EPT

不同时区的当前日期和时间

以当地通行时间返回当前日期和时间(sysdate)

 Select sysdate from dual;

select LOCALTIMESTAMP FROM DUAL;

以 UTC 格式返回当前日期

select LOCALTIMESTAMP at time zone '+00:00' FROM DUAL

-- 尝试使用 localtimestamp、to_timestamp 和 to_timestamp_tz,而不是使用 sysdate 和 to_date。它们类似于 sysdate 和 to_date,但添加了时区功能。

select LOCALTIMESTAMP at time zone '+00:00' FROM DUAL; –- returns essentially the same as sysdate but in UTC

or 

ALTER SESSION SET TIME_ZONE = 'UTC';
select LOCALTIMESTAMP FROM DUAL –- after setting session time_zone to ‘UTC’ this will now return a UTC timestamp

时区转换 以 UTC 格式获取当前时间以用于 SQL 语句。

-- Get current time in UTC format and subtract 5 minutes.

    LOCALTIMESTAMP at time zone '+00:00' - 5/1440

-- Trunc the time to eliminate seconds

TRUNC(LOCALTIMESTAMP at time zone '+00:00' - 5/1440, 'MI')

-- Convert to characters then back to datetime. 

to_timestamp(to_char(TRUNC(LOCALTIMESTAMP at time zone '+00:00' - 5/1440, 'MI'),'mm/dd/yyyy hh24:mi'),'mm/dd/yyyy hh24:mi')

-- Select from dual to show it works. 

select to_timestamp(to_char(TRUNC(LOCALTIMESTAMP at time zone '+00:00' - 5/1440, 'MI'),'mm/dd/yyyy hh24:mi'),'mm/dd/yyyy hh24:mi') FROM DUAL;

Get the current time in EPT for use in a SQL statement.

    -- Get current time in UTC format and subtract 5 minutes.
    ALTER SESSION SET TIME_ZONE = 'US/Eastern'; -- set to EPT time
    select LOCALTIMESTAMP from dual - 5/1440
-- Trunc the time to eliminate seconds

    TRUNC(LOCALTIMESTAMP - 5/1440, 'MI')

    -- Convert to characters then back to datetime. 
    to_timestamp(to_char(TRUNC(LOCALTIMESTAMP - 5/1440, 'MI'),'mm/dd/yyyy hh24:mi'),'mm/dd/yyyy hh24:mi')

    -- Select from dual to show it works. 
    select to_timestamp(to_char(TRUNC(LOCALTIMESTAMP - 5/1440, 'MI'),'mm/dd/yyyy hh24:mi'),'mm/dd/yyyy hh24:mi') FROM DUAL;

返回 DB 和 Session 时区函数

ALTER SESSION SET TIME_ZONE = '+00:00';  -- you will now see times in UTC instead of EPT
ALTER SESSION SET NLS_DATE_FORMAT = 'MM/DD/YYYY HH24:MI:SS';

ALTER SESSION SET TIME_ZONE = '+00:00';  -- you will now see times in UTC instead of EPT
ALTER SESSION SET TIME_ZONE = 'UTC'; -- set to UTC time same as command above
SELECT DBTIMEZONE , SESSIONTIMEZONE, CURRENT_TIMESTAMP, LOCALTIMESTAMP, systimestamp, sysdate FROM DUAL; -- see the results
ALTER SESSION SET TIME_ZONE = 'US/Eastern'; -- set to EPT time
SELECT DBTIMEZONE , SESSIONTIMEZONE, CURRENT_TIMESTAMP, LOCALTIMESTAMP, systimestamp, sysdate FROM DUAL; -- see the results

SELECT TO_TIMESTAMP_TZ('05/16/2014 11:26:48 -04:00',
   'MM/DD/YYYY HH:MI:SS TZH:TZM') FROM DUAL;


SELECT tzname, tzabbrev from V$TIMEZONE_NAMES where tzabbrev = 'EPT';
SELECT TZ_OFFSET('US/Eastern') FROM DUAL;

-- The following example casts a null column in a UNION operation as TIMESTAMP WITH LOCAL TIME ZONE using the sample tables oe.order_items and oe.orders:

SELECT order_id, line_item_id,
   CAST(NULL AS TIMESTAMP WITH LOCAL TIME ZONE) order_date
   FROM order_items
UNION
SELECT order_id, to_number(null), order_date
   FROM orders;

日期时间和时区 (TO_TIMESTAMP_TZ)

TO_TIMESTAMP_TZ converts char of CHAR, VARCHAR2, NCHAR, or NVARCHAR2 datatype to a value of TIMESTAMP WITH TIME ZONEdatatype.

示例:以下示例将字符串转换为 TIMESTAMP WITH TIME ZONE 的值:

SELECT TO_TIMESTAMP_TZ('1999-12-01 11:00:00 -8:00',
   'YYYY-MM-DD HH:MI:SS TZH:TZM') FROM DUAL;
TO_TIMESTAMP_TZ('1999-12-0111:00:00-08:00','YYYY-MM-DDHH:MI:SSTZH:TZM')

以下示例使用示例表 oe.order_items 和 oe.orders 将 UNION 操作中的空列转换为 TIMESTAMP WITH LOCAL TIME ZONE:

SELECT order_id, line_item_id,
   CAST(NULL AS TIMESTAMP WITH LOCAL TIME ZONE) order_date
   FROM order_items
UNION
SELECT order_id, to_number(null), order_date
   FROM orders;

设置日期和时间格式

ALTER SESSION SET NLS_DATE_FORMAT = 'MM/DD/YYYY HH24:MI:SS';
SELECT CURRENT_TIMESTAMP, LOCALTIMESTAMP FROM DUAL;

设置当前/本地时区

ALTER SESSION SET TIME_ZONE = '-5:00';
ALTER SESSION SET NLS_DATE_FORMAT = 'MM/DD/YYYY HH24:MI:SS';
SELECT CURRENT_TIMESTAMP, LOCALTIMESTAMP FROM DUAL;

当地时间 (LOCALTIMESTAMP)

LOCALTIMESTAMP 以数据类型 TIMESTAMP 的值返回会话时区中的当前日期和时间。此函数与 CURRENT_TIMESTAMP 的区别在于 LOCALTIMESTAMP 返回一个 TIMESTAMP 值,而 CURRENT_TIMESTAMP 返回一个 TIMESTAMP WITH TIME ZONE 值。

ALTER SESSION SET TIME_ZONE = '-5:00';
    ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-YYYY HH24:MI:SS';
    SELECT CURRENT_TIMESTAMP, LOCALTIMESTAMP FROM DUAL;

以下语句使用正确的格式掩码来匹配 LOCALTIMESTAMP 的返回类型:

    INSERT INTO local_test VALUES
   (TO_TIMESTAMP(LOCALTIMESTAMP, 'DD-MON-RR HH.MI.SSXFF PM'));

The code above is required to include the TIME ZONE portion of the return type of the function

当前时间戳 (CURRENT_TIMESTAMP)

CURRENT_TIMESTAMP 以数据类型 TIMESTAMP WITH TIMEZONE 的值返回会话时区中的当前日期和时间。时区偏移量反映了 SQL 会话的当前本地时间

    ALTER SESSION SET TIME_ZONE = '-5:0';
ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-YYYY HH24:MI:SS';
    SELECT SESSIONTIMEZONE, CURRENT_TIMESTAMP FROM DUAL;
于 2014-05-16T19:42:58.020 回答
2

这个怎么样?

select to_timestamp_tz(to_char(sysdate,'YYYY-MM-DD HH24:MI:SS') || ' ' || 'FROM_TIME_ZONE', 'YYYY-MM-DD HH24:MI:SS TZR') at time zone 'TO_TIME_ZONE'
from dual;
于 2012-04-27T12:48:00.420 回答
1

尝试这个:

CREATE TABLE TIMEZONES (ZONE          CHAR(1) PRIMARY KEY,
                        NAMES         VARCHAR2(25) NOT NULL,
                        OFFSET_HOURS  NUMBER NOT NULL);

按如下方式填充它:

INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('Z', 'GMT', 0);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('N', '-1', -1);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('O', '-2', -2);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('P', '-3', -3);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('Q', '-4 EDT', -4);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('R', 'EST CDT', -5);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('S', 'CST MDT', -6);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('T', 'MST PDT', -7);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('U', 'PST', -8);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('V', '-9', -9);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('W', '-10', -10);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('X', '-11', -11);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('Y', '-12', -12);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('A', '1', -1);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('B', '2', -2);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('C', '3', -3);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('D', '4', -4);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('E', '5', -5);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('F', '6', -6);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('G', '7', -7);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('H', '8', -8);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('I', '9', -9);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('K', '10', -10);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('L', '11', -11);
INSERT INTO TIMEZONES (ZONE, NAMES, OFFSET_HOURS) VALUES ('M', '12', -12);

鉴于上述情况,您可以这样做

SELECT SYS_EXTRACT_UTC(SYSTIMESTAMP) + (tz.OFFSET_HOURS / 24)
  FROM TIMEZONES tz
  WHERE tz.NAMES LIKE '%EDT%';

或者

  WHERE tz.ZONE = 'Q'

获取-4时区的当地时间。

分享和享受。

于 2012-04-26T17:28:38.940 回答
1

以下将为您提供当前的 EST 时间(UTC - 5 小时),而不考虑夏令时:

SELECT SYS_EXTRACT_UTC(SYSTIMESTAMP) FROM DUAL

为了考虑夏令时,您有 2 个选项:

  1. 编写一个函数来计算夏令时更改发生在哪些日期
  2. 填充包含这些日期的表

如果您只需要支持 EST 时区,那么编写一个函数可能是要走的路;否则我建议填充一个包含这些日期的表格,因为它们在时区之间有所不同

于 2012-04-26T08:28:12.293 回答
0

到目前为止,所有方法在使用当前时间戳时都可以很好地工作。然而,我注意到甲骨文tz_offset会给你主要的时间偏移量。例如,七月,

SELECT TZ_OFFSET('US/Eastern') FROM DUAL;

结果为“-04:00”。1 月,相同的语句导致“-05:00”。因此,如果要转换存储在数据库中的日期(而不是当前系统或会话时间),则必须进行一些开发。

你可能会注意到

SELECT TZ_OFFSET('EST') FROM DUAL;

总是返回“-05:00”。不幸的是,对其他美国标准时间(中部、山区和太平洋)的快速测试显示了不同的结果。运行以下命令自己查看。在 DST 生效时,我在 6 月 16 日运行了以下命令。

SELECT TZ_OFFSET('US/Eastern'), TZ_OFFSET('EST'),  TZ_OFFSET('EST5EDT') FROM DUAL;
SELECT TZ_OFFSET('US/Central'), TZ_OFFSET('CST'),  TZ_OFFSET('CST6CDT') FROM DUAL;
SELECT TZ_OFFSET('US/Mountain'), TZ_OFFSET('MST'),  TZ_OFFSET('MST7MDT') FROM DUAL;
SELECT TZ_OFFSET('US/Pacific'), TZ_OFFSET('PST'),  TZ_OFFSET('PST8PDT') FROM DUAL;

-04:00      -05:00      -04:00
-05:00      -05:00      -05:00
-06:00      -07:00      -06:00
-07:00      -07:00      -07:00

结果有些令人沮丧。从快速采样来看,几乎所有 tz_offset 查询似乎都以当前流行时间响应。这在您处理当前时间的转换时很有用,但在处理从数据库中提取的时间时会变得平淡无奇。

现在,我可以编写代码来确定我是处于标准时间还是现行时间。但是,我看不到在tz_offset标准时间或日光时间持续拉动 a 的方法,只是普遍存在。

这使得开发人员需要像上面 Bob Jarvis 所做的那样创建自己的表来解决问题,就像我在下面的代码中所做的那样。

ALTER SESSION SET NLS_DATE_FORMAT = 'MM/DD/YYYY HH24:MI:SS';

Declare
-- ******** User declarations begin here ******** --




-- ******** User declarations end here ******** --

/*******************  All Declarations of Variables and Functions below this point support Time Zone Conversion (Convert_TZ function) *******************/  
  -- TimeZone Conversion Procedure

  -- User Input (Parameters)
  input_date date := TO_TIMESTAMP_TZ('7/1/2009 18:00','mm/dd/yyyy hh24:mi');  -- Try: LocalTimestamp; or TO_TIMESTAMP('2/1/2009 13:00','mm/dd/yyyy hh24:mi')
  --input_date date := LocalTimestamp;
  input_TZ varchar(3) := 'GMT';  -- Exmaples: EST, EDT or EPT for Eastern Standard, Daylight or Prevailing, respectively.
  output_TZ varchar(3) := 'EPT';  -- 

  -- Variables
  type date_array is table of date;
  return_date date := localtimestamp;
  temp_date date := to_date('10/27/1974 02:00','mm/dd/yyyy hh24:mi');
  type str_array is table of varchar2(10);
  dow_list str_array;

   Function dst_start_stop (input_date DATE) 
        RETURN date_array
    AS
        year_part number(4);
        start_week number(1) := 0;  -- week of month: -1=last, 1=1st, 2=nd, 0=fixed date (like 1974 and 1975)
        stop_week number(1) := 0;   -- week of month: -1=last, 1=1st, 2=nd, 0=fixed date (like 1974 and 1975)
        dst_start date := to_date('01/06/1974 23:59','mm/dd/yyyy hh24:mi');
        dst_stop date := to_date('10/27/1974 23:59','mm/dd/yyyy hh24:mi');
        dst_date date := dst_start;
        dst_msg varchar2(500) := ' ';
        inc_dec number := 0;
        Cnt number(1) := 0;
        dst_dow number(1) := 1;  --  1=Sunday, 2=Monday, etc.
        i number;
        dst_range date_array;
   BEGIN
      dst_range := date_array();
      dst_range.extend(2);
      dst_range(1) := temp_date;
      dst_range(2) := temp_date;
      DBMS_OUTPUT.PUT_LINE('  ** Start: dst_start_stop Func **');
      --insert into dst_range values(dst_start,dst_stop);
      --dst_range(1) := dst_start;
      --dst_range(2) :=  dst_stop;
      year_part := to_number(to_char(input_date,'YYYY'));
      DBMS_OUTPUT.PUT_LINE('      Year: '||year_part);

      -- Determine DST formula based on year of input_date
      If year_part > 9999 Then  --   Invalid TempYear > 9999
          dst_msg := 'N/A.  I can''t guess if DST will be applied after 9999.  Standard Time returned.  ';
          Goto found_start_stop;
      ElsIf year_part >= 2007 Then --   2007 forward.  Latest DST Rules used after 2007.
          dst_msg := '2007 forward: Third National DST Standard.  ';
          --dst_msg := dst_msg || 'Spring Forward 2:00 AM second Sunday in March (skip 02:00:00 through 02:59:59, I.E. skip from 01:59:59 to 03:00:00).  '
          --dst_msg := dst_msg || 'Fall Back 2:00 AM first Sunday in November (repeat 02:00:00 to 02:59:59, I.E. jump back from 02:59:59 to 02:00:00 once).  '
          DBMS_OUTPUT.PUT_LINE('    '||dst_msg);
          dst_start := to_date('03/01/'||year_part||' 02:00','mm/dd/yyyy hh24:mi');
          start_week := 2; -- 2nd Sunday in March
          dst_stop := to_date('11/01/'||year_part||' 02:00','mm/dd/yyyy hh24:mi');
          stop_week := 1;  -- 1st Sunday in November
      ElsIf year_part >= 1987 Then  --   1987 thru 2006.
          dst_msg := '1987 thru 2006: Second National DST Standard.  ';
          --dst_msg := dst_msg || 'Spring Forward 2:00 AM first Sunday in April (skip 02:00:00 through 02:59:59, I.E. skip from 01:59:59 to 03:00:00).  ';
          --dst_msg := dst_msg || 'Fall Back 2:00 AM last Sunday in October (repeat 02:00:00 to 02:59:59, I.E. jump back from 02:59:59 to 02:00:00 once).  ';
          DBMS_OUTPUT.PUT_LINE('    '||dst_msg);
          start_week := 1; 
          dst_start := to_date('04/01/'||year_part||' 02:00','mm/dd/yyyy hh24:mi');
          stop_week := -1;  
          dst_stop := to_date('10/31/'||year_part||' 02:00','mm/dd/yyyy hh24:mi');
      ElsIf year_part >= 1976 Then  --   1976 thru 1986 OLD DST Rules used 1961 thru 1973.
          dst_msg := '1976 thru 1986: First National DST Standard (resumed after 1974-1975 extended DST trials).  ';
          --dst_msg := dst_msg || 'Spring Forward 2:00 AM last Sunday in April (skip 02:00:00 through 02:59:59, I.E. skip from 01:59:59 to 03:00:00).  ';
          --dst_msg := dst_msg || 'Fall Back 2:00 AM last Sunday in October (repeat 02:00:00 to 02:59:59, I.E. jump back from 02:59:59 to 02:00:00 once).  ';
          DBMS_OUTPUT.PUT_LINE('    '||dst_msg);
          start_week := -1; 
          dst_start := to_date('04/30/'||year_part||' 02:00','mm/dd/yyyy hh24:mi');
          stop_week := -1;  
          dst_stop := to_date('10/31/'||year_part||' 02:00','mm/dd/yyyy hh24:mi');
      ElsIf year_part = 1975 Then  --   1975 Trial.
          dst_msg := '1975 Trial of Extended DST.  ';
          --dst_msg := dst_msg || 'Spring Forward 2:00 AM Feb 23 (skip 02:00:00 through 02:59:59, I.E. skip from 01:59:59 to 03:00:00).  ';
          --dst_msg := dst_msg || 'Fall Back 2:00 AM Oct 26, the last Sun in Oct (repeat 02:00:00 to 02:59:59, I.E. jump back from 02:59:59 to 02:00:00 once).  ';
          DBMS_OUTPUT.PUT_LINE('    '||dst_msg);
          dst_start := to_date('02/23/1975 02:00','mm/dd/yyyy hh24:mi');
          dst_stop := to_date('10/26/1974 02:00','mm/dd/yyyy hh24:mi');
          Goto found_start_stop;
      ElsIf year_part = 1974 Then  --   1974 Trial.
          dst_msg := '1974 Trial of Extended DST.  ';
          --dst_msg := dst_msg || 'Spring Forward 2:00 AM Jan 6 (skip 02:00:00 through 02:59:59, I.E. skip from 01:59:59 to 03:00:00)).  ';
          --dst_msg := dst_msg || 'Fall Back 2:00 AM Oct 27 (repeat 02:00:00 to 02:59:59, I.E. jump back from 02:59:59 to 02:00:00 once).  ';
          DBMS_OUTPUT.PUT_LINE('    '||dst_msg);
          dst_start := to_date('01/06/1974 02:00','mm/dd/yyyy hh24:mi');
          dst_stop := to_date('10/27/1974 02:00','mm/dd/yyyy hh24:mi');
          Goto found_start_stop;
      ElsIf year_part >= 1961 Then  --   1961 thru 1973 First National DST Standard.
          dst_msg := '1961 thru 1973: First National DST Standard.  ';
          --dst_msg := dst_msg || 'Spring Forward 2:00 AM last Sunday in April (skip 02:00:00 through 02:59:59, I.E. skip from 01:59:59 to 03:00:00).  ';
          --dst_msg := dst_msg || 'Fall Back 2:00 AM last Sunday in October (repeat 02:00:00 to 02:59:59, I.E. jump back from 02:59:59 to 02:00:00 once).  ';
          start_week := -1; 
          dst_start := to_date('04/30/'||input_date||' 02:00','mm/dd/yyyy hh24:mi');
          stop_week := -1;  
          dst_stop := to_date('10/31/'||year_part||' 02:00','mm/dd/yyyy hh24:mi');
      ElsIf year_part >=1900 Then  --   DST was applied inconsistently or not at all
          dst_msg := 'N/A.  Before 1961, DST was applied inconsistently across states or not at all.  Standard Time returned.  ';
          Goto found_start_stop;
      ElsIf year_part < 1900 Then  --   Invalid year_part
          dst_msg := 'N/A. DST never active before 1900';
          Goto found_start_stop;
      Else  --   Invalid year_part 
          dst_msg := 'N/A.  Error.  Invalid datetime value.';
          Goto found_start_stop;
      End If;   
      DBMS_OUTPUT.PUT_LINE('  The code specified the following DST rules for the input date ('||input_date||').  '||dst_msg);
      if start_week > 0 then
        DBMS_OUTPUT.PUT_LINE('    Start on '||dow_list(dst_dow)||' #'||start_week||' of '||trunc(dst_start,'W')||'. ');
      else
        DBMS_OUTPUT.PUT_LINE('    Starts '||start_week||' from the last '||dow_list(dst_dow)||' of '||trunc(dst_start,'W')||'. ');
      end if;
      if stop_week > 0 then
        DBMS_OUTPUT.PUT_LINE('    End on '||dow_list(dst_dow)||' #'||stop_week||' of '||trunc(dst_stop,'W')||'. ');
      else
        DBMS_OUTPUT.PUT_LINE('    Ends '||stop_week||' from the last '||dow_list(dst_dow)||' of '||trunc(dst_stop,'W')||'. ');
      end if;
      DBMS_OUTPUT.PUT_LINE('    ');


      /* Apply formula determined above to find dst start and stop times for the year of the input_date.
            This section is skipped if start/stop already determined or indeterminant. 
      */
        -- DstStartDay 
        inc_dec := start_week/abs(start_week);  -- results in +1 or -1
        Cnt := 0; i:=0;
        while (Cnt < abs(start_week) and i<20) loop
          i:=i+1;
          if (to_char(dst_start,'D') = dst_dow) then 
            Cnt := Cnt + 1; 
            --DBMS_OUTPUT.PUT_LINE('    Found '||dow_list(dst_dow))||' '||Cnt||': '||dst_start)
          end if;
          if (Cnt < abs(start_week)) then 
            dst_start := dst_start + inc_dec; 
          end if;
        end loop;
        case inc_dec
          when 1 then
            DBMS_OUTPUT.PUT_LINE('  Spring forward on  '||dow_list(dst_dow)||' #'||Cnt||' of the month: '||dst_start);
          else
            DBMS_OUTPUT.PUT_LINE('  Spring forward on the last'||dow_list(dst_dow)||'of the month: '||dst_start);
        end case;
      -- DstStopDay 
        inc_dec := stop_week/abs(stop_week);  -- results in +1 or -1
        Cnt := 0; i :=0;
        while (Cnt < abs(stop_week) and i <20) loop -- to_char(dst_stop,'D') > 1 loop
          i:=i+1;
          if (to_char(dst_stop,'D') = dst_dow) then 
            dst_stop := dst_stop + inc_dec; 
            Cnt := Cnt + 1; 
          end if;
          if (Cnt < abs(stop_week)) then 
            dst_stop := dst_stop + inc_dec; 
          end if;
        end loop;
        case inc_dec
          when 1 then
            DBMS_OUTPUT.PUT_LINE('  Fall back on  '||dow_list(dst_dow)||' #'||Cnt||' of the month: '||dst_stop);
          else
            DBMS_OUTPUT.PUT_LINE('  Fall back on the last'||dow_list(dst_dow)||'of the month: '||dst_stop);
        end case;
    <<found_start_stop>>
      dst_range(1) := dst_start; 
      DBMS_OUTPUT.PUT_LINE('      dst_range(1): '||to_char(dst_range(1),'mm/dd/yyyy hh24:mi')||' = '||dst_start);
      dst_range(2) := dst_stop;
      DBMS_OUTPUT.PUT_LINE('      dst_range(2): '||to_char(dst_range(2),'mm/dd/yyyy hh24:mi')||' = '||dst_stop);
      DBMS_OUTPUT.PUT_LINE('  ** Finish: dst_start_stop Func **');
      Return dst_range;
   END dst_start_stop;

   Function is_dst_now
        Return boolean
      AS
          --type date_array is table of date;
          dst_range date_array;
          curr_time date := LocalTimestamp;
      Begin
          dst_range := date_array();
          dst_range.extend(2);
          dst_range := dst_start_stop(curr_time);
          If (dst_range(1) <= curr_time and curr_time < dst_range(2))  then 
            DBMS_OUTPUT.PUT_LINE('DST is  active.');
            Return True;
          Else
            DBMS_OUTPUT.PUT_LINE('DST is NOT active.');
            Return False;
          End If;  
   End;

   FUNCTION dst_offset (prevailing_date DATE, dst_start DATE, dst_stop DATE) 
        RETURN number
      AS
            offset_days number :=0;
      BEGIN

          DBMS_OUTPUT.PUT_LINE('  Starting dst_offset sub-function:');
          DBMS_OUTPUT.PUT_LINE('        where (input date, DST start, DST stop) = '||to_char(prevailing_date,'mm/dd/yyyy hh24:mi')
                                ||', '||to_char(dst_start,'mm/dd/yyyy hh24:mi')||', '||to_char(dst_stop,'mm/dd/yyyy hh24:mi'));

          If (dst_start <= prevailing_date and prevailing_date < dst_stop) then 
            offset_days :=1/24;
            DBMS_OUTPUT.PUT_LINE('        input date is between dst start and stop');
          Else
            offset_days :=0;
            DBMS_OUTPUT.PUT_LINE('        input date is not between dst start and stop');
          End If;
          DBMS_OUTPUT.PUT_LINE('        Result: DST Offset days = '||offset_days);
          DBMS_OUTPUT.PUT_LINE('                          hours = '||(offset_days*24)); 
          Return offset_days;
   END dst_offset;

-- Begin  --move this down under the function -- ******************

   FUNCTION Convert_TZ (input_date DATE, input_tz varchar2, output_tz varchar2) 
   RETURN date
   AS
        -- Variables
        input_sz varchar(3) := substr(input_TZ,1,1)||'S'||substr(input_TZ,3,1);
        input_sz varchar(3) := substr(output_TZ,1,1)||'S'||substr(output_TZ,3,1);
        temp_str varchar2(1000);
        dst_range date_array;
        input_dst_offset number := 0;
        input_tz_offset number := 0;
        input_date_st date; --standard time
        gmt_date date;
        output_dst_offset number := 0;
        output_tz_offset number := 0;
        output_date date;
        output_date_pt date; -- prevailing time
        tz_offset_str varchar2(30);
        --orig_nls_date_format varchar2(30) := NLS_DATE_FORMAT;
        --TempYear number(4,0) := to_char(TempDate,'YYYY');  -- or := trunc(PrevailingTime, YYYY);

   BEGIN 

      DBMS_OUTPUT.PUT_LINE('Starting Pl/sql procedure.  ');

      DBMS_OUTPUT.PUT_LINE('Input Date: '||to_char(input_date,'mm/dd/yyyy hh24:mi')||' '||input_tz||'.  ');
      -- Find DST start/stop dates  
      dst_range := date_array();
      dst_range.extend(2);
      dst_range := dst_start_stop(input_date);
      DBMS_OUTPUT.PUT_LINE('DST date range determined.  ');
      DBMS_OUTPUT.PUT_LINE('      dst_range(1): '||to_char(dst_range(1),'mm/dd/yyyy hh24:mi')||' = '||dst_range(1));
      DBMS_OUTPUT.PUT_LINE('      dst_range(2): '||to_char(dst_range(2),'mm/dd/yyyy hh24:mi')||' = '||dst_range(2));

      -- Convert Input Date from input time zone to GMT
        If upper(input_TZ) in ('GMT','UCT') then
            -- If input TZ is GMT, we can skip this conversion!
            DBMS_OUTPUT.PUT_LINE('    Input Time is ('||to_char(input_date,'mm/dd/yyyy hh24:mi')||' '
                                  ||input_tz||' GMT).  No conversion required.  ');
            input_tz_offset := 0;
            input_dst_offset := 0; 
            gmt_date := input_date;
        Else
            -- Convert from local prevailing to local standard time
                -- Get input_dst_offset 
                Case upper(substr(input_TZ,2,1)) 
                  When 'S' then 
                    -- already in standard time, not conversion needed.
                    input_dst_offset := 0; -- duplicative
                    DBMS_OUTPUT.PUT_LINE('Standard time ('||input_tz||') entered; no dst offset.' );
                          --input_tz_offset := input_tz_offset;
                  Else 
                    -- run dst_offset function to convert from prevailing or daylight time to standard time.
                    input_dst_offset := dst_offset(input_date, dst_range(1), dst_range(2));
                    input_date_st := input_date - input_dst_offset; 
                    DBMS_OUTPUT.PUT_LINE('Daylight Saving Time Effective ('||to_char(input_date,'mm/dd/yyyy hh24:mi')||' '
                                          ||input_tz||'); 1 hour offset; input DST offset = '||input_dst_offset);
                    DBMS_OUTPUT.PUT_LINE('        where (input_date, dst_start, dst_stop) = '
                                          ||to_char(input_date,'mm/dd/yyyy hh24:mi')
                                          ||' '||input_tz||', '||dst_range(1)||', '||dst_range(2)||', ');
                    DBMS_OUTPUT.PUT_LINE('        which adjusts '||to_char(input_date,'mm/dd/yyyy hh24:mi')||' '||input_tz
                                          ||' daylight to '||input_date_st||' standard time.  ');
                End Case;

            -- Convert from local standard time to GMT
                SELECT TZ_OFFSET((SELECT max(tzname) FROM V$TIMEZONE_NAMES where tzabbrev = input_TZ)) 
                INTO tz_offset_str 
                FROM DUAL;

                input_tz_offset := ( substr(tz_offset_str,1,3)/24 + substr(tz_offset_str,5,2)/1440 );
                If is_dst_now then 
                  input_tz_offset := input_tz_offset - 1/24;
                End if;
                DBMS_OUTPUT.PUT_LINE('    input_tz_offset (fractional days): '||input_tz_offset||'. ');
                DBMS_OUTPUT.PUT_LINE('    input_tz_offset (hours): '||input_tz_offset*24||'. ');
                gmt_date := input_date_st - input_tz_offset;

        End If;

        -- Convert input date from GMT to requested output time zone
        DBMS_OUTPUT.PUT_LINE('  ');
        DBMS_OUTPUT.PUT_LINE('Starting output_date analysis. ');
        If upper(output_TZ) in ('GMT','UCT') then
            -- If desired output TZ is GMT, we can skip this conversion!
            output_tz_offset := 0;
            output_dst_offset := 0; 
            output_date := gmt_date;
            DBMS_OUTPUT.PUT_LINE('    Requested output format is GMT: ('||to_char(output_date,'mm/dd/yyyy hh24:mi')||' '||output_tz||').  No conversion required.  ');
        Else
            -- Get output_dst_offset 
                Case upper(substr(output_TZ,2,1)) 
                  When 'S' then 
                    output_dst_offset := 0; -- duplicative
                    DBMS_OUTPUT.PUT_LINE('Standard time ('||output_TZ||') entered; no dst offset.' );
                  Else
                    output_dst_offset := dst_offset(gmt_date + output_tz_offset, dst_range(1), dst_range(2));
                End Case;
            -- Convert from GMT to local standard time
                SELECT TZ_OFFSET((SELECT max(tzname) FROM V$TIMEZONE_NAMES where tzabbrev = output_TZ)) INTO tz_offset_str FROM DUAL;
                output_tz_offset := ( substr(tz_offset_str,1,3)/24 + substr(tz_offset_str,5,2)/1440 );
                DBMS_OUTPUT.PUT_LINE('    output_tz_offset (fractional days): '||output_tz_offset||'. ');
                DBMS_OUTPUT.PUT_LINE('    output_tz_offset (hours): '||output_tz_offset*24||'. ');
                If is_dst_now then 
                  output_tz_offset := output_tz_offset - 1/24;
                  DBMS_OUTPUT.PUT_LINE('    tz_offset correction... ');
                  DBMS_OUTPUT.PUT_LINE('      output_tz_offset (fractional days): '||output_tz_offset||'. ');
                  DBMS_OUTPUT.PUT_LINE('      output_tz_offset (hours): '||output_tz_offset*24||'. ');
                End if;

                    output_date := gmt_date + output_tz_offset + output_dst_offset;        
                    DBMS_OUTPUT.PUT_LINE('          gmt_date: '||gmt_date);
                    DBMS_OUTPUT.PUT_LINE('  output_tz_offset: '||output_tz_offset);
                    DBMS_OUTPUT.PUT_LINE(' output_dst_offset: '||output_dst_offset);

                    DBMS_OUTPUT.PUT_LINE('Daylight Saving Time ('||output_TZ||') offset = '||output_dst_offset);
                    DBMS_OUTPUT.PUT_LINE('        where (output_date, dst_start, DST_stop) = '||output_date||', '||dst_range(1)||', '||dst_range(2));
                    DBMS_OUTPUT.PUT_LINE('        which adjusts '||output_date||' standard to '||output_date_pt||' daylight time.  ');
        End If;

        DBMS_OUTPUT.PUT_LINE('Output Date = '||to_char(output_date,'mm/dd/yyyy hh24:mi')||' '||output_tz||'.  ');

    Goto AllDone;

    <<FoundError>>      

    <<AllDone>>
      DBMS_OUTPUT.PUT_LINE('   ');
      DBMS_OUTPUT.PUT_LINE('***    Results     ***');
      DBMS_OUTPUT.PUT_LINE('   ');

      if input_dst_offset <> 0 then
        temp_str := 'daylight saving';
      else
        temp_str := 'standard';
      end if;
      DBMS_OUTPUT.PUT_LINE('    Input Date: '||to_char(input_date,'mm/dd/yyyy hh24:mi')||' '||input_tz||', which falls in  '||temp_str||' time.  ');
      DBMS_OUTPUT.PUT_LINE('    GMT Date: '||to_char(gmt_date,'mm/dd/yyyy hh24:mi')||' UTC/GMT.  ');
      DBMS_OUTPUT.PUT_LINE('    Output Date: '||to_char(output_date,'mm/dd/yyyy hh24:mi')||' UTC/GMT.  ');
      if output_dst_offset <> 0 then
        temp_str := 'daylight saving';
      else
        temp_str := 'standard';
      end if;
      DBMS_OUTPUT.PUT_LINE('    All Done.  Return Value: '||to_char(output_date,'mm/dd/yyyy hh24:mi')||' '||output_tz||'.  ');
      DBMS_OUTPUT.PUT_LINE('   ');
      DBMS_OUTPUT.PUT_LINE('*** End of Results ***');
      DBMS_OUTPUT.PUT_LINE('   ');
      DBMS_OUTPUT.PUT_LINE('LocalTimestamp EPT: '||LocalTimestamp);
      DBMS_OUTPUT.PUT_LINE('LocalTimestamp GMT:'||LOCALTIMESTAMP at time zone '+00:00');

      Return output_date;
   END;  
/*********************** End of Declarations of Variables and Functions for Time Zone Conversion (Convert_TZ function) *********************/  
Begin  
/*********************** Start of Procedural Code for  Time Zone Conversion (Convert_TZ function) *********************/  
     /* DOW list is required for Time Zone Conversion (Convert_TZ function) and should not be deleted. */
      dow_list := str_array();
      dow_list.extend(7);
      dow_list(1) := 'Sun';
      dow_list(2) := 'Mon';
      dow_list(3) := 'Tue';
      dow_list(4) := 'Wed';
      dow_list(5) := 'Thu';
      dow_list(6) := 'Fri';
      dow_list(7) := 'Sat';

     /* Next 2 lines are example of use of Time Zone Conversion (Convert_TZ function). */
      return_date := Convert_TZ (input_date, input_tz, output_tz);
      DBMS_OUTPUT.PUT_LINE('ta-dah! '||return_date);
/*********************** End of Procedural Code for Time Zone Conversion (Convert_TZ function) *********************/  

-- ******** User coded begins here ******** --
End;    
于 2014-06-18T23:17:20.907 回答
0
RTRIM( TO_CHAR( systimestamp at time zone 'GMT', 'DD-MON-YYYY HH24:MI:SS TZR' ))
RTRIM( TO_CHAR( systimestamp at time zone 'EST', 'DD-MON-YYYY HH24:MI:SS TZR' ))
RTRIM( TO_CHAR( systimestamp at time zone 'PST', 'DD-MON-YYYY HH24:MI:SS TZR' ))

output:
   05-NOV-2014 17:20:10 GMT
   05-NOV-2014 12:20:10 EST
   05-NOV-2014 09:20:10 PST

substr('05-NOV-2014 09:20:10 PST', -3, 3)   will return 'PST'

RTRIM (EXTRACT (HOUR from systimestamp ))
output:  17    (notice the 17 is in GMT time)
于 2014-11-05T21:24:53.930 回答