2016-04-11 3 views
0

Мое требование здесь - получить время в GMT/UTC из столбца типа даты. Но когда я использую бросок для датирования даты в timestamp, он использует часовой пояс US/Pacific в качестве ссылки, хотя часовой пояс сеанса установлен на GMT. Поэтому, если я не использую from_tz, я не вижу желаемого результата. Есть ли какой-либо другой параметр часового пояса в оракуле sql, который мне нужно изменить, чтобы всегда использовать GMT в качестве ссылки?Oracle sql timezone issue

alter session set time_zone='+00:00'; 
select sessiontimezone from dual; 
select current_timestamp from dual; 
select sys_extract_utc(cast (sysdate as timestamp)) from dual; 
select sys_extract_utc(from_tz(cast (sysdate as timestamp), '-07:00')) from dual; 
select sys_extract_utc(current_timestamp) from dual; 


Session altered. 


SESSIONTIMEZONE 
--------------------------------------------------------------------------- 
+00:00 


CURRENT_TIMESTAMP 
--------------------------------------------------------------------------- 
11-APR-16 08.46.42.292173 AM +00:00 


SYS_EXTRACT_UTC(CAST(SYSDATEASTIMESTAMP)) 
--------------------------------------------------------------------------- 
11-APR-16 01.46.42.000000 AM 

SYS_EXTRACT_UTC(FROM_TZ(CAST(SYSDATEASTIMESTAMP),'-07:00')) 
--------------------------------------------------------------------------- 
11-APR-16 08.46.42.000000 AM 


SYS_EXTRACT_UTC(CURRENT_TIMESTAMP) 
--------------------------------------------------------------------------- 
11-APR-16 08.46.42.295310 AM 

Таблица задач имеет столбец типа даты, называемый task_started. Я ищу, чтобы получить время UTC из этого поля даты. В рамках этого я пытался изменить временную зону сеанса на GMT при вставке данных, чтобы я мог просто отбросить ее обратно на временную метку, которая не работает.

select task_started from tasks where rownum <2; 

TASK_STAR 
--------- 
10-APR-16 

desc tasks; 
Name          Null? Type 
----------------------------------------- -------- ---------------------------- 
... 
TASK_STARTED          DATE 
... 
+0

Можете ли вы привести пример хранимой даты (со временем) и ожидаемого результата? В каком часовом поясе указывается дата/время в этом столбце и как вы знаете - есть ли другой столбец, хранящий его часовой пояс, или вы предполагаете, что требуется какое-то преобразование? –

+0

@AlexPoole В моей таблице сохранена только дата, поэтому я возвращаю ее обратно в метку времени. Я предполагаю, что дата/время, хранящиеся в таблице, должны использовать временную зону сеанса, которая является GMT, поскольку я изменил зону сеанса. Поскольку функция броска возвращает время назад в США/Тихоокеанском регионе, я смутился. –

+0

У столбца даты нет часового пояса (но всегда есть время, даже если ваш запрос/клиент этого не показывает). Если вы нажмете как обычную временную метку, время останется неизменным, но у него по-прежнему не будет информации о часовом поясе.Ваш вопрос заключается в преобразовании даты/времени в UTC, что означает, что он хранится или предоставляется из определенной зоны. Например. если дата была первоначально вставлена ​​с использованием sysdate, что подразумевает часовой пояс сервера, и вы хотите получить эквивалент UTC. Пожалуйста, добавьте данные и выводите их, поскольку не ясно, что вам действительно нужно. –

ответ

0

Это демо, используя данные, вставленные с помощью sysdate в системе по лондонскому времени, так что в настоящее время на BST (+01: 00). Разница меньше, чем вы видели на западном побережье, но применяются те же самые вещи.

Подражая таблицу, вы можете видеть, что время сеанса зона не имеет никакого влияния на вставленном значении, поскольку sysdate использует время сервера базы данных, а не сеанс (клиент) время (as explained here):

alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'; 
alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS.FF3'; 
alter session set nls_timestamp_tz_format = 'YYYY-MM-DD HH24:MI:SS.FF3 TZH:TZM'; 

create table tasks (id number, task_started date); 

alter session set time_zone='America/Los_Angeles'; 

insert into tasks (id, task_started) values (1, sysdate); 

select task_started, cast(task_started as timestamp) as ts 
from tasks where rownum < 2; 

TASK_STARTED  TS      
------------------- ----------------------- 
2016-04-11 11:55:59 2016-04-11 11:55:59.000 

alter session set time_zone = 'UTC'; 

select task_started, cast(task_started as timestamp) as ts 
from tasks where rownum < 2; 

TASK_STARTED  TS      
------------------- ----------------------- 
2016-04-11 11:55:59 2016-04-11 11:55:59.000 

Так это время BST в обоих случаях. Отсутствует какой-либо параметр сеанса или базы данных, который покажет вам дату (или временную метку без часового пояса), автоматически преобразованную в определенный часовой пояс. База данных не знает, что представляет собой сохраненная дата/время, если вы не сообщите об этом. Он не знает или имеет дело, если вы используете sysdate, current_date или литер даты; в момент, когда данные вставляются в таблицу, он вообще не имеет информации о часовом поясе.

Для получения UTC-эквивалента вам необходимо использовать , чтобы заявить, что сохраненное значение представляет определенный часовой пояс; то вы можете использовать at time zone (который хранит информацию о часовом поясе) или sys_extract_utc (а это не так), чтобы преобразовать его; и, возможно, отбрасывать назад к дате:

select from_tz(cast(task_started as timestamp), 'Europe/London') as db_tstz, 
    from_tz(cast(task_started as timestamp), 'Europe/London') at time zone 'UTC' as utc_tstz, 
    sys_extract_utc(from_tz(cast(task_started as timestamp), 'Europe/London')) as utc_ts, 
    cast(sys_extract_utc(from_tz(cast(task_started as timestamp), 'Europe/London')) as date) as utc_date 
from tasks where rownum < 2; 

DB_TSTZ      UTC_TSTZ      UTC_TS     UTC_DATE   
------------------------------ ------------------------------ ----------------------- ------------------- 
2016-04-11 11:55:59.000 +01:00 2016-04-11 10:55:59.000 +00:00 2016-04-11 10:55:59.000 2016-04-11 10:55:59 

Я использовал время название зоны региона, так что заботится о летнем времени для меня; вы можете использовать dbtimezone, но это всегда будет использовать -08: 00, и, как вы показали в вопросе, вам нужно использовать -07: 00 на данный момент. И вы могли бы использовать sessiontimezone, но тогда вы должны помнить, что правильно установите это. Очевидно, что в вашем случае вы будете использовать свой локальный регион, например. Америка/Лос-Анджелесе, вместо Европы/Лондона.

И от того, что вы можете получить эпоху, через интервал по сравнению временных меток или более просто из сравнения дат:

select sys_extract_utc(from_tz(cast(task_started as timestamp), 'Europe/London')) 
    - timestamp '1970-01-01 00:00:00' as diff_interval, 
    cast(sys_extract_utc(from_tz(cast(task_started as timestamp), 'Europe/London')) as date) 
    - date '1970-01-01' as diff_days, 
    86400 * 
    (cast(sys_extract_utc(from_tz(cast(task_started as timestamp), 'Europe/London')) as date) 
     - date '1970-01-01') as epoch 
from tasks where rownum < 2; 

DIFF_INTERVAL DIFF_DAYS  EPOCH 
---------------- --------- ----------- 
16902 10:55:59.0 16902.46 1460372159 

Если положить 1460372159 в интернет-конвертер (есть много) будет показывать Время UTC.