【问题标题】:Is Oracle db able to compare timestamps with different timezones?Oracle db 是否能够比较不同时区的时间戳?
【发布时间】:2017-05-13 05:48:24
【问题描述】:

我想知道 Oracle 是否能够比较不同时区的日期,例如:

12/26/2016 3:58:16.491476 AM -06:00 > 12/26/2016 3:58:16.491476 AM +05:00

顺便说一句,我正在使用 JPA 进行此比较,其想法是查找一小时前创建的所有行。

我发现我可能可以使用 After 关键字来查找它(即 findMeasureDateAfter)

【问题讨论】:

  • 这是一个类似问题的答案,希望对Oracle comparing timestamp有帮助
  • 截断不能解决问题,因为我需要确保返回的唯一行是在一小时前创建的。
  • 答案是肯定的:TIMESTAMP WITH TIME ZONE 值的所有操作和比较都是在 UTC 时间在内部完成的,即它们被隐式转换以进行计算。

标签: java spring oracle date spring-data-jpa


【解决方案1】:

在 Oracle 中检查非常容易。答案是肯定的。请注意,在下图中,输出显示了使用我会话的 NLS 设置的时间戳(我不想更改它们)。

with
     inputs ( ts1, ts2 ) as (
       select to_timestamp_tz('12/26/2016 3:58:16.491476 AM -06:00',
                              'mm/dd/yyyy hh:mi:ss.ff AM TZH:TZM'),
              to_timestamp_tz('12/26/2016 3:58:16.491476 AM +05:00', 
                              'mm/dd/yyyy hh:mi:ss.ff AM TZH:TZM') from dual
     )
select ts1, ts2, case when ts1 > ts2 then 'ts1 > ts2' 
                      when ts1 = ts2 then 'ts1 = ts2'
                      when ts1 < ts2 then 'ts1 < ts2'
                 end as comparison,
       ts1 - ts2 as difference
from inputs
;

TS1                           TS2                           COMPARISON DIFFERENCE
----------------------------- ----------------------------- ---------- -------------------
26-DEC-16 03.58.16.491 AM -06 26-DEC-16 03.58.16.491 AM +05 ts1 > ts2  +00 11:00:00.000000

如果您基于这样的谓词从 Oracle 表中提取数据,最好在数据库中完成这项工作 - 因此在 Java 中如何完成是无关紧要的。 (您当然不想获取所有行,只是在检查 Java 中的时间戳后忽略其中的大部分。)当然,如果您需要“最后一小时”,您可以与 systimestamp - 1/24 进行比较。

【讨论】:

    【解决方案2】:

    ISO 8601

    首先,如果这些输入实际上是问题中显示的字符串,请尽可能使用标准的ISO 8601 格式。标准格式对人类来说是直观的,并且更容易被计算机解析。事实上,java.time 类在解析/生成字符串时默认使用 ISO 8601 格式。

    java.time

    虽然我不了解 Oracle 中的查询(我自己是 Postgres 人),但我可以展示如何在 Java 端更多地形成查询。

    理想情况下,我们会将输入字符串解析为OffsetDateTime,因为它缺少时区指示,只有与UTC 的偏移量。区域是一个偏移量加上一组用于处理异常情况的规则,例如夏令时 (DST)。时区以continent/region 的格式命名,例如America/Montreal

    不幸的是,Java 8 中的 java.time 实现在解析 DateTimeFormatter 类中的 offset-from-UTC 方面存在一些错误。所以在 Java 9 之前,这里有一些 hack 代码可以解析为 ZonedDateTime 并转换为更合适的 OffsetDateTime

    String input = "12/26/2016 3:58:16.491476 AM -06:00";
    DateTimeFormatter f = DateTimeFormatter.ofPattern ( "MM/dd/uuuu h:m:s.SSSSSS a z" , Locale.ENGLISH );
    OffsetDateTime odt = ZonedDateTime.parse ( input , f ).toOffsetDateTime ();
    

    odt.toString(): 2016-12-26T03:58:16.491476-06:00

    重复你的结束时刻。

    如果您的 JDBC 驱动程序支持 JDBC 4.2 或更高版本,您可以直接通过 PreparedStatement::setObject 传递这些 java.time 类型。

    如果不是,则转换为 java.sql 类型。要进行转换,请查看添加到旧类的新方法。 from 方法采用 Instant,这是 UTC 时间线上的一个时刻。您可以将Instant 视为去除了偏移量的OffsetDateTime。调用OffsetDateTime::toInstant 提取Instant

    java.sql.Timestamp ts = java.sql.Timestamp.from( odt.toInstant() ) ;
    

    在您的开始和结束时刻都这样做。将这些 java.sql.Timestamp 对象传递给您的 PreparedStatement


    关于java.time

    java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

    Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

    要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

    从哪里获得 java.time 类?

    ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

    【讨论】:

      猜你喜欢
      • 2017-06-24
      • 2020-12-07
      • 1970-01-01
      • 2012-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-10
      • 1970-01-01
      相关资源
      最近更新 更多