我试图让DB以与在机场相同的方式显示日期。例如,如果您在德克萨斯州并且需要乘坐飞机前往东海岸,机场侯爵将在您当地时间显示起飞时间和着陆时间。因此,例如从达拉斯飞往纽约的航班将显示该地区当地时间的时间。
Marquis in Dallas : Takeoff time : 8AM Landing time: 10AM
Marquis in New York: Takeoff time : 9AM Landing time: 11AM
为了做到这一点,我认为数据库会将时间存储在UTC中。我知道TIMESTAMP没有与之关联的区域 - 但是 - 它确实允许人们节省时间到附加了区域的数据库 - 所以 - 我的想法是某种计算会已执行将其转换为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 Poole的详细回复!
我正在使用Hibernate,Java和Oracle,并且遇到了一些使用Hibernate保存基于时间的数据的问题(关于那部分,我在这里看到这篇文章使用JAVA Calendar类格式化解决方案)。文章在这里:How To Handle Oracle TimeStamp with TimeZone from Java我之前也看过你提到的关于“长篇大论”的论文(以及其他文章)。他们似乎不鼓励使用TIMESTAMP和LOCAL TIMEZONE。只是因为这个信息,我有点想完全坚持使用TIMESTAMP :-)但是,还有TIMESTAMP WITH TIMEZONE的选项。
您对使用此Oracle类型有什么想法吗?
答案 0 :(得分:7)
您误解了数据类型。正如您所指出的,时间戳不会存储时区,但它也不允许您“为附加了区域的数据库节省时间”。
当你这样做时:
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
对其产生影响。
在您的情况下,您将最终处理不同时区的两个值,仅使用会话时区对您没有帮助。您可以存储出发/到达机场的时区感知时间:
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,手动或使用{ {3}}:
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
,你可以更好地利用两者,更简单,并且无论如何转换输入时间:
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
(另请阅读sys_extract_utc()
了解有关数据类型选项的更多背景信息。)
答案 1 :(得分:1)
试试这个:
create table toast ( t timestamp WITH LOCAL TIME ZONE );
与TIMESTAMP WITH TIME ZONE类似,但数据除外 存储时标准化为数据库时区,并调整为 检索时匹配客户的时区。