繁体   English   中英

TIMESTAMP、TIMESTAMP WITH TIME ZONE 和 TIMESTAMP WITH LOCAL TIME ZONE 之间的区别

[英]Difference between TIMESTAMP, TIMESTAMP WITH TIME ZONE and TIMESTAMP WITH LOCAL TIME ZONE

我在两个不同的数据库中运行相同的语句:我的本地数据库和Oracle Live SQL

CREATE TABLE test(
    timestamp TIMESTAMP DEFAULT SYSDATE,
    timestamp_tmz TIMESTAMP WITH TIME ZONE DEFAULT SYSDATE,
    timestamp_local_tmz TIMESTAMP WITH LOCAL TIME ZONE DEFAULT SYSDATE
);

INSERT INTO test VALUES (DEFAULT, DEFAULT, DEFAULT);

SELECT * FROM test;

(所有语句大约在同一时间执行 - 欧洲中部时间上午 09:35)

我本地数据库的结果:

TIMESTAMP: 10-JAN-23 09.35.32.000000000 AM
TIMESTAMP WITH TIME ZONE: 10-JAN-23 09.35.32.000000000 AM EUROPE/BERLIN
TIMESTAMP WITH LOCAL TIME ZONE: 10-JAN-23 09.35.32.000000000 AM

来自 Oracle 直播的结果:

TIMESTAMP: 10-JAN-23 08.35.44.000000 AM 
TIMESTAMP WITH TIME ZONE: 10-JAN-23 08.35.44.000000 AM US/PACIFIC   
TIMESTAMP WITH LOCAL TIME ZONE: 10-JAN-23 08.35.44.000000 AM

看到结果后,我的问题是:

  • 为什么 Oracle Live 的 TIMESTAMP 显示日期在不同的时区(8.35 AM 而不是 9.35 AM)?
  • 为什么 Oracle Live 的 TIMESTAMP WITH TIME ZONE 返回 US/PACIFIC 作为时区?
  • TIMESTAMP 和 TIME STAMP WITH LOCAL TIME ZONE 有区别吗?

文档中描述了不同的数据类型。

TIMESTAMP 数据类型是 DATE 数据类型的扩展。 它存储年、月、日、小时、分钟和秒值。 它还存储小数秒,这是 DATE 数据类型不存储的。

TIMESTAMP WITH TIME ZONE 是 TIMESTAMP 的变体,其值中包含时区区域名称或时区偏移量。

TIMESTAMP WITH LOCAL TIME ZONE 是 TIMESTAMP 的另一种变体。 它与 TIMESTAMP WITH TIME ZONE 的区别如下:存储在数据库中的数据被规范化为数据库时区,时区偏移量不存储为列数据的一部分。 当用户检索数据时,Oracle 数据库以用户本地 session 时区返回。

您看到了差异,因为您有不同的时区,并且您将值默认为SYSDATE ,即系统DATE

在您的本地数据库中,系统时区( select dbtimezone from dual )似乎基于 CET,而 Live SQL 数据库似乎基于 UTC,正如 Oracle 所建议的那样。 由于 CET 比 UTC/GMT 早一个小时,这就解释了一个小时的差异。

TIMESTAMP值只是一个简单的强制转换,即cast(SYSDATE as TIMESTAMP ),因此您将获得与直接查询SYSDATE时相同的值,但添加了零小数秒。

对于TIMESTAMP WITH TIME ZONE ,它必须存储一个时区,并且必须从某个地方获取该时区,默认情况下它使用您的session时区,而不是数据库时区。 在您的本地数据库中,这似乎也是 CET,但 Live SQL 将session时区默认为美国太平洋时间 - 考虑到 Oracle 所在的位置,这并非不合理。 所以现在它有效地为该值执行from_tz(cast(SYSDATE as TIMESTAMP), SESSIONTIMEZONE) ,其中SESSIONTIMEZONE在一个数据库中是 CET,在另一个数据库中是 US/Pacific。

对于TIMESTAMP WITH LOCAL TIME ZONE它正在做同样的事情,但是然后将其规范化回数据库时区以进行存储(有效地cast(from_tz(cast(SYSDATE as TIMESTAMP), SESSIONTIMEZONE) at time zone DBTIMEZONE as TIMESTAMP) - 实际上不是在内部,但给了你想法),并在查询时再次从数据库时区转换回你的 session 时区。

在这两个数据库中,如果您在插入之前alter session set time_zone =... ,并在查询之前再次更改为不同的值,那么您将看到不同的结果——前两列显示的时间部分将保持不变,但是时区将更改为WITH TIME ZONE ,时间将更改为WITH LOCAL TIME ZONE

摆弄不同的 session 时区。

您可以在我上面已链接的文档中阅读有关所有这些行为的更多信息。


如果您使用SYSTIMESTAMP而不是SYSDATE作为所有列的默认值,那么您将避免隐式转换为WITH TIME ZONE值的 session 时区,这将始终显示数据库时区。 LOCAL列仍将显示在您的 session 时区,但它们都代表相同的时间。 您还会看到两个数据库之间一小时的差异,因为它们具有不同的数据库时区。 您可以考虑将普通时间戳默认为sys_extract_utc(SYSTIMESTAMP) ,或者将它们全部(或至少前两个) SYSTIMESTAMP at time zone 'UTC'

摆弄UTC 标准化值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM