我想代表一个“营业日”,例如发生在“ 2019年6月3日”的交易。我们完全为此目的而积极地忽略了时区,因为我们完全知道日本的“ 2019年6月3日”可能是美国的“ 2019年6月2日”,因此“天”内的订购同样无关紧要。所有日期都是今天或以前的日期。
我的明显答案是这是一个LocalDate
。但是,有人建议将其更好地表示为Instant
中的2019-06-03T00:00:00.000Z
。
除了在UI中将其转换/格式化为人类可读的日期时需要进行的各种调用之外,这两种方法之间实际上是否存在差异?
这是与What's the difference between Instant and LocalDateTime?不同的问题,因为时间与该问题无关,并且仅与过去(或当前)日期有关。
答案 0 :(得分:4)
我曾经在一个产品上工作过,但我们错误地将生日表示为一个生日。
这是我们几年后仍在处理的“微小”设计错误之一。
问题在于,随着用户更改时区,您无法在UI中可靠地显示它;由于开发人员在服务器运行所在的不同时区工作,因此在后端进行转换很容易出错。它虽然可以在一个时区工作,但是随着产品扩展到其他时区,这完全让人头疼。
瞬间是时间线上的点;本地日期是时间的范围(而不是明确定义的时间范围,从某种意义上讲,它可以表示不同时区的不同时刻范围)。它们代表不同的事物。
如果要表示日期,请存储日期。我并不是说java.util.Date
,这确实是一个瞬间。
使用LocalDate
。
答案 1 :(得分:4)
LocalDate
可能不明确 Answer by Andy Turner是正确且有价值的。另外,我想指出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日。
instant.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 [美国/纽约]
请参见此代码run live at IdeOne.com。
因此,在存储LocalDate
时,您可能还需要存储时区名称。在数据库表中,这意味着两列。
举个例子,想想生日。如果知道某人的年龄直到今天至关重要,那么仅日期的值是不够的。只需约会,在日本东京看来年满18岁的人在美国俄亥俄州托莱多仍将17岁。再举一个例子,考虑合同中的到期日。如果只说日期,日本的利益相关者将认为任务已逾期,而托莱多的另一利益相关者则将任务视为准时。
相反,当您指的是时间轴上的特定时刻时,请使用Instant
(或OffsetDateTime
或ZonedDateTime
)。