即时与 ZonedDateTime

Posted

技术标签:

【中文标题】即时与 ZonedDateTime【英文标题】:Instant vs 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 只要设置了时区就可以采取任何措施,但我们为什么要关心呢?


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

【问题讨论】:

【参考方案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 不合适。

【讨论】:

以上是关于即时与 ZonedDateTime的主要内容,如果未能解决你的问题,请参考以下文章

谷歌钱包即时购买与应用内购买

即时定位与地图构建(SLAM)与基于视觉的SLAM(VSLAM)

用于动画模型的 OpenGL 即时模式与 VBO

Veeam Backup 11 即时与快速恢复

Veeam Backup 11 即时与快速恢复

Socket搭建即时通讯服务器