簡體   English   中英

oracle db timezone用於會話和數據庫,會話區域的更改不起作用

[英]oracle db timezone for session and database, change of session zone not working

我試圖讓DB以與它在機場相同的方式顯示日期。 例如,如果您在德克薩斯州並且需要乘坐飛機前往東海岸,機場侯爵將在您當地時間顯示起飛時間和着陸時間 因此,例如從達拉斯飛往紐約的航班將顯示該地區當地時間的時間。

Marquis in Dallas :     Takeoff time : 8AM  Landing time: 10AM  
Marquis in New York:    Takeoff time : 9AM  Landing time: 11AM

為了做到這一點,我認為數據庫會以UTC格式存儲時間。 我知道TIMESTAMP沒有與之關聯的區域 - 但是 - 它確實允許人們將時間安排到附加了區域的數據庫 - 所以 - 我的想法是,已經執行了某種計算以將其轉換為世界標准時間。 但是,根據我在下面的小測試,這似乎沒有發生。 無論我將SESSION TIME ZONE設置為什么,日期都保持不變。

TIA

SQL> create table toast ( t timestamp );
Table created.


SQL> insert into toast values ( TIMESTAMP '2019-09-23 16:03:11 US/Eastern');
1 row created.


SQL> select dbtimezone from dual;
DBT
---
UTC

SQL> select sessiontimezone from dual;
SESSIONTIMEZONE
---------------------------------------------------------------------------
-04:00


SQL> select * from toast;
T
---------------------------------------------------------------------------
23-SEP-19 04.03.11.000000 PM

更改會話中的時區仍然會獲得相同的日期

SQL> alter session set time_zone = 'America/Chicago';
Session altered.

SQL> select sessiontimezone from dual;
SESSIONTIMEZONE
---------------------------------------------------------------------------
America/Chicago

SQL> select * from toast;
T
---------------------------------------------------------------------------
23-SEP-19 04.03.11.000000 PM

再次改變它,結果相同

SQL> alter session set time_zone = 'Pacific/Auckland';
Session altered.


SQL> select * from toast;
T
---------------------------------------------------------------------------
23-SEP-19 04.03.11.000000 PM

改為使用小時代替,結果相同

SQL> SQL> alter session set time_zone = '-3:00';
Session altered.


SQL> select sessiontimezone from dual;
SESSIONTIMEZONE
---------------------------------------------------------------------------
-03:00


SQL> select * from toast;
T
---------------------------------------------------------------------------
23-SEP-19 04.03.11.000000 PM

更新非常感謝@Alex Poole的詳細回復!

我正在使用Hibernate,Java和Oracle,並且遇到了一些使用Hibernate保存基於時間的數據的問題(關於那部分,我在這里看到這篇文章使用JAVA Calendar類格式化解決方案)。 文章在這里: 如何使用Java中的TimeZone處理Oracle TimeStamp我還看過你之前提到的關於“tirade”的文章(以及其他文章)。 他們似乎不鼓勵使用TIMESTAMP和LOCAL TIMEZONE。 只是因為這個信息,我有點想完全堅持使用TIMESTAMP :-)但是,還有TIMESTAMP WITH TIMEZONE的選項。

您對使用此Oracle類型有什么想法嗎?

您誤解了數據類型。 時間戳不存儲時區,正如你所指出的,但它也不會允許你“節省時間的DB與它相連的區域”。

當你這樣做時:

insert into toast values ( TIMESTAMP '2019-09-23 16:03:11 US/Eastern');

你正在將文字值隱式轉換為普通時間戳,就好像在做:

insert into toast values ( cast (TIMESTAMP '2019-09-23 16:03:11 US/Eastern' as timestamp ) );

原始區域信息不會保留或可用。 沒有轉換(到UTC或其他任何東西),原始時區信息被丟棄。

select TIMESTAMP '2019-09-23 16:03:11 US/Eastern',
  cast (TIMESTAMP '2019-09-23 16:03:11 US/Eastern' as timestamp )
from dual;

TIMESTAMP'2019-09-2316:03:11US/EASTERN' CAST(TIMESTAMP'2019-09-2316:
--------------------------------------- ----------------------------
23-SEP-19 16.03.11.000000000 US/EASTERN 23-SEP-19 16.03.11.000000000

時間戳文字的原始值顯示時區; 演員值沒有時區信息。

正如您所見,更改會話時區對普通timestamp沒有影響,因為沒有時區信息可以產生任何影響。 您必須timestamp with time zone timestamp with local time zone timestamp with time zonetimestamp with local time zone創建數據類型timestamp with time zone以使其產生任何影響。

在您的情況下,因為您最終將處理不同時區中的兩個值,僅使用會話時區將無法真正幫助您。 您可以存儲出發/到達機場的時區感知時間:

create table toast ( depart timestamp with time zone,
  arrive timestamp with time zone);

insert into toast ( depart, arrive )
values ( TIMESTAMP '2019-09-23 08:00:00 US/Central',
  TIMESTAMP '2019-09-23 11:00:00 US/Eastern' );

alter session set time_zone = 'UTC';

Session altered.

select to_char(depart, 'HH24:MI TZR') as depart,
  to_char(arrive, 'HH24:MI TZR') as arrive
from toast;

DEPART                                 ARRIVE                                
-------------------------------------- --------------------------------------
08:00 US/CENTRAL                       11:00 US/EASTERN                      

然后使用datetime表達式調整到本地機場/顯示時區,顯式地使用命名區域:

select to_char(depart at time zone 'US/Central', 'HH24:MI TZR') as depart,
  to_char(arrive at time zone 'US/Central', 'HH24:MI TZR') as arrive
from toast;

DEPART                                 ARRIVE                                
-------------------------------------- --------------------------------------
08:00 US/CENTRAL                       10:00 US/CENTRAL                      

select to_char(depart at time zone 'US/Eastern', 'HH24:MI TZR') as depart,
  to_char(arrive at time zone 'US/Eastern', 'HH24:MI TZR') as arrive
from toast;

DEPART                                 ARRIVE                                
-------------------------------------- --------------------------------------
09:00 US/EASTERN                       11:00 US/EASTERN                      

或者通過本地會話時區,如果您確信這是正確的:

alter session set time_zone = 'US/Central';

select to_char(depart at local, 'HH24:MI TZR') as depart,
  to_char(arrive at local, 'HH24:MI TZR') as arrive
from toast;

DEPART                                 ARRIVE                                
-------------------------------------- --------------------------------------
08:00 US/CENTRAL                       10:00 US/CENTRAL                      

alter session set time_zone = 'US/Eastern';

select to_char(depart at local, 'HH24:MI TZR') as depart,
  to_char(arrive at local, 'HH24:MI TZR') as arrive
from toast;

DEPART                                 ARRIVE                                
-------------------------------------- --------------------------------------
09:00 US/EASTERN                       11:00 US/EASTERN                      

最好將時間存儲為UTC,如果您願意,可以在普通時間戳中完成 - 因此所有內容都假設存儲的值始終為UTC - 並將您的原始時間轉換為UTC,手動或使用sys_extract_utc()

create table toast ( depart timestamp, arrive timestamp);

insert into toast ( depart, arrive )
values ( sys_extract_utc ( TIMESTAMP '2019-09-23 08:00:00 US/Central' ),
  sys_extract_utc ( TIMESTAMP '2019-09-23 11:00:00 US/Eastern' ) );

...

alter session set time_zone = 'US/Eastern';

select to_char(from_tz( depart, 'UTC' ) at local, 'HH24:MI TZR') as depart,
  to_char(from_tz ( arrive, 'UTC' ) at local, 'HH24:MI TZR') as arrive
from toast;

DEPART                                 ARRIVE                                
-------------------------------------- --------------------------------------
09:00 US/EASTERN                       11:00 US/EASTERN                      

但包括該地區可能更安全:

create table toast ( depart timestamp with time zone,
  arrive timestamp with time zone);

insert into toast ( depart, arrive )
values ( TIMESTAMP '2019-09-23 08:00:00 US/Central' at time zone 'UTC',
  TIMESTAMP '2019-09-23 11:00:00 US/Eastern' at time zone 'UTC' );

...

alter session set time_zone = 'US/Eastern';

select to_char(depart at local, 'HH24:MI TZR') as depart,
  to_char(arrive at local, 'HH24:MI TZR') as arrive
from toast;

DEPART                                 ARRIVE                                
-------------------------------------- --------------------------------------
09:00 US/EASTERN                       11:00 US/EASTERN                      

但是如果你timestamp with local time zone使用timestamp with local time zone那么你可以更好地利用timestamp with local time zone ,更簡單,無論你如何轉換輸入時間:

create table toast ( depart timestamp with local time zone,
  arrive timestamp with local time zone);

insert into toast ( depart, arrive )
values ( TIMESTAMP '2019-09-23 08:00:00 US/Central',
  TIMESTAMP '2019-09-23 11:00:00 US/Eastern' at time zone 'UTC' );

alter session set time_zone = 'UTC';

select to_char(depart, 'HH24:MI TZR') as depart,
  to_char(arrive, 'HH24:MI TZR') as arrive
from toast;

DEPART                                 ARRIVE                                
-------------------------------------- --------------------------------------
13:00 UTC                              15:00 UTC                             

alter session set time_zone = 'US/Central';

select to_char(depart, 'HH24:MI TZR') as depart,
  to_char(arrive, 'HH24:MI TZR') as arrive
from toast;

DEPART                                 ARRIVE                                
-------------------------------------- --------------------------------------
08:00 US/CENTRAL                       10:00 US/CENTRAL                      

alter session set time_zone = 'US/Eastern';

select to_char(depart, 'HH24:MI TZR') as depart,
  to_char(arrive, 'HH24:MI TZR') as arrive
from toast;

DEPART                                 ARRIVE                                
-------------------------------------- --------------------------------------
09:00 US/EASTERN                       11:00 US/EASTERN                      

(另請閱讀Tony's Tirade對TIMESTAMP WITH TIME ZONE以獲取有關數據類型選項的更多背景知識。)

嘗試這個:

create table toast ( t timestamp WITH LOCAL TIME ZONE );

與TIMESTAMP WITH TIME ZONE類似,不同之處在於數據在存儲時標准化為數據庫時區,並在檢索時調整為與客戶端的時區相匹配。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM