数据库中的UTC时间,其类型是“没有时区的时间戳”#39;在UTC中显示响应

时间:2018-06-06 10:29:26

标签: java postgresql hibernate timezone utc

我在postgres中有一个字段,其类型为"时间戳没有时区"。 我希望在API响应中显示数据库中的UTC时间。

我使用以下代码在相同的UTC时区显示它,但它在API响应中添加了我的本地时间偏移量 -

// date from db in UTC is 2018-06-06 09:59:04.103
Date createdDateTime = description.getCreatedDateTime();
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
try {
        Date date = isoFormat.parse(createdDateTime.toString());
        description.setCreatedDateTime(date);
        } catch (ParseException e) {
            LOGGER.error("An exception has occured in parsing .", e);
        }

我在IST的创作时间 - 2018-06-06 15:16:04.103 IST 我仍然得到带有偏移量的输出: Jun 6, 2018 8:46:52 PM

我正在使用hibernate从表中获取数据。

2 个答案:

答案 0 :(得分:0)

此列类型应返回Java中的Timestamp类型(或带有JDBC 4.2+的LocalDateTime)。该时间戳将包含原始日期,但在您的默认时区中。所以你需要对它应用UTC时区。

java.sql.Timestamp t = ...;
ZonedDateTime zdt = t.toLocalDateTime() //remove time zone information
                     .atZone(ZoneOffset.UTC); //this is actually a UTC time

此时,您可以继续使用java.time个对象(如果可以的话,没有理由不这样做),或者您可以将ZonedDateTime转换为java.util.Date

java.util.Date date = Date.from(zdt.toInstant());

答案 1 :(得分:0)

java.util.Date::toString适用区域

您可能会对java.util.Date::toString方法的善意但不幸的设计决定感到困惑,即动态应用JVM当前的默认时区,同时生成一个String来表示Date的值实际上,按照定义,它始终是UTC。 许多的原因之一是避免这个非常麻烦的老班。

数据库中的数据类型错误

  

我在postgres中有一个字段,其类型是“没有时区的时间戳”。我希望在API响应中显示数据库中的UTC时间。

这是一个矛盾。 SQL标准TIMESTAMP WITHOUT TIME ZONE列不包含UTC值。该数据类型缺少任何时区概念或从UTC偏移。 (此类UTC值应该存储在TIMESTAMP WITH TIME ZONE类型的列中。)

您插入的值可能是用于的UTC,但是一旦存储到数据库,您就会丢失该事实。

java.time

避免java.sql.Timestamp

没有需要使用java.sql.Timestamp。应该避免遗留类。从JDBC 4.2及更高版本开始,我们可以直接与数据库交换 java.time 类型。 Hibernate supports java.time

LocalDateTime

缺少任何区域/偏移量,您应该使用LocalDateTime类检索这些值。该类还缺少任何时区概念或从UTC偏移。

LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;

OffsetDateTime

如果您想假设检索到的值表示UTC时刻,请应用ZoneOffset获取OffsetDateTime个对象。对于UTC,我们可以使用预定义的常量ZoneOffset.UTC

OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ;

不是ZonedDateTime

虽然ZonedDateTime类在技术上可以代替OffsetDateTime类,但它的使用是不合适的。

时区不仅仅是一个偏移量。区域是特定区域的人员使用的偏移的过去,现在和将来的变化的历史。相比之下,从UTC的偏移量仅仅是几小时和几分钟,仅此而已。

因此,在此UTC上下文中使用ZonedDateTime会产生误导,并可能造成混淆。

Instant

现在,在您的OffsetDateTime对象中,您有一个UTC时刻。

如果您知道您只想从那里开始使用UTC,请提取Instant。根据定义,Instant始终为UTC。以UTC表示时刻时,通常使用Instant。如果您需要更多灵活性,例如以各种格式生成字符串,请切换到使用OffsetDateTime

Instant instant = odt.toInstant() ;

关于 java.time

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

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

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

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

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore