2012-04-26 7 views
3

Мне нужно преобразовать sysdate и время в определенный часовой пояс, например EST. Я не могу принять текущий часовой пояс.Изменение часового пояса в PLSQL

Как это сделать в plsql? Пожалуйста, помогите мне.

+0

Хорошо, ваш имеют SYSDATE. Но я не понимаю, что вы хотите получить. Напишите пример, пожалуйста. –

ответ

1

Следующие даст вам текущее время EST (UTC - 5 часов) без учета перехода на летнее:

SELECT SYS_EXTRACT_UTC(SYSTIMESTAMP) FROM DUAL 

Для того, чтобы переходить на летнее время счета, у вас есть 2 варианта:

  1. Напишите функцию расчета, которая относится на летнее и зимнее время изменения происходят на
  2. Заполняют таблицу, содержащую эти даты

Если вам нужна только поддержка часового пояса EST, тогда запись функции может быть путем; в противном случае я бы рекомендовал заполнить таблицу, содержащую эти даты, как они vary between time zones.

+0

Спасибо за ваш ответ. Он дает ошибку, что DATEADD является недопустимым идентификатором. – Suvonkar

+0

Ах, извиняюсь, я не понимал, что вы используете Oracle, попробуйте это: SELECT SYS_EXTRACT_UTC (SYSTIMESTAMP) FROM DUAL; – weenoid

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 часовом поясе.

Делитесь и наслаждайтесь.

6

Предполагая, что у вас есть 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 
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; 
3

Oracle уже есть часовой пояс таблицу:

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

Получить текущее время в ЕРТ для использования в SQL заявление:

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

11g SQL ссылка Oracle, является довольно хорошо и доступно онлайн здесь: http://docs.oracle.com/cd/B28359_01/server.111/b28286/toc.htm

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

  • current_timestamp
  • DBTIMEZONE
  • localtimestamp
  • Trun (дата)
  • sessiontimezone
  • sys_extract_utc
  • systimestamp
  • to_timestamp
  • to_timestamp_tz
  • TZ_OFFSET

    ALTER SESSION SET 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 

- Вместо использования sysdate и to_date попробуйте использовать localtimestamp, to_timestamp и to_timestamp_tz. Они похожи на 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 и время сеанса функции зоны

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 С временной зоной:

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') 

Следующий пример отличает нулевой столбец в операции UNION как TIMESTAMP WITH LOCAL TIME ZONE с использованием таблицы tablesoe.order_items и 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; 

Set Дата & время форматирует

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

Установить ток/локальный Timezone

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; 
0

Всех методов до сих пор работает хорошо при работе с текущим временем. Однако я заметил, что Oracle tz_offset даст вам преобладающее смещение времени. Например, в июле

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

Результаты '-04: 00.' В январе такое же заявление приводит к «-05: 00». Итак, если вы хотите конвертировать дату, хранящуюся в базе данных (в отличие от текущей системы или времени сеанса), вам нужно сделать некоторую разработку.

Вы можете заметить, что

SELECT TZ_OFFSET('EST') FROM DUAL; 

всегда возвращает "-05: 00. К сожалению, быстрый тест на другие стандартные времена США (Центральная, Гора и Тихий океан) показал разные результаты. Выполните следующее, чтобы убедиться сами. Я выполнил следующее 16 июня, тогда как DST был в силе.

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 для стандартного или дневного времени, просто превалируя.

Это оставляет разработчику необходимость создать свой собственный стол, как Боб Джарвис сделал выше, чтобы взломать проблему, как я сделал в коде ниже.

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;  
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) 
+0

Поскольку это старый вопрос, как ваш ответ обеспечивает лучшее решение? – carlodurso

Смежные вопросы