Instant和LocalDateTime之间的区别是什么?

我知道:

  • 即时是相当“技术性”的;用于计算的时间戳表示(纳秒)。
  • LocalDateTime是人类的日期/时钟表示。

最后,IMO可以作为大多数应用程序用例的类型。举个例子:目前,我正在运行一个批处理作业,我需要根据日期计算下一次运行,并且我正在努力寻找这两种类型之间的优缺点(除了Instant的纳秒精度优势和LocalDateTime的时区部分)。

你能举出一些只使用InstantLocalDateTime的应用例子吗?

编辑:小心误读LocalDateTime关于精度和时区的文档。

205304 次浏览

一个主要的区别是“本地的”;LocalDateTime的一部分。如果你生活在德国并创建了一个LocalDateTime实例,而其他人生活在美国并在同一时刻创建了另一个实例(假设时钟设置正确)-这些对象的值实际上是不同的。这不适用于Instant,它是独立于时区计算的。

LocalDateTime存储没有时区的日期和时间,但它的初始值是依赖于时区的。Instant的不是。

此外,LocalDateTime提供了操作日期组件的方法,如日、小时和月。Instant则不是。

除了Instant的纳秒精度优势和 LocalDateTime的时区部分

这两个类具有相同的精度。LocalDateTime不存储时区。仔细阅读Javadocs,因为你可能会因为这样的无效假设而犯一个大错误:InstantLocalDateTime

你对LocalDateTime的理解是错误的:它不存储任何时区信息,并且具有纳秒精度。引用Javadoc(我的重点):

ISO-8601日历系统中没有时区的日期-时间,如2007-12-03T10:15:30。

LocalDateTime是一个不可变的日期-时间对象,表示日期-时间,通常被视为年-月-日-小时-分-秒。还可以访问其他日期和时间字段,例如一年中的一天、一周中的一天和一年中的一周。时间以纳秒精度表示。例如,值“2nd October 2007 at 13:45.30.123456789"可以存储在LocalDateTime中。

两者之间的区别是Instant表示从Epoch(01-01-1970)的偏移,因此,表示时间线上的特定时刻。在地球上两个不同的地方同时创建的两个Instant对象将具有完全相同的值。

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

博士tl;

InstantLocalDateTime是两种完全不同的动物:一个代表一个时刻,另一个不代表。

  • Instant代表一个时刻,时间轴上的一个特定点。
  • LocalDateTime表示日期和时间。但缺少时区或偏移utc, 该类不能表示时刻。它代表了大约26到27小时范围内的潜在的时刻,即全球所有时区的范围。LocalDateTime的值是固有的模棱两可的

错误的假设

LocalDateTime是包含人类时区的日期/时钟表示。

你的陈述是不正确的:A < A href="http://docs.oracle.com/javase/11/docs/api/java/time/LocalDateTime.html" rel="noreferrer">LocalDateTime has no时区。没有时区是这门课的全部意义所在。

引用这个类的doc:

该类不存储或表示时区。相反,它是对日期的描述,就像生日一样,结合墙上时钟上的当地时间。它不能在没有偏移量或时区等附加信息的情况下表示时间线上的瞬间。

所以Local…表示“没有分区,没有偏移量”。

Instant

enter image description here

InstantUTC中的时间轴上的一个时刻,是自1970 UTC的第一个时刻的epoch以来的纳秒的计数(基本上,查看类文档了解基本细节)。由于大多数业务逻辑、数据存储和数据交换都应该使用UTC,因此这是一个经常使用的方便类。

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

OffsetDateTime

enter image description here

OffsetDateTime类将时刻表示为一个日期和时间,其上下文为UTC前后的某个小时-分钟-秒数。偏移量,即小时-分钟-秒的数量,由ZoneOffset类表示。

如果小时-分钟-秒数为零,则OffsetDateTime表示UTC中的时刻,与Instant相同。

ZoneOffset

enter image description here

ZoneOffset类表示一个offset-from-UTC,一个比UTC早或晚的小时-分钟-秒数。

ZoneOffset仅仅是一个小时-分钟-秒的数字,仅此而已。区域远不止这些,它有一个名称和要抵消的更改历史。因此,使用区域总是比使用偏移量更好。

ZoneId

enter image description here

时区ZoneId类表示。

例如,在巴黎中,新的一天比在蒙特利尔中来得早。因此,我们需要移动时钟的指针,以更好地反射中午(当太阳直射时)。西欧/非洲距离UTC线越东/西,偏移量越大。

时区是当地社区或地区对时间调整和异常情况的一套处理规则。最常见的异常是被称为日光节约时间(DST)的非常流行的疯狂。

时区具有过去规则、当前规则和近期确认的规则的历史。

这些规则的变化比你想象的要频繁。确保日期时间库的规则(通常是“tz”数据库的副本)是最新的。在Java 8中,随着Oracle发布时区更新工具,保持更新比以往任何时候都容易。

指定格式为Continent/Region正确的时区名称,例如America/MontrealAfrica/Casablanca,或Pacific/Auckland。永远不要使用2-4个字母的缩写,如ESTIST,因为它们是真实时区,不是标准化的,甚至不是唯一的(!)。

时区=偏移量+调整规则

ZoneId z = ZoneId.of( “Africa/Tunis” ) ;

ZonedDateTime

enter image description here

从概念上看,ZonedDateTime是一个带有赋值ZoneIdInstant

zoneeddatetime = (Instant + ZoneId)

要捕捉特定地区(时区)的人们所使用的挂钟时间中的当前时刻:

ZonedDateTime zdt = ZonedDateTime.now( z ) ;  // Pass a `ZoneId` object such as `ZoneId.of( "Europe/Paris" )`.

几乎所有的后端、数据库、业务逻辑、数据持久性、数据交换都应该使用UTC。但是为了向用户演示,您需要调整到用户期望的时区。这就是ZonedDateTime类和formatter类用于生成这些日期-时间值的String表示的目的。

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小时22分55秒heure de l 'Inde

__abc0, __abc1, __abc2

仅显示LocalDate日历的图表。 < / >

仅显示LocalTime时钟的图表。 < / >

为LocalDateTime显示日历加时钟的图表。 < / >

“local"日期时间类,LocalDateTimeLocalDateLocalTime,是一种不同的生物。它们不局限于任何一个地点或时区。它们不受时间轴的限制。它们没有真正的意义,直到你将它们应用到一个位置以找到时间轴上的一个点。

对于外行来说,这些类名中的“Local”可能是违反直觉的。这个词的意思是任何局部性或每一个局部性,但是一个特定的局部性。

因此,对于商业应用程序,“本地”;类型不常被使用,因为它们只表示可能的日期或时间的一般概念,而不是时间轴上的特定时刻。商业应用程序往往关心发票到达的确切时间,产品运输的确切时间,员工的确切时间,或者出租车离开车库的确切时间。因此,商业应用程序开发人员最常使用InstantZonedDateTime类。

那么什么时候使用LocalDateTime呢?在三种情况下:

  • 我们希望跨多个位置应用特定的日期和时间。
  • 我们正在预约。
  • 我们预定了一个尚未确定的时区。

请注意,这三种情况都不涉及时间轴上的某个特定点,它们都不是一个时刻。

一天中的一个时间,多个时刻

有时,我们希望表示某一天的某个时间,但希望将其应用到跨时区的多个位置。

例如,“圣诞节开始于2015年12月25日午夜”;是LocalDateTime。巴黎的午夜钟声与Montréal不同,在西雅图奥克兰中也是不同的。

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。为了具有真正的意义,您需要将其应用到时间轴上,以计算斯图加特工厂的12:30或拉巴特工厂的12:30或悉尼工厂的12:30。

预订预约

使用LocalDateTime的另一种情况是预订未来的事件(例如:牙医预约)。这些任命可能是很久以后的事了,你可能要冒着政客们重新定义时区的风险。政客们通常很少提前发出警告,甚至根本不发出警告。如果你是指“明年1月23日下午3点”;不管政客们如何玩弄时钟,你都无法记录下一个时刻——例如,如果该地区采用或放弃日光节约时间,下午3点就会变成下午2点或下午4点。

对于约会,存储LocalDateTimeZoneId,分别保存。稍后,在生成调度时,通过调用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。从ZonedDateTime中提取Instant

Instant instant = zdt.toInstant() ;  // Adjust from some zone to UTC. Same moment, same point on the timeline, different wall-clock time.

未知区

有些人可能会在时区或偏移量未知的情况下使用LocalDateTime

我认为这个案子不合适也不明智。如果指定了一个区域或偏移量,但未确定,则有坏数据。这就像存储产品的价格而不知道预期的货币(美元、英镑、欧元等)。这不是个好主意。

所有日期-时间类型

为了完整起见,这里列出了所有可能的日期-时间类型,包括Java中的现代和传统日期-时间类型,以及SQL标准定义的日期-时间类型。这可能有助于将Instant &LocalDateTime类在更大的上下文中。

 Java中所有日期-时间类型的表(现代&以及SQL标准。”/ > < / ></p>
<p>注意Java团队在设计JDBC 4.2时所做的一些奇怪的选择。他们选择支持所有的<em>java.time</em>次数,除了两个最常用的类:<code>Instant</code>和amp;<code>ZonedDateTime</code>。</p>
<p>但不用担心。我们可以很容易地来回转换。</p>
<p><code>Instant</code>转换。</p>
<pre><code>// Storing
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;


// Retrieving
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Instant instant = odt.toInstant() ;
</code></pre>
<p><code>ZonedDateTime</code>转换。</p>
<pre><code>// 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 ) ;
</code></pre>
<hr />
<h1>关于<em>java.time</em></h1>
<p><a href=< em > java.time < / em >框架内置于Java 8及更高版本中。这些类取代了麻烦的旧遗产日期-时间类,如java.util.DateCalendar, &SimpleDateFormat

要了解更多信息,请参见< < em >甲骨文教程/ em >。搜索Stack Overflow可以找到很多例子和解释。规格是JSR 310

现在在维护模式中的< em > Joda-Time < / em >项目建议迁移到java.time类。

你可以直接与你的数据库交换java.time对象。使用与JDBC 4.2或更高版本兼容的JDBC驱动程序。不需要字符串,不需要java.sql.*类。Hibernate 5 &JPA 2.2支持java.time

从哪里获取java。时间类?

表的java。“/></a> . time library with哪个版本的Java或Android</p>
<p><a href=< >强ThreeTen-Extra < / >强项目扩展了java。额外的课程时间。这个项目是未来可能添加到java.time的一个试验场。你可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter更多的

LocalDateTime没有时区信息:一个LocalDateTime可能代表世界各地不同机器的不同瞬间。因此,您不应该尝试将它与隐式时区(系统的默认时区)一起使用。你应该根据它所代表的内容来使用它,例如“新年是1月1日,在0:00”:这意味着在地球上的所有点都是不同的时间,但在这种情况下是需要的。

Instant是格林威治时区的一个时间点。例如,除了用户的时区之外,还可以使用它向用户显示他/她所在时区的会议开始时间。

如果这两个类不代表您想要存储/交换的内容,那么也许ZonedDateTime或其他类可以做得更好。

下面是一个简单的合成模式,可以获得java中类的总体情况。时间包及其与ISO-8601标准的关系,用于在Java和其他语言或框架之间可靠而轻松地交换日期和时间:

 java的类。时间包及其与ISO-8601标准 . xml "的关系

这里详细解释了模式:http://slaout.linux62.org/java-date-time/