您误解了数据类型。正如您所指出的,时间戳不存储时区,但它也确实不允许您“将时间保存到附加区域的数据库中”。
当你这样做时:
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 987654325@:
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
(另请阅读 Tony’s Tirade against TIMESTAMP WITH TIME ZONE 了解有关数据类型选项的更多背景信息。)