17

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

我们有一个OfferEntitywhich 有一个成员,该成员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 文档中我们知道:

对于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;
}

对比

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

据我了解 - 这不应该有所作为。无论如何,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();
}

将返回:

{
  "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只要设置了时区,就需要任何时间,但我们为什么要关心呢?


那么两者中哪一个是更好的选择,为什么我会选择一个而不是另一个?

4

1 回答 1

17

以下链接中的答案比我以往任何时候都更好地解释了它。答案涉及 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);

结果将是这样的:

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

不同之处在于在阿姆斯特丹时区,10 月 27 日有一个额外的小时。当我们转换为 Instant 时,时区信息会丢失,因此添加一天只会增加 24 小时。

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

于 2019-10-23T09:17:22.503 回答