【问题标题】:Oracle SQL: converting timestamp to UTCOracle SQL:将时间戳转换为 UTC
【发布时间】:2014-05-06 12:13:35
【问题描述】:

我有一个简单的选择查询,如下所示,但我注意到我正在返回区域时间。如何在我的选择语句中转换为 UTC?

select myTimeStamp, MyName, MyBranch from tableA

结果:'27/03/2014 15:15:26' 'john', 'london'

我曾尝试使用 sys_extract_utc (myTimeStamp),但出现错误

sql 命令没有正确结束

myTimestamp 列的类型为“日期”。

【问题讨论】:

  • 如果您的列是date 类型,您怎么知道它有“区域”时间,Oracle 将如何知道它代表的区域/偏移量 - 那么如何将其转换为 UTC?您是否有其他信息可以确定每个值应该位于哪个区域?

标签: sql oracle utc sql-timestamp


【解决方案1】:
select cast(mytimestamp as timestamp) at time zone 'UTC', 
       MyName, 
       MyBranch 
from tableA

因为mytimestamp 实际上是date 而不是您需要转换的时间戳。这样做会使 Oracle 假定存储在 mytimestamp 中的信息在服务器的时区中 - 如果不是这种情况,您需要使用 Madhawas 的解决方案。

【讨论】:

  • 谢谢,我试过了,但我得到“ORA-300084 - 带有时区修饰符的日期时间主数据类型无效”。我再次检查了“日期”类型的 myTimestamp ios。
  • 上述解决方案会将日期与时区联系起来。现在我还需要做一件事;将时间更改为UTC?例如,如果时间是 PDT 凌晨 1 点(UTC-7 小时),我希望这个时间是 UTC 早上 8 点
【解决方案2】:

根据类型的不同,Oracle 正在从哪个时区转换取决于 myTimestamp 的数据类型,存在一些问题。

带有时区的时间戳

It Just Works™。 a_horse_with_no_name 在这里有正确的答案。

带有本地时区的时间戳

它被隐式转换为 timestamp with time zone,然后 It Just Works™。同样,a_horse_with_no_name 就在这里。

时间戳

虽然它也被隐式转换为 timestamp with time zone,但默认分配的时区是 session 时区(而不是 数据库时区)。

  • 对此的显式调用是myTimestamp at local
  • 或者(而且很可能更好),您可以按照 Madhawas 所说的进行操作,并使用 from_tz 函数显式构建一个具有明确时区而非会话时区的值。李>

日期

如您所述,尝试在 date 之前执行上述任何操作都会失败:

  • myTimestamp at time zone 'UTC'
    ORA-30084:具有时区修饰符的日期时间主数据类型无效

  • from_tz(myTimestamp, 'America/New_York')
    ORA-00932:不一致的数据类型:预期 TIMESTAMP 得到 DATE

这里的解决方案是先将日期转换为时间戳

select from_tz(cast(myTimestamp as timestamp), 'America/New_York') from tableA

示例脚本

以下脚本说明了该行为。请注意,在我的系统上,dbtimezone 是美国/中部,sessiontimezone 是 GMT-05:00。

我还使用to_char 来转换输出,因为我发现一些工具会以微妙的方式改变结果时间戳,特别是如果它们没有良好的时间戳支持(现在这种情况很少见,但仍然可能是个问题) .

alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'
/
alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS'
/
alter session set nls_timestamp_tz_format = 'YYYY-MM-DD HH24:MI:SS TZR'
/

select dbtimezone
      ,sessiontimezone
      ,to_char(timestamp '2017-01-01 06:00:00') as ts
      ,to_char(timestamp '2017-01-01 06:00:00' at local) as ts_at_local
      ,to_char(timestamp '2017-01-01 06:00:00' at time zone dbtimezone) as ts_at_db
      ,to_char(timestamp '2017-01-01 06:00:00' at time zone sessiontimezone) as ts_at_session
 from dual
/

我系统上的输出如下(为了便于阅读,重新格式化为柱状):

DBTIMEZONE          US/Central
SESSIONTIMEZONE     -05:00
TS                  2017-01-01 06:00:00
TS_AT_LOCAL         2017-01-01 06:00:00 -05:00
TS_AT_DB            2017-01-01 05:00:00 US/CENTRAL
TS_AT_SESSION       2017-01-01 06:00:00 -05:00

【讨论】:

  • 我不知道为什么我有一个包含时间的日期类型,但它确实如此我的下一个问题是...将日期转换为 dateTime 会覆盖我变量的时间部分,将其重置为00:00:00?
  • @Fearghal - Oracle 的date 类型有一个时间组件,所以这是完全正常的。投射到timestamp 将保留该时间。 (虽然小数秒部分将为零)。这很容易测试:select cast(sysdate as timestamp) from dual.
  • 哦,好的,我看到了一个问题,我想我错过了描述这个问题。上述解决方案将日期与时区联系起来。现在我还需要做一件事;将时间更改为UTC?例如,如果时间是 PDT 凌晨 1 点(UTC-7 小时),我希望这个时间是 UTC 早上 8 点
  • 我知道这已经完全过时了,但是@cdonnellytx,您是否有以下文档的参考资料?虽然它也隐式转换为带时区的时间戳,但默认分配的时区是会话时区(与数据库时区相反)。我找不到说使用“会话”时区的文档(这不是我在测试中看到的,我看到正在使用 UTC)
  • @ChrisR.Donnelly,感谢您的回复。使用 SQL 开发人员,无论是 dbtimezone 还是 sessiontimezone,我都看到时区数据的值完全相同。即使是列数据的转储也会产生日期时间组件的数据,完全独立于时区。我发现当我从实际客户端检索数据时,我得到的是相同的东西,时区独立数据。 (仅供参考,我为您和将来可能偶然发现此问题的任何人所看到的内容)
【解决方案3】:

你需要知道你的时区;

SELECT myTimeStamp, from_tz(myTimeStamp, 'America/New_York') AT TIME ZONE 'UTC' utc FROM dual;

【讨论】:

  • 您需要在 from_tz 调用中使用 cast(myTimeStamp as timestamp),因为它是 date
  • 上述解决方案会将日期与时区联系起来。现在我还需要做一件事;将时间更改为UTC?例如,如果时间是 PDT 凌晨 1 点(UTC-7 小时),我希望这个时间是 UTC 早上 8 点
  • @Fearghal - 这是调整时间。 from_tz() 将日期与时区联系起来,在本例中为 EST/EDT; 'at time zone 'UTC'` 正在将时间转换为 UTC。只要您知道日期最初来自哪个时区,这就是您所说的需要。对于评论来说,这确实是太多的代码,但是:select from_tz(cast(to_date('2014-03-27 01:00', 'YYYY-MM-DD HH24:MI') as timestamp), 'America/Los_Angeles') at time zone 'UTC' from dual 给出了27-MAR-14 08.00.00.000000 UTC。如果这不是你的意思,你需要扩展你的问题。
【解决方案4】:

从 Oracle 19c 开始,引入了一个新功能,即TO_UTC_TIMESTAMP_TZ

SQL 函数 TO_UTC_TIMESTAMP_TZ 采用 ISO 8601 日期格式 string 作为 varchar 输入并返回 SQL 数据类型的实例 带有时区的时间戳。它将输入标准化为 UTC 时间 (协调世界时,原格林威治标准时间)。与 SQL 不同 函数 TO_TIMESTAMP_TZ ,新函数假定输入 字符串使用 ISO 8601 日期格式,默认时区为 UTC 0.

select TO_UTC_TIMESTAMP_TZ ( to_char(sysdate,'yyyy-mm-dd"T"HH:MI:SS') )  as utc 
   from dual;

 UTC
31-MAR-19 05.45.36.000000 AM +00:00

【讨论】:

    猜你喜欢
    • 2018-09-17
    • 2019-08-15
    • 2015-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-27
    相关资源
    最近更新 更多