即时与ZonedDateTime

时间:2018-10-07 16:44:07

标签: 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
);

PostgreSQL docs我们知道:

  

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

这表示在保留任何日期/时间信息时我应该没事。

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

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

vs

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

据我了解-这不会有所作为。 PostgreSQL无论如何都将所有内容存储为UTC,所以我应该能够使用InstantZonedDateTime对吗?写点东西-> 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();
}

会返回:

{
  "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",
}

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


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

@RequestMapping("/places/{placeId}/offers", method = RequestMethod.GET)
public List<OfferDto> getOffers(
        @PathVariable(name = "placeId") Long placeId,
        @RequestParam(name = "date") ZonedDateTime date) {
    return this.offerService.getOffers(placeId, date);
}

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


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

1 个答案:

答案 0 :(得分:0)

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

What's the difference between Instant and LocalDateTime?

简短摘要: 类Instant和ZonedDateTime(以及OffsetDateTime) 代表同一件事:片刻。区别在于 ZonedDateTime和OffsetDateTime提供额外的上下文和功能 关于时区或时区偏移,而“即时”没有时区或 指定的偏移量。这可能会导致差异,尤其是在涉及夏时制的情况下。例如,采用以下代码段:

    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);

结果将是这样:

    2019-10-27T05:00:00Z
    2019-10-27T04:00:00Z

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

LocalDateTime完全是另一种野兽。它代表一个日期 和时间,没有时区信息。它代表 这一刻。对于写“圣诞节”之类的东西很有用 早上从12月25日00:00:00开始。 时区,因此ZonedDateTime或Instant不适合。