4

我想代表一个“营业日期”,例如“2019 年 6 月 3 日”发生的交易。为此,我们积极忽略时区,因为完全知道日本的“2019 年 6 月 3 日”可能是美国的“2019 年 6 月 2 日”——在“当天”内订购同样无关紧要。所有日期都将是今天或之前的日期。

我的明显答案是,这是一个LocalDate. 但是,其他人建议将其更好地表示为Instantof 2019-06-03T00:00:00.000Z

除了在 UI 中将其转换/格式化为人类可读日期时我们必须进行的不同调用之外,这两种方法之间实际上有什么区别吗?

这是一个不同的问题Instant 和 LocalDateTime 之间有什么区别?因为时间与这个问题无关,它只与过去(或当前)日期有关。

4

2 回答 2

9

我曾经在一个产品上工作过,我们犯了将出生日期表示为瞬间的错误。

这是我们多年后仍在处理的那些“微小”设计错误之一。

问题是当用户更改时区时,您无法在 UI 中可靠地显示它;在后端进行转换很容易出错,因为开发人员在与服务器运行的不同时区工作。它有点在一个时区工作,但随着产品扩展到其他时区,它变得非常头疼。

瞬间是时间线上的一个点;本地日期是一个时间范围(而不是一个明确定义的时间范围,因为它可以表示不同时区的不同瞬间范围)。它们代表不同的事物。

如果要表示日期,请存储 date。我不是说 a java.util.Date,它实际上是一个瞬间。

使用LocalDate.

于 2019-06-03T09:54:15.630 回答
5

LocalDate可能模棱两可

安迪·特纳的答案是正确且有价值的。另外,我想指出LocalDate.

该类LocalDate表示仅日期值,没有时间,没有时区。对于任何给定的时刻,日期在全球范围内因时区而异。在某个特定时刻,在日本东京可能是“明天”,而在美国俄亥俄州托莱多可能是“昨天”。两个不同的日期在同一时刻生效。

因此,虽然您可能认为日期包含 24 小时,定义了特定的时刻范围,但事实并非如此。您必须将日期放在时区的上下文中才能确定时刻。(顺便说一句,日子并不总是 24 小时。)

LocalDate localDate = LocalDate.of( 2021 , Month.JANUARY , 24 ) ;
ZoneId zoneTokyo = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime startOfDayTokyo = localDate.atStartOfDay( zoneTokyo ) ;  // Determine a specific moment. 

startOfDayTokyo.toString(): 2021-01-24T00:00+09:00[亚洲/东京]

要在 UTC 中查看同一时刻,请提取一个Instant对象。

Instant instant = startOfDayTokyo.toInstant() ;

请注意,日期是 23 日而不是 24 日。

即时.toString(): 2021-01-23T15:00:00Z

通过第三个挂钟时间查看同一时刻,即美国俄亥俄州托莱多时区的时刻America/New_York

ZonedDateTime zdtToledo = instant.atZone( ZoneId.of( "America/New_York" ) ) ;

请注意,日期是 23 日而不是 24 日。

zdtToledo.toString(): 2021-01-23T10:00-05:00[美国/纽约]

请参阅在 IdeOne.com 上实时运行的代码。

因此,在存储 a 时LocalDate,您可能还想存储时区名称。在数据库表中,这意味着两列。

例如,想想生日。如果知道某人当天的年龄至关重要,那么仅日期值是不够的。只有一个约会,一个在日本东京看起来年满 18 岁的人在美国俄亥俄州托莱多仍然是 17 岁。作为另一个例子,考虑合同中的到期日。如果仅表示日期,日本的利益相关者将认为任务过期,而托莱多的另一利益相关者将任务视为准时。

相反,当您指的是时间线上的特定点时,请使用Instant(或OffsetDateTimeZonedDateTime)。


Java 中的日期时间类型表,包括现代和传统。

于 2020-06-10T15:28:09.813 回答