即时与 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,所以我应该可以使用 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
只要设置了时区就可以采取任何措施,但我们为什么要关心呢?
那么两者中哪一个是更好的选择,我为什么要选择一个而不是另一个?
【问题讨论】:
【参考方案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的主要内容,如果未能解决你的问题,请参考以下文章