类型为 'timestamp without timezone' 的数据库中的 UTC 时间以 UTC 显示作为响应

UTC time in database whose type is 'timestamp without timezone' to show in UTC in response

我在 postgres 中有一个类型为 "timestamp without timezone" 的字段。 这是我想在 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

我正在使用休眠从 table 获取数据。

此列类型应 return Timestamp 键入 Java(或 LocalDateTime 和 JDBC 4.2+)。该时间戳将包含原始日期,但在您的默认时区中。因此,您需要为其应用 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());

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

您可能对 java.util.Date::toString 方法的善意但不幸的设计决策感到困惑,该方法动态应用 JVM 当前的默认时区,同时生成一个字符串来表示 Date 根据定义,它实际上总是在 UTC 中。 许多 原因之一,以避免这个非常麻烦的旧 class。

数据库中的数据类型错误

I have a field in postgres whose type is "timestamp without timezone". It is UTC time in database which I want to show in API response.

这是一种自相矛盾的说法。 SQL-标准 TIMESTAMP WITHOUT TIME ZONE 列不包含 UTC 值。该数据类型缺少任何时区或与 UTC 的偏移量的概念。 (这样的 UTC 值应该存储在 TIMESTAMP WITH TIME ZONE 类型的列中。)

您插入的值可能 预期 用于 UTC,但一旦存储到数据库中,您就失去了这一事实。

java.time

避免java.sql.Timestamp

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

LocalDateTime

缺少任何 zone/offset,您应该使用 LocalDateTime class 检索这些值。 class 也缺少任何时区或与 UTC 的偏移量的概念。

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

OffsetDateTime

如果您想假设检索到的值代表 UTC 中的一个时刻,请应用 ZoneOffset to get a OffsetDateTime object. For UTC specifically, we can use the predefined constant ZoneOffset.UTC.

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

不是ZonedDateTime

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

时区不仅仅是偏移量。区域是特定区域的人们使用的偏移的过去、现在和未来变化的历史。相比之下,与 UTC 的偏移量仅仅是小时数和分钟数,仅此而已。

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

Instant

现在,在您的 OffsetDateTime 对象中,您有时间使用 UTC。

如果您知道自己只想在 UTC 中工作,请提取 Instant。根据定义,Instant 始终采用 UTC。在用UTC表示时刻时,一般使用Instant。如果您需要更大的灵活性,例如生成各种格式的字符串,请切换到使用 OffsetDateTime

Instant instant = odt.toInstant() ;

关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

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

从哪里获得java.time classes?

ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.