我知道:

即时是一种用于计算的“技术”时间戳表示(纳秒)。 LocalDateTime是包含人类时区的日期/时钟表示。

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

您能举出一些只使用Instant或LocalDateTime的应用程序示例吗?

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


当前回答

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

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

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

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

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

其他回答

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

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

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

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

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

关于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对象将具有完全相同的值。

博士tl;

Instant和LocalDateTime是两种完全不同的东西:一个表示时刻,另一个不表示时刻。

Instant表示时间轴上的一个特定点。 LocalDateTime表示日期和一天中的时间。但是由于缺少时区或与utc的偏移量,该类不能表示时刻。它代表了26到27小时范围内的潜在时刻,即全球所有时区的范围。LocalDateTime值本质上是不明确的。

错误的假设

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

您的陈述是不正确的:LocalDateTime没有时区。没有时区是这门课的全部意义所在。

引用这个类的doc:

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

所以Local…的意思是“不分区,不偏移”。

即时

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

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

OffsetDateTime

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

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

ZoneOffset

ZoneOffset类表示一个相对于UTC的偏移量,一个比UTC早或晚的小时-分钟-秒数。

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

ZoneId

时区由ZoneId类表示。

例如,在巴黎,新的一天的黎明要比Montréal早。因此,我们需要移动时钟的指针,以更好地反映给定地区的中午(太阳直射时)。西欧/非洲距离UTC线越东/西,偏移量越大。

时区是当地社区或地区对时间调整和异常情况的一套处理规则。最常见的反常现象是众所周知的“日光节约时间”(DST)。

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

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

请指定合适的时区名称,格式为“大陆/地区”,如“美洲/蒙特利尔”、“非洲/卡萨布兰卡”或“太平洋/奥克兰”。不要使用2-4个字母的缩写,如EST或IST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

时区=偏移量+调整规则

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

分区日期时间

在概念上,可以将zoneeddatetime视为具有已分配ZoneId的Instant。

分区日期时间 = ( 即时 + 区域 ID )

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

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

几乎所有的后端、数据库、业务逻辑、数据持久性、数据交换都应该使用UTC。但是为了向用户演示,您需要调整到用户期望的时区。这就是zoneeddatetime类和用于生成这些日期-时间值的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 ) ;

2019年4月30日,星期二,印度时间23:22:55

LocalDate, LocalTime, LocalDateTime

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

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

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

什么时候使用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。

预订预约

Another situation to use LocalDateTime is for booking future events (ex: Dentist appointments). These appointments may be far enough out in the future that you risk politicians redefining the time zone. Politicians often give little forewarning, or even no warning at all. If you mean "3 PM next January 23rd" regardless of how the politicians may play with the clock, then you cannot record a moment – that would see 3 PM turn into 2 PM or 4 PM if that region adopted or dropped Daylight Saving Time, for example.

对于约会,存储一个LocalDateTime和一个ZoneId,分别保存。稍后,在生成调度时,通过调用LocalDateTime::atZone(ZoneId)来生成一个zoneeddatetime对象,从而动态地确定一个时刻。

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。从zoneeddatetime中提取一个瞬间。

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团队在设计JDBC 4.2时所做的一些奇怪的选择。他们选择支持所有的java。除了两个最常用的类:Instant和zoneeddatetime。

但不用担心。我们可以很容易地来回转换。

转换。

// 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。时间框架内置于Java 8及更高版本中。这些类取代了麻烦的旧遗留日期-时间类,如java.util。日期,日历和简单日期格式。

要了解更多,请参阅Oracle教程。搜索Stack Overflow可以找到很多例子和解释。规范是JSR 310。

Joda-Time项目现在处于维护模式,建议迁移到java。时间类。

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

从哪里获取java。时间类?

Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation. Java 9 brought some minor features and fixes. Java SE 6 and Java SE 7 Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport. Android Later versions of Android (26+) bundle implementations of the java.time classes. For earlier Android (<26), a process known as API desugaring brings a subset of the java.time functionality not originally built into Android. If the desugaring does not offer what you need, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above) to Android. See How to use ThreeTenABP….

ThreeTen-Extra项目扩展了java。额外的课程时间。这个项目是未来可能添加到java.time的一个试验场。你可以在这里找到一些有用的类,比如Interval、YearWeek、YearQuarter等等。

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

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

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

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

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