即时与ZonedDateTime

dis*_*ame 6 postgresql utc timestamp-with-timezone zoneddatetime java.time.instant

我只是不太了解在以下示例中应该使用这两个中的哪一个:

我们有OfferEntity一个成员availableDay,该成员是要约可用的日期。

现在,该表将如下所示:

CREATE TABLE IF NOT EXISTS offer (
  created   timestamp with time zone NOT NULL DEFAULT NOW(),
  id        BIGSERIAL PRIMARY KEY,
  available timestamp with time zone
);
Run Code Online (Sandbox Code Playgroud)

PostgreSQL文档中我们知道:

对于timestamp with time zone,内部存储的值始终以UTC(通用协调时间,通常称为格林威治标准时间,GMT)表示。使用该时区的适当偏移量,将指定了明确时区的输入值转换为UTC。如果在输入字符串中未指定时区,则假定该时区位于系统TimeZone参数指示的时区中,并使用时区的偏移量将其转换为UTC。

这意味着在保留任何日期/时间信息时我应该没问题。

但这对我OfferEntity和我定义的REST端点意味着什么OfferController

@Entity
@Table(name = "offer")
public class OfferEntity {    
    @Column(name = "available", nullable = false)
    private ZonedDateTime availableDay;
}
Run Code Online (Sandbox Code Playgroud)

@Entity
@Table(name = "offer")
public class OfferEntity {    
    @Column(name = "available", nullable = false)
    private Instant availableDay;
}
Run Code Online (Sandbox Code Playgroud)

据我了解-这不会有所作为。PostgreSQL无论如何都将所有内容存储为UTC,所以我应该可以接受Instant还是ZonedDateTime正确?写点东西-> UTC。再次阅读->仍然是UTC。

甚至客户也无法分辨出区别:

@RequestMapping(value = "/hello", method = RequestMethod.GET)
public Object hello() {

    class Hello {
        public Instant instant = Instant.now();
        public ZonedDateTime zonedDateTime = ZonedDateTime.now();
        public ZonedDateTime viennaTime = ZonedDateTime.now(ZoneId.of("GMT+2"));
        public LocalDateTime localDateTime = LocalDateTime.now();
    }

    return new Hello();
}
Run Code Online (Sandbox Code Playgroud)

将返回:

{
  "instant":       "2018-10-07T15:30:08.579Z",
  "zonedDateTime": "2018-10-07T15:30:08.579Z",
  "viennaTime":    "2018-10-07T17:30:08.579+02:00",
  "localDateTime": "2018-10-07T15:30:08.579",
}
Run Code Online (Sandbox Code Playgroud)

但是必须存在一个关键的区别,我显然没有看到。


我有两个区别。看来Spring转换"2018-10-07T15:30:08.579Z"Instant对象没有问题,但是如果我将类型更改为,则这样做失败ZonedDateTime。至少开箱即用。

{
  "instant":       "2018-10-07T15:30:08.579Z",
  "zonedDateTime": "2018-10-07T15:30:08.579Z",
  "viennaTime":    "2018-10-07T17:30:08.579+02:00",
  "localDateTime": "2018-10-07T15:30:08.579",
}
Run Code Online (Sandbox Code Playgroud)

另一个区别是这样一个事实,即如果我使用的话,我将Instant迫使我的客户首先将其所有日期/时间字符串转换为UTC。因此,任何客户都必须myDate.toUTCString()首先。ZonedDateTime只要设置了时区,它将花费任何时间,但是我们为什么要关心呢?


那么,哪两个是更好的选择,为什么我要选择一个呢?

Joo*_*gts 11

以下链接中的答案比我以往任何时候都更好地解释了它。答案涉及 Java 中所有不同的日期/时间类,以及它们与 sql 类型的关系。

Instant 和 LocalDateTime 有什么区别?

简短摘要:类 Instant 和 ZonedDateTime(以及 OffsetDateTime)代表相同的事物:时间。不同之处在于 ZonedDateTime 和 OffsetDateTime 提供有关时区或时间偏移的额外上下文和功能,而 Instant 没有指定时区或偏移。这可能会导致差异,尤其是在涉及夏令时时。例如,采用以下代码片段:

    ZonedDateTime z1 = zonedDateTime.of(LocalDateTime.of(2019,10,26,6,0,0),ZoneId.of("Europe/Amsterdam"));
    Instant i1 = z1.plus(1,ChronoUnit.DAYS).toInstant();
    Instant i2 = z1.toInstant().plus(1,ChronoUnit.DAYS);
    System.out.println(i1);
    System.out.println(i2);
Run Code Online (Sandbox Code Playgroud)

结果将是这样的:

    2019-10-27T05:00:00Z
    2019-10-27T04:00:00Z
Run Code Online (Sandbox Code Playgroud)

差异源于这样一个事实,即在阿姆斯特丹时区,10 月 27 日有一个额外的小时。当我们转换为 Instant 时,时区信息会丢失,因此添加一天只会添加 24 小时。

LocalDateTime 是一个不同的野兽。它表示没有时区信息的日期和时间。它并没有在时间代表了一会儿。这对于编写诸如“圣诞节早上从 12 月 25 日 00:00:00 开始”之类的内容很有用。无论时区如何,这都是正确的,因此 ZonedDateTime 或 Instant 不合适。