【问题标题】:How to get the timezone ID from Oracle instead timezone offset如何从 Oracle 获取时区 ID 而不是时区偏移
【发布时间】:2021-01-13 05:00:17
【问题描述】:

有没有办法从 oracle 获取时区 id 而不是时区偏移量? 当我执行SELECT SYSTIMESTAMP AS TIMEZONE FROM DUAL; 时,返回的结果是13-JAN-21 10.19.52.936031000 AM +05:30

当我使用 rs.getObject( "TIMEZONE ", ZonedDateTime.class ) 从 Java 中检索它时,ZonedDateTime 对象将 offsetzoneID 都设置为 +05:30

但我希望看到的是,SELECT SYSTIMESTAMP AS TIMEZONE FROM DUAL; 应该返回 04-JAN-21 02.40.50.000000000 PM ASIA/COLOMBO 并且查询的 Java ZonedDateTime 应该将 offset 设置为 +05:30 并将 zoneID 设置为 Asia/Colombo

有没有办法在 DB 级别或 Java 级别进行设置?当前DBTIMEZONE 设置为+05:30

【问题讨论】:

标签: java oracle timezone


【解决方案1】:

如果数据已经在 Oracle SQL 表中,并且您必须转换为带时区的时间戳(例如,在您在同一张表中创建的新列中),则无需显式转到操作系统,或者使用 Java 或任何其他东西,而不是 Oracle 数据库本身。

从您的问题中不清楚您是否必须假设“日期”是在服务器时区(您提到“数据库”,通常是指服务器)或客户端时区(您提到“会话" 表示客户)。无论哪种方式:

update <your_table>
set <timestamp_with_time_zone_col> = 
            from_tz(cast<date_col> as timestamp, dbtimezone)
;

或者使用 sessiontimezone 作为第二个参数,如果你需要的话。

这假设数据库(和/或会话)时区在数据库中正确设置,分别在客户端中。如果不是/它们不是,则需要先修复。如果首先正确设置参数,Oracle 完全有能力处理日间节省时间。 (如果它们不是,那么您为什么要尝试让您的操作比数据库最初支持的“更正确”呢?)

示例:在下面的 WITH 子句中,我模拟了一个具有数据类型 date 的列 dt 的表。然后我将其转换为带有时区的时间戳,在我的会话(客户端)时区中。

with
  my_table ( dt ) as ( 
    select to_date('2018-06-20 14:30:00', 'yyyy-mm-dd hh24:mi:ss') from dual 
  )
select dt,
       from_tz(cast(dt as timestamp), sessiontimezone) as ts_with_tz
from   my_table
;

DT                  TS_WITH_TZ                                       
------------------- -------------------------------------------------
2018-06-20 14:30:00 2018-06-20 14:30:00.000000000 AMERICA/LOS_ANGELES

参考你可以查看这个链接 StackOverflow Ref. Link

【讨论】:

    【解决方案2】:

    从某种意义上说,你不走运。 SYSTIMESTAMP 只返回您的操作系统报告的内容。时区是托管数据库的计算机系统的时区。它不是数据库时区(可能与数据库实际所在的位置完全无关)或会话时区或类似的东西。如果可以的话,您需要在 db 主机操作系统本身中进行更改。

    如果您确定托管您的数据库的系统在斯里兰卡,那么您可以像这样间接获得您想要的:

    select systimestamp AT TIME ZONE 'ASIA/COLOMBO' from dual;
    

    【讨论】:

      【解决方案3】:

      您可以使用ALTER database 命令在数据库级别设置时区,如下所示:

      alter database set time_zone = '+05:30';
      

      请注意,这将在您重新启动数据库后生效。

      shutdown immediate
      startup
      

      【讨论】:

      • 正如我在问题中所述,SELECT DBTIMEZONE FROM DUAL; 返回+05:30。但我希望这是Asia/Colombo。实际上,我不在乎这个查询返回什么,只要查询 SELECT SYSTIMESTAMP AS TIMEZONE FROM DUAL; retunrs 04-JAN-21 02.40.50.000000000 PM ASIA/COLOMBO 而不是 04-JAN-21 02.40.50.000000000 PM +05:30
      • systimestamp 报告托管数据库的计算机的操作系统的时区。数据库时区与此无关。事实上,我将我的数据库时区设置为 +00:00,由select dbtimezone from dual 确认; systimestamp 的时区为 -08:00,这是我机器上 Unix 操作系统的时区,位于美国西海岸。
      • 更改DBTIMEZONESYSTIMESTAMP 没有影响,请参阅其他答案。
      • 在不创建从偏移量到名称的转换函数的情况下,您将获得所需的高度。您可能想尝试从 v$timezone_names 中选择。问题是具有该偏移量的时区不少于 8 个。见here
      【解决方案4】:

      SYSTIMESTAMP 在数据库操作系统的时区中返回 - 因此无法在数据库中更改它。

      不要将数据库操作系统的时区与DBTIMEZONE 混在一起,它们是不同的。

      另请注意,时区 Asia/Colombo 与时区 +05:30 不同,尽管它们(当前)具有相同的 UTC 偏移量。

      时区Asia/Colombo 考虑夏令时以防万一,它还涵盖changes。例如,Asia/Colombo 在 2006 年从 UTC+06:00 更改为 UTC+05:30。例如,TZ_OFFSET(TIMESTAMP '2020-01-01 12:00:00 Asia/Colombo') 返回的偏移量与 TZ_OFFSET(TIMESTAMP '2000-01-01 12:00:00 Asia/Colombo') 不同。

      时区+05:30总是比世界标准时间早 5:30。

      你的问题不是很清楚,你想得到什么?

      【讨论】:

      • 当我从 Java 查询 rs.getObject( "TIMEZONE ", ZonedDateTime.class 时,我期望得到 ZoneIDZoneOffset。假设列TIMEZONE 具有SYSTIMESTAMP 作为值,那么Java 中的ZonedDateTime 对象将ZoneIDZoneOffset 都设置为+05:30。但我希望 ZoneID 成为 Asia/ColomboZoneOffsetZonedDateTime 对象中成为 +05:30
      • SYSTIMESTAMP 在数据库操作系统的时区中给出,即+05:30。如果您将此值插入表中,那么这就是插入和显示的值 - 句点。如果您想将时区+05:30转换Asia/Colombo,请选择SYSTIMESTAMP AT TIME ZONE 'Asia/Colombo'
      【解决方案5】:

      Oracle TZ_OFFSET() 函数返回有效时区名称或 SESSIONTIMEZONE 或 DBTIMEZONE 函数名称相对于 UTC 的时区偏移量。

      TZ_OFFSET(value)
      

      TZ_OFFSET() 函数接受一个参数,该参数可以是有效的时区名称,例如“Europe/London”、SESSIONTIMEZONE 或 DBTIMEZONE 的函数名称,或与 UTC 的时区偏移量(仅返回自身)。

      SELECT
        TZ_OFFSET( 'Europe/London' )
      FROM
        DUAL;
      

      结果将是 +01:00

      【讨论】:

      • 我想从 ZoneOffset 获取 ZoneID。这提供了另一种方式
      • 已经有两个赞成...对于一个根本没有回答问题的答案(实际上,响应者似乎一开始就没有理解这个问题)。 -1 来自我。
      • 这如何回答这个问题?
      【解决方案6】:

      这是获取时区的方法。

      SELECT systimestamp AS DBTime,
             systimestamp at time zone 'Europe/London',
             systimestamp at time zone 'America/Sao_Paulo'from dual;
      

      SELECT
        TZ_OFFSET( DBTIMEZONE )
      FROM
        DUAL;
      

      【讨论】:

      • 这如何回答 OP 的问题?两个赞成票已经......哇!不过我是-1。
      猜你喜欢
      • 1970-01-01
      • 2021-04-11
      • 2015-06-16
      • 2012-12-06
      • 1970-01-01
      • 2020-04-20
      • 2022-01-21
      • 2016-04-22
      • 2023-03-25
      相关资源
      最近更新 更多