【问题标题】:Storing time zone offset in Oracle DB as separate field将 Oracle DB 中的时区偏移存储为单独的字段
【发布时间】:2017-11-09 20:31:49
【问题描述】:

我正在开发航空 Java 应用程序,需要在 Oracle DB 中存储本地时间和时区信息。

DATE/TIMESTAMP 类型的问题比 WITH TIME ZONE 类似。

如果我将本地日期存储在 DATE 字段中,我应该为 Oracle DB 和 Java/Hibernate 映射中的单独字段分配什么类型的偏移量?我希望日期算术在 Java 和 Oracle 原生 SQL 查询中都很容易。

我只能成像INT(6) 以将偏移量存储为秒。原生 Oracle SQL 查询可以使用算术运算:

departure_date + departure_off/(24*60*60)

在 Java 中:

departureDate.atOffset(ZoneOffset.ofTotalSeconds(departureOff))

更新我没有 TZ 地区的信息,例如“美国/太平洋”,只有数字偏移量。

【问题讨论】:

  • 为什么你认为 DATE/TIMESTAMP 类型的问题更少?
  • @WernfriedDomscheit 看看tonyhasler.wordpress.com/2010/09/04/…
  • 看了这篇博客,主要列出了一些性能问题。请记住,如果您必须在查询中运行与时区相关的偏移量计算,那么您可能会取消使用 DATE/TIMESTAMP 类型获得的性能提升
  • 您打算如何处理夏令时?
  • 我不需要处理夏令时。出发事件发生在特定时间,外部系统提供时间/TZ 信息。我只需要保留这些信息并进行范围选择。

标签: java oracle hibernate timezone timezone-offset


【解决方案1】:

我首先建议使用TIMESTAMP WITH TIME ZONE,分别。 TIMESTAMP WITH LOCAL TIME ZONE,我认为这是最简单的方法。

否则我会按照 ISO-8601 存储时区偏移量,即 VARCHAR(6) 值,如 +05:00

然后就可以很简单的转换成TIMESTAMP WITH TIME ZONElike

SELECT FROM_TZ(departure_date, departure_off)
FROM ...

【讨论】:

    【解决方案2】:

    不要。将所有时间转换为公共时区(即 UTC),然后,当前端想要在其本地时区显示它时,它可以从 UTC 转换回来。

    INSERT INTO your_table ( departure_date )
    VALUES (
      FROM_TZ(
        CAST( :your_date AS TIMESTAMP ),
        TO_CHAR( TRUNC( :your_offset / 60 ), 'FMS00' )
          || ':' || TO_CHAR( MOD( :your_offset, 60 ), 'FM00' )
      ) AT TIME ZONE 'UTC'
    );
    

    或者你可以使用TIMESTAMP WITH TIME ZONE

    CREATE TABLE departures (
      departure_date   TIMESTAMP WITH TIME ZONE
    );
    
    INSERT INTO your_table ( departure_date )
    VALUES (
      FROM_TZ(
        CAST( :your_date AS TIMESTAMP ),
        TO_CHAR( TRUNC( :your_offset / 60 ), 'FMS00' )
          || ':' || TO_CHAR( MOD( :your_offset, 60 ), 'FM00' )
      )
    );
    

    但是,如果您真的想分别存储日期和偏移量,请使用INTERVAL DAY TO SECOND

    CREATE TABLE departures (
      departure_date   DATE,
      departure_offset INTERVAL DAY TO SECOND
    );
    
    INSERT INTO departures VALUES (
      :your_date,
      NUMTODSINTERVAL( :your_offset, 'SECOND' )
    );
    

    【讨论】:

    • 将所有时间转换为公共时区(即 UTC),然后,当前端想要在其本地时区显示它时,它可以从 UTC 转换回来。 - 这实际上是TIMESTAMP WITH LOCAL TIME ZONE 的工作原理。唯一的区别是:它使用DBTIMEZONE(当然可以设置为UTC)而不是UTC
    猜你喜欢
    • 2023-03-25
    • 1970-01-01
    • 2015-08-17
    • 2016-10-30
    • 2019-03-31
    • 1970-01-01
    • 2021-06-29
    • 2020-12-07
    • 2022-06-28
    相关资源
    最近更新 更多