Преобразование временной метки EST в часовой пояс каждого конкретного пользователя - PullRequest
0 голосов
/ 28 августа 2018

Я работаю над программой, которая содержит временные метки базы данных. Настройки времени дБ устанавливаются в EST. Я видел много постов о переходе из одного часового пояса в другой, но есть ли способ конвертировать из EST в любой часовой пояс, в котором находится пользователь?

Ответы [ 2 ]

0 голосов
/ 28 августа 2018

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

(Кстати, почему EST? Вам не нужен часовой пояс со смещением летнего времени? Или, другими словами, вы на 100% уверены, что это EST, а не EDT?)

В идеале, если целью является работа в местных часовых поясах, тип данных столбца не должен быть либо timestamp, либо timestamp with time zone; вместо этого должно быть timestamp with local time zone. Всякий раз, когда данные вводятся в этот тип данных, вы указываете только часовой пояс. Oracle считает, что он находится в часовом поясе вашего сеанса; он преобразует его в часовой пояс сервера и сохраняет его. Информация о часовом поясе не сохраняется, но тип столбца имеет смысл. Когда извлекаются те же данные, они преобразуются во временную зону вызывающего абонента.

В вашей ситуации, если временная метка хранится без часового пояса в столбце типа данных timestamp, вам нужно сделать две вещи при получении данных. Во-первых, вы должны сообщить Oracle, что временная метка была в часовом поясе EST (или в любом другом часовом поясе, в котором она действительно должна находиться). Затем - после этого шага - вы можете конвертировать в метку времени с local time zone; тогда поведение становится таким же, как в идеальном расположении, где столбец имел тип данных timestamp with local time zone с самого начала.

На рисунке ниже показаны оба шага.

Вот ваша базовая таблица - с одним столбцом типа timestamp и одной строкой. ВЫ знаете, что временная метка находится в часовом поясе EST; база данных не.

create table tbl(ts timestamp);

insert into tbl(ts)
  values (timestamp '2018-08-24 13:50:23.392302000');

И вот что я предлагаю в качестве решения. Только последний столбец - это то, что вам действительно нужно; Я показываю второй столбец для иллюстрации необходимого промежуточного шага. Обратите внимание на разницу между вторым столбцом и первым: второй столбец имеет часовой пояс, показанный в конце (-05: 00). Также обратите внимание, что третий столбец будет зависеть от моего (или вашего или чьего-либо) часового пояса сеанса. Мой (в настоящее время с DST) на два часа отстает от EST; это будет три часа позади EDT. Я на западном побережье США.

select ts,
       from_tz(ts, 'EST')                                         ts_with_time_zone,
       cast(from_tz(ts, 'EST') as timestamp with local time zone) ts_in_local_time_zone
from   tbl;

TS                            TS_WITH_TIME_ZONE                    TS_IN_LOCAL_TIME_ZONE        
----------------------------- ------------------------------------ -----------------------------
2018-08-24 13:50:23.392302000 2018-08-24 13:50:23.392302000 -05:00 2018-08-24 11:50:23.392302000
0 голосов
/ 28 августа 2018

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

select dbtimezone db, sessiontimezone sess from dual;

DB                             SESS
------------------------------ ------------------------------
+00:00                         Europe/London

alter session set time_zone = 'Australia/Perth';

select dbtimezone db, sessiontimezone sess from dual;

DB                             SESS
------------------------------ ------------------------------
+00:00                         Australia/Perth

Вы можете преобразовать временную метку из одного часового пояса в другой с помощью предложения at time zone. Например:

alter session set time_zone = 'Europe/London';

select systimestamp server,
       systimestamp at time zone sessiontimezone sess,
       systimestamp at time zone 'Asia/Calcutta' india,
       current_timestamp curr_ts
from   dual;

SERVER                              SESS                                     INDIA                                    CURR_TS
----------------------------------- ---------------------------------------- ---------------------------------------- ----------------------------------------
28-AUG-18 08.46.59.104889 -07:00    28-AUG-18 16.46.59.104889 EUROPE/LONDON  28-AUG-18 21.16.59.104889 ASIA/CALCUTTA  28-AUG-18 16.46.59.104899 EUROPE/LONDON

Примечание: systimestamp возвращает дату, время и часовой пояс сервера. Это может отличаться от DBTIMEZONE! Current_timestamp - часовой пояс сеанса.

Как именно работает это преобразование, зависит от того, как вы сохранили свои значения.

Существует три типа меток времени:

  • отметка времени
  • отметка времени с часовым поясом
  • отметка времени с местным часовым поясом

Обычные старые временные метки не содержат информации о часовом поясе. Так что вам нужно знать, в каком TZ ваше приложение хранит его! Добавление предложения at time zone возвращает то же время с добавлением часового пояса.

Временная метка с сохранением часового пояса сохраняет часовой пояс как есть. Использование at time zone возвращает дату, конвертированную в указанный часовой пояс.

Местные часовые пояса нормализуют данные в соответствии с часовым поясом базы данных. Когда вы запрашиваете их, база данных преобразует их в часовой пояс сеанса. Использование at time zone возвращает дату, преобразованную в указанный часовой пояс.

create table t (
  ts     timestamp,
  ts_tz  timestamp with time zone,
  ts_ltz timestamp with local time zone
);
insert into t values ( 
  timestamp '2018-01-01 00:00:00', timestamp '2018-01-01 00:00:00 UTC', timestamp '2018-01-01 00:00:00 UTC'
);
insert into t values ( 
  timestamp '2018-01-01 00:00:00', timestamp '2018-01-01 00:00:00 America/Denver', timestamp '2018-01-01 00:00:00 America/Denver'
);

select * from t;

TS                                       TS_TZ                                    TS_LTZ
---------------------------------------- ---------------------------------------- ----------------------------------------
01-JAN-18 00.00.00.000000                01-JAN-18 00.00.00.000000 UTC            01-JAN-18 00.00.00.000000
01-JAN-18 00.00.00.000000                01-JAN-18 00.00.00.000000 AMERICA/DENVER 01-JAN-18 07.00.00.000000

alter session set time_zone = 'Asia/Calcutta';

select * from t;

TS                                       TS_TZ                                    TS_LTZ
---------------------------------------- ---------------------------------------- ----------------------------------------
01-JAN-18 00.00.00.000000                01-JAN-18 00.00.00.000000 UTC            01-JAN-18 05.30.00.000000
01-JAN-18 00.00.00.000000                01-JAN-18 00.00.00.000000 AMERICA/DENVER 01-JAN-18 12.30.00.000000

select ts at time zone sessiontimezone ts,
       ts_tz at time zone sessiontimezone ts_tz,
       ts_ltz at time zone sessiontimezone ts_ltz
from   t;

TS                                       TS_TZ                                    TS_LTZ
---------------------------------------- ---------------------------------------- ----------------------------------------
01-JAN-18 00.00.00.000000 ASIA/CALCUTTA  01-JAN-18 05.30.00.000000 ASIA/CALCUTTA  01-JAN-18 05.30.00.000000 ASIA/CALCUTTA
01-JAN-18 00.00.00.000000 ASIA/CALCUTTA  01-JAN-18 12.30.00.000000 ASIA/CALCUTTA  01-JAN-18 12.30.00.000000 ASIA/CALCUTTA

Если вы храните значения в date, то применяются те же правила, что и для простой отметки времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...