从 Oracle 中选择 UTC 日期并在 Java 中转换为 UTC

XMi*_*ght 3 java oracle spring timestamp jdbctemplate

如果我在我的应用程序中调用:

System.currentTimeMillis()
Run Code Online (Sandbox Code Playgroud)

结果将是,比方说:1536842771599,:格林威治标准时间:2018 年 9 月 13 日星期四下午 12:46:11.599 或在我当地:2018 年 9 月 13 日星期四下午 3:46:11.599 GMT+03:00

如果我在本地安装的 Oracle 数据库上执行以下选择:

select CAST(sys_extract_utc(SYSTIMESTAMP) AS DATE) from dual;
Run Code Online (Sandbox Code Playgroud)

我通过以下 JdbcTemplate 代码得到:

jdbc.queryForObject(sqlCommand, new Object[0], Timestamp.class);
Run Code Online (Sandbox Code Playgroud)

结果如下: 在此处输入图片说明

在我看来这已经是错误的,因为时间戳通常代表本地化时间。此外,如果我打电话:

myResult.getTime()
Run Code Online (Sandbox Code Playgroud)

要获得 long 值,这会将我的时间(大约下午 12.46 分)转换为值 1536831971599,实际上是:格林威治标准时间:2018 年 9 月 13 日星期四上午 9:46:11.599。

显然这不好,因为它比我的实际本地时间晚 2 * GMT+03:00(6 小时),并且比数据库的 UTC 时间晚 GMT+03:00(3 小时)。

我做错了什么?到目前为止,我唯一的结论是避免在数据库上执行sys_extract_utc并让数据库返回本地时间,当我在 Timestamp 实例上调用 getTime 时,本地时间将转换为 UTC 时间。

对此有什么解释吗?

PS根据java.sql.Timestamp是UTC的答案,我附上了调试器向我显示的截图,哪个是错误的,因为它认为UTC的结果是GMT+03:00。因此,它显示我的时间为 8.26 + 03:00。我的当地时间是 11.26。如果我在 Timestamp 的这个实例上调用 getTime,我将得到一个长值,如果我将它放入https://www.epochconverter.com/然后我得到 2018 年 9 月 14 日星期五上午 8:26:06 GMT+03: 00 DST 或 2018 年 9 月 14 日星期五 5:26:06 AM,这比我实际拥有的 UTC 时间晚了 3 小时!

PS2 我使用 Spring JDBC 4.2.5-RELEASE。不能将 Instant 与它一起使用,它会抛出无法将 Timestamp 转换为 Instant 的异常,因为它需要从 Number 派生的东西。不幸的是,我现在无法更改此 JDBC,甚至是版本。

在此处输入图片说明

Bas*_*que 5

tl;博士

你误解了java.sql.Timestamp课堂。

  • java.sql.Timestamp 始终代表 UTC 中的一个时刻。
  • java.time.Instant年前换的Timestamp

只使用Instant,从不Timestamp

Instant

可怕的java.sql.Timestamp类现在已经被java.time类过时了,特别是Instant.

Instant.now()  // Capture the current moment in UTC. 
Run Code Online (Sandbox Code Playgroud)

JDBC 4.2

从 JDBC 4.2 开始,我们可以直接与数据库交换java.time对象。无需再使用过的可怕的DateCalendar或java.sql中的类。

取回。

Instant instant = myResultSet.getObject( … , Instant.class ) ;
Run Code Online (Sandbox Code Playgroud)

插入。

myPreparedStatement.setObject( … , instant ) ;
Run Code Online (Sandbox Code Playgroud)

时间戳通常表示本地化时间。

不正确。Ajava.sql.Timestamp代表 UTC 中的一个时刻,根据定义,始终是 UTC。同样,Instanttoo 也代表UTC 中的一个时刻。这两个类都表示自 UTC 时间 1970 年的第一个时刻以来的计数。


关于java.time

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

现在处于维护模式Joda-Time项目建议迁移到java.time类。

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

您可以直接与您的数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。java.sql.*

从哪里获得 java.time 类?

ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多