2017-08-01 69 views
0

我想让数据库以在机场工作的相同方式显示日期。例如,如果您在德克萨斯州,并且需要乘坐飞机前往东海岸,机场侯爵将在当地时间中显示起飞时间和着陆时间。因此,例如从达拉斯到纽约的航班将在当地时间显示该地区的时间。会话和数据库的oracle数据库时区,更改会话区域不起作用

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

为了做到这一点,我以为DB会存储UTC的时间。我知道TIMESTAMP没有与之关联的区域 - 但是 - 它确实可以节省时间到DB 并附带区域 - 所以 - 我的想法是某种计算会执行转换它到UTC。但是,根据我下面的小测试,这似乎没有发生。无论我设置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普尔为详细的答复!

我正在使用Hibernate,Java和Oracle,并且使用Hibernate保存基于时间的数据时出现了一些问题(关于那个部分,我在这里看到这篇文章使用JAVA Calendar类来设计一个解决方案)。文章在这里:How To Handle Oracle TimeStamp with TimeZone from Java我也曾浏览过你提到的有关“tirade”的文章(以及其他文章)。他们似乎不鼓励使用TIMESTAMP WITH LOCAL TIMEZONE。只是因为这个信息,我有点试图坚持使用TIMESTAMP :-)但是,也有TIMESTAMP WITH TIMEZONE的选项。

你对使用这种Oracle类型有什么想法吗?

回答

4

您误解了数据类型。正如您所指出的那样,时间戳不会存储时区,但而不是可让您“将时间节省到具有附加区域的数据库”。

当你这样做:

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没有影响,因为没有时区信息可以产生任何效果。您将不得不使数据类型timestamp with time zonetimestamp with local 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      

,然后调整到当地机场/显示时间区域with datetime expressions,无论是明确将其命名为区域:

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你种得最好的两个,更简单地说,和你是如何转换的输入时间regarless:

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      

(ALS o请阅读Tony’s Tirade against TIMESTAMP WITH TIME ZONE了解更多关于数据类型选项的背景信息。)

+0

优秀答案 –

+0

@Alex Poole非常感谢您的详细解答!我用以下问题更新了消息:我浏览了之前提到的那篇论文。我也看过其他文章。基本上,似乎是使用TIMESTAMP WITH LOCAL TIMEZONE(?)如果是这样,那么TIMESTAMP WITH TIMEZONE是否可以替代TIMESTAMP WITH LOCAL TIMEZONE? TIA –

+0

@CaseyHarrils - 你一定已经在Tony的文章中对表格下的项目符号进行了非常不同的解释, “当您在不同时区周围复制数据时,请使用TIMESTAMP WITH LOCAL TIME ZONE”和“不要打扰TIMESTAMP或TIMESTAMP WITH TIME ZONE”。他们都有问题,但'当地时区的时间戳'似乎是最简单的(基地唐Tonay的工作)最适合你在做什么?如上所示,坚持使用'时间戳'并强制所有东西都可以工作,并且可能是航空的常用方法。 –

1

试试这个:

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

WITH TIME ZONE到时间戳,除了数据类似的是 标准化为存储在数据库的时区,并在检索时调整到 匹配客户的时区。