根据Oracle docs,带有本地时区的TIMESTAMP的行为如下。
我对第二点即检索有疑问。
也就是说,到用户时区的这种转换是数据库本身发生的还是由数据库客户端/驱动程序负责的?
例如:说我正在使用Oracle JDBC驱动程序。驱动程序是否将时间值转换为用户的时区,或者数据库应该在用户的时区中返回时间值?如果应该进行数据库转换,则客户端应该向数据库提供其时区的指示,不是吗?
答案 0 :(得分:3)
数据库执行该操作。如果您在时间戳中存储了相同的标称时刻,则带时区的时间戳和带本地时区的时间戳列:
create table t42 (id number,
ts timestamp,
tstz timestamp with time zone,
tsltz timestamp with local time zone
);
insert into t42 (id, ts, tstz, tsltz)
values (1,
timestamp '2019-08-13 07:13:20 UTC',
timestamp '2019-08-13 07:13:20 UTC',
timestamp '2019-08-13 07:13:20 UTC'
);
insert into t42 (id, ts, tstz, tsltz)
values (2,
timestamp '2019-08-13 12:34:56.789 Australia/Sydney',
timestamp '2019-08-13 12:34:56.789 Australia/Sydney',
timestamp '2019-08-13 12:34:56.789 Australia/Sydney'
);
alter session set time_zone = 'Europe/London';
select id, ts, tstz, tsltz from t42 order by id;
ID TS TSTZ TSLTZ
-- ----------------------- ---------------------------------------- -----------------------
1 2019-08-13 07:13:20.000 2019-08-13 07:13:20.000 UTC 2019-08-13 03:13:20.000
2 2019-08-13 12:34:56.789 2019-08-13 12:34:56.789 AUSTRALIA/SYDNEY 2019-08-12 22:34:56.789
...您可以使用dump()
来查看它们在内部的实际存储方式:
select id, 'TS' as col, to_char(ts, 'YYYY-MM-DD HH24:MI:SS.FF3') as value, dump(ts) as dumped from t42
union all
select id, 'TSTZ', to_char(tstz, 'YYYY-MM-DD HH24:MI:SS.FF3 TZR'), dump(tstz) from t42
union all
select id, 'TSLTZ', to_char(tsltz, 'YYYY-MM-DD HH24:MI:SS.FF3 TZR'), dump(tsltz) from t42
order by 1, 4;
ID COL VALUE DUMPED
-- ----- ---------------------------------------- -------------------------------------------------------
1 TS 2019-08-13 07:13:20.000 Typ=180 Len=7: 120,119,8,13,8,14,21
1 TSTZ 2019-08-13 07:13:20.000 UTC Typ=181 Len=13: 120,119,8,13,8,14,21,0,0,0,0,208,4
1 TSLTZ 2019-08-13 08:13:20.000 EUROPE/LONDON Typ=231 Len=7: 120,119,8,13,8,14,21
2 TS 2019-08-13 12:34:56.789 Typ=180 Len=11: 120,119,8,13,13,35,57,47,7,47,64
2 TSTZ 2019-08-13 12:34:56.789 AUSTRALIA/SYDNEY Typ=181 Len=13: 120,119,8,13,3,35,57,47,7,47,64,133,128
2 TSLTZ 2019-08-13 03:34:56.789 EUROPE/LONDON Typ=231 Len=11: 120,119,8,13,3,35,57,47,7,47,64
对于原始UTC值,您可以看到TS和TSLTZ值存储的字节数完全相同,但类型代码不同; TSTZ是第三种类型,前7个字节相同(存储的日期/时间-参见MoS Doc ID 69028.1或here-这些字节与12类日期相同)加上其他字节用于时区信息(此处零表示小数秒)。日期/时间字节都是相同的,因为它们都是UTC。无论如何,在我的数据库中,因为那是我的DBTIMEZONE:
select dbtimezone, sessiontimezone from dual;
DBTIME SESSIONTIMEZONE
------ ---------------------------------------------------------------------------
+00:00 Europe/London
对于最初的悉尼值,TS值为当地时间,因此小时字节为13(12 + 1);对于TSTZ和TSLTZ,日期/时间字节仍然是UTC,因此它们具有3(2 + 1); TSTZ还具有时区信息。 TSLTZ没有时区信息,因为类型231始终为UTC。将其转换为字符串时,将应用会话时区,因此存储的小时字节3(2 + 1)变为本地小时3。
在不同的会话时区中,您几乎会看到相同的内容:
alter session set time_zone = 'America/New_York';
select id, 'TS' as col, to_char(ts, 'YYYY-MM-DD HH24:MI:SS.FF3') as value, dump(ts) as dumped from t42
union all
select id, 'TSTZ', to_char(tstz, 'YYYY-MM-DD HH24:MI:SS.FF3 TZR'), dump(tstz) from t42
union all
select id, 'TSLTZ', to_char(tsltz, 'YYYY-MM-DD HH24:MI:SS.FF3 TZR'), dump(tsltz) from t42
order by 1, 4;
ID COL VALUE DUMPED
-- ----- ---------------------------------------- -------------------------------------------------------
1 TS 2019-08-13 07:13:20.000 Typ=180 Len=7: 120,119,8,13,8,14,21
1 TSTZ 2019-08-13 07:13:20.000 UTC Typ=181 Len=13: 120,119,8,13,8,14,21,0,0,0,0,208,4
1 TSLTZ 2019-08-13 03:13:20.000 AMERICA/NEW_YORK Typ=231 Len=7: 120,119,8,13,8,14,21
2 TS 2019-08-13 12:34:56.789 Typ=180 Len=11: 120,119,8,13,13,35,57,47,7,47,64
2 TSTZ 2019-08-13 12:34:56.789 AUSTRALIA/SYDNEY Typ=181 Len=13: 120,119,8,13,3,35,57,47,7,47,64,133,128
2 TSLTZ 2019-08-12 22:34:56.789 AMERICA/NEW_YORK Typ=231 Len=11: 120,119,8,13,3,35,57,47,7,47,64
当然,存储的字节完全相同;但是现在TSLTZ值已调整为纽约时间,因此对于悉尼,小时字节3(2 + 1)变为本地时间22,并且在另一个日期。
(由于我格式化的方式,此处显示的是时区TSLTZ;正如您在第一个查询中看到的那样,它实际上没有时区,因此还进行了进一步的隐式转换以便显示该会话值。
如果让客户端格式化底层内部字节结构,您将看到相同的值,就像我在上面的第一个查询中所做的那样。但是使用to_char()
可以回答问题的主要部分;数据库必须在之前发生这种情况,将值从其内部格式转换为字符串。如果客户端(或JDBC)将调整时间调整为本地时间,那么to_char()
将只看到存储的基于DBTIMEZONE的字节,并始终为您提供与该时间相同的DBTIMEZONE。
您的客户端-或JDBC-告诉数据库使用哪个本地时区。我已经用alter session
覆盖了它,您可以通过JDBC进行相同的操作。默认情况下,它基于Java语言环境和其他应用程序设置。但you can override it。