[英]Difference between two dates with one date as timestamp without 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
看到结果后,我的问题是:
文档中描述了不同的数据类型。
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.