我知道:
最终,IMO 两者都可以作为大多数应用程序用例的类型。例如:目前我正在运行一个批处理作业,我需要根据日期计算下一次运行,我正在努力寻找这两种类型之间的优缺点(除了 Instant 的纳秒精度优势和时区部分)本地日期时间)。
你能说出一些应用程序示例,其中应该只使用 Instant 或 LocalDateTime 吗?
编辑:当心误读 LocalDateTime 有关精度和时区的文档
最佳答案
tl;博士Instant
和 LocalDateTime
是两种完全不同的动物:一种代表片刻,另一种则不代表。
Instant
代表一个时刻,时间线中的一个特定点。 LocalDateTime
表示日期和时间。但缺少时区或UTC偏移量,这个类不能代表片刻 .它代表了大约 26 到 27 小时范围内的潜在时刻,这是全局所有时区的范围。一个 LocalDateTime
值为 本质上模棱两可 . 错误推定
LocalDateTime
is rather date/clock representation including time-zones for humans.
您的说法有误:
LocalDateTime
没有时区 .没有时区是该类(class)的重点。引用该类的文档:
This class does not store or represent a time-zone. Instead, it is a description of the date, as used for birthdays, combined with the local time as seen on a wall clock. It cannot represent an instant on the time-line without additional information such as an offset or time-zone.
所以
Local…
意思是“没有分区,没有偏移”。Instant
安
Instant
是时间线上的一个时刻 UTC ,计数 nanoseconds自 1970 UTC 第一个时刻以来(基本上,请参阅类(class)文档以了解详细信息)。由于您的大部分业务逻辑、数据存储和数据交换都应采用 UTC,因此这是一个经常使用的方便类。Instant instant = Instant.now() ; // Capture the current moment in UTC.
OffsetDateTime
类(class)
OffsetDateTime
类将一个时刻表示为日期和时间,其上下文在 UTC 之前或之后一定数量的小时-分钟-秒。偏移量,即小时-分钟-秒数,由 ZoneOffset
表示类(class)。如果小时-分钟-秒数为零,则
OffsetDateTime
代表 UTC 中的一个时刻,与 Instant
相同.ZoneOffset
ZoneOffset
类代表一个 offset-from-UTC , UTC 之前或之后的小时-分钟-秒数。一个
ZoneOffset
只是几个小时-分钟-秒,仅此而已。一个区域远不止这些,有一个名称和一个要偏移的更改历史。因此,使用区域总是比仅使用偏移更可取。ZoneId
time zone由
ZoneId
表示类(class)。新的一天在 Paris 中更早开始了比Montréal , 例如。所以我们需要移动时钟的指针以更好地反射(reflect)noon (当太阳直接位于头顶时)给定区域。西欧/非洲的UTC线向东/向西越远,偏移量越大。
时区是一组用于处理本地社区或地区实践的调整和异常的规则。最常见的异常是非常流行的疯子,称为 Daylight Saving Time (DST) .
时区具有过去规则、现在规则和为不久的将来确认的规则的历史。
这些规则的变化比您预期的要频繁。确保保留日期时间库的规则,通常是 the 'tz' database 的副本。 , 最新。随着 Oracle 发布 Timezone Updater Tool,在 Java 8 中保持最新状态比以往任何时候都容易.
指定一个 proper time zone name格式为
Continent/Region
,例如 America/Montreal
, Africa/Casablanca
, 或 Pacific/Auckland
.切勿使用 2-4 个字母的缩写,例如 EST
或 IST
因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。Time Zone = Offset + Rules of Adjustments
ZoneId z = ZoneId.of( “Africa/Tunis” ) ;
ZonedDateTime
想想
ZonedDateTime
概念上为 Instant
具有分配的 ZoneId
.ZonedDateTime = ( Instant + ZoneId )
要捕捉特定地区(时区)的人们使用的挂钟时间中看到的当前时刻:
ZonedDateTime zdt = ZonedDateTime.now( z ) ; // Pass a `ZoneId` object such as `ZoneId.of( "Europe/Paris" )`.
几乎所有的后端、数据库、业务逻辑、数据持久性、数据交换都应该使用 UTC。但是为了向用户展示,您需要调整到用户期望的时区。这就是ZonedDateTime
的目的类和 formatter classes用于生成这些日期时间值的字符串表示。ZonedDateTime zdt = instant.atZone( z ) ;
String output = zdt.toString() ; // Standard ISO 8601 format.
您可以使用 DateTimeFormatter
生成本地化格式的文本.DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ) ;
String outputFormatted = zdt.format( f ) ;
mardi 30 avril 2019 à 23 h 22 min 55 s heure de l’Inde
LocalDate
, LocalTime
, LocalDateTime
“本地”日期时间类,
LocalDateTime
, LocalDate
, LocalTime
,是一种不同的小动物。与任何一个地点或时区无关。它们与时间线无关。 它们没有实际意义直到您将它们应用于某个地点以在时间轴上找到一个点。这些类名中的“本地”这个词对于不熟悉的人来说可能是违反直觉的。这个词的意思是任何地方,或每一个地方,但不是一个特定的地方。
因此,对于商业应用程序,“本地”类型并不常用,因为它们仅代表可能的日期或时间的一般概念,而不是时间线上的特定时刻。商业应用程序往往关心发票到达、运输产品、雇用员工或出租车离开车库的确切时间。所以商业应用开发者使用
Instant
和 ZonedDateTime
类最常见。那么我们什么时候使用
LocalDateTime
?在三种情况下:请注意,这三个案例中没有一个涉及时间线上的某个特定点,这些都不是片刻。
一天中的一个时间,多个时刻
有时我们想表示某个日期的某个时间,但想将其应用于跨时区的多个地点。
例如,“圣诞节从 2015 年 12 月 25 日午夜开始”是
LocalDateTime
.午夜在巴黎和蒙特利尔的不同时刻发生,在 Seattle 中再次不同并在 Auckland .LocalDate ld = LocalDate.of( 2018 , Month.DECEMBER , 25 ) ;
LocalTime lt = LocalTime.MIN ; // 00:00:00
LocalDateTime ldt = LocalDateTime.of( ld , lt ) ; // Christmas morning anywhere.
另一个示例,“Acme 公司的政策是,其全局每个工厂的午餐时间从下午 12:30 开始”是 LocalTime
.要获得真正的意义,您需要将其应用到时间线以计算 Stuttgart 处的 12:30 时刻。工厂或 12:30 在 Rabat工厂或 12:30 在 Sydney工厂。预约面谈
另一种使用情况
LocalDateTime
用于预订 future 的 Activity (例如:牙医预约)。这些任命在 future 可能已经足够远,你可能会冒着政治家重新定义时区的风险。政治家通常很少发出预警,甚至根本不发出警告。如果您的意思是“明年 1 月 23 日下午 3 点”而不管政客如何玩时钟,那么您将无法记录片刻——如果该地区采用或取消夏令时,那么下午 3 点将变成下午 2 点或 4 点,例如。对于约会,存储一个
LocalDateTime
和一个 ZoneId
,分开存放。稍后,在生成时间表时,通过调用 LocalDateTime::atZone( ZoneId )
即时确定时刻。生成 ZonedDateTime
目的。ZonedDateTime zdt = ldt.atZone( z ) ; // Given a date, a time-of-day, and a time zone, determine a moment, a point on the timeline.
如果需要,您可以调整为 UTC。提取 Instant
来自 ZonedDateTime
.Instant instant = zdt.toInstant() ; // Adjust from some zone to UTC. Same moment, same point on the timeline, different wall-clock time.
未知区域有些人可能会用
LocalDateTime
在时区或偏移量未知的情况下。我认为这个案子不恰当和不明智。如果区域或偏移量是预期的但未确定,则您的数据是错误的。这就像在不知道预 future 币(美元、英镑、欧元等)的情况下存储产品的价格。不是个好主意。
所有日期时间类型
为了完整起见,这里是所有可能的日期时间类型的表,包括 Java 中的现代和遗留,以及 SQL 标准定义的那些。这可能有助于放置
Instant
& LocalDateTime
更大范围内的类。请注意 Java 团队在设计 JDBC 4.2 时做出的奇怪选择。他们选择支持所有的 java.time 时间……除了两个最常用的类:
Instant
& ZonedDateTime
.但不用担心。我们可以轻松地来回转换。
转换
Instant
.// Storing
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;
// Retrieving
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Instant instant = odt.toInstant() ;
转换 ZonedDateTime
.// Storing
OffsetDateTime odt = zdt.toOffsetDateTime() ;
myPreparedStatement.setObject( … , odt ) ;
// Retrieving
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = odt.atZone( z ) ;
关于 java.time
java.time框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy日期时间类,例如
java.util.Date
, Calendar
, & SimpleDateFormat
.要了解更多信息,请参阅 Oracle Tutorial .并在 Stack Overflow 上搜索许多示例和解释。规范为 JSR 310 .
Joda-Time项目,现在在 maintenance mode ,建议迁移到 java.time类。
您可以直接与您的数据库交换 java.time 对象。使用 JDBC driver符合 JDBC 4.2或以后。不需要字符串,不需要
java.sql.*
类。 Hibernate 5 & JPA 2.2 支持 java.time。从哪里获得 java.time 类?
ThreeTen-Extra项目使用附加类扩展 java.time。该项目是 future 可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如
Interval
, YearWeek
, YearQuarter
, 和 more .
关于java - Instant 和 LocalDateTime 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32437550/