【问题标题】:Instant vs ZonedDateTime即时与 ZonedDateTime
【发布时间】:2019-03-12 10:34:56
【问题描述】:

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

我们有一个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;
}

@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 只要设置了时区就可以采取任何措施,但我们为什么要关心呢?


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

【问题讨论】:

    标签: postgresql utc timestamp-with-timezone zoneddatetime java.time.instant


    【解决方案1】:

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

    What's the difference between Instant and LocalDateTime?

    简短的总结: Instant 和 ZonedDateTime 类(以及 OffsetDateTime) 代表同一件事:时间的片刻。不同之处在于 ZonedDateTime 和 OffsetDateTime 提供额外的上下文和功能 关于时区或时间偏移,而 Instant 没有时区或 指定的偏移量。这可能会导致差异,尤其是在涉及夏令时时。比如下面的sn-p代码:

        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 不合适。

    【讨论】:

      猜你喜欢
      • 2021-07-25
      • 2018-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-31
      • 2017-10-15
      • 2019-03-12
      相关资源
      最近更新 更多