java.time.LocalDate vs Instant一个“营业日期”

时间:2019-06-03 09:32:07

标签: java java.time.instant java.time

我想代表一个“营业日”,例如发生在“ 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?不同的问题,因为时间与该问题无关,并且仅与过去(或当前)日期有关。

2 个答案:

答案 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(或OffsetDateTimeZonedDateTime)。


Table of date-time types in Java, both modern and legacy.