我知道:

  • Instant相当于用于计算的"技术"时间戳表示(纳秒).
  • 对于人类来说,LocalDateTime相当于日期/时钟表示法,包括时区.

最后,对于大多数应用程序用例来说,IMO都可以看作是一种类型.例如:目前我正在运行一个批处理作业(job),其中我需要根据日期计算下一次运行,我正在努力寻找这两种类型之间的优缺点(除了Instant的纳秒精度优势和LocalDateTime的时区优势之外).

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

Edit: Beware misread documentations for LocalDateTime regarding precision and time-zone

推荐答案

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

tl;dr

InstantLocalDateTime是两种完全不同的动物:一种代表瞬间,另一种不代表瞬间.

  • Instant代表一个时刻,时间线上的一个特定点.
  • LocalDateTime表示日期和一天中的时间.但是缺少时区或与UTC的偏移,this class cannot represent a moment.它代表了大约26到27小时范围内的potential个时刻,这是全球所有时区的范围.值LocalDateTimeinherently ambiguous.

Incorrect Presumption

LocalDateTime相当于日期/时钟表示,包括人类的时区.

你的说法不正确:A 100 has no time zone.没有时区是这门课的重点.

引用该类文档:

此类不存储或表示时区.相反,它是对日期的描述,用于生日,与挂钟上显示的当地时间相结合.如果没有偏移量或时区等附加信息,它不能表示时间线上的某个瞬间.

所以Local…意味着"没有分区,没有偏移".

Instant

enter image description here

InstantUTC中的时间轴上的一个时刻,自1970UTC的第一个时刻以来的计数是nanoseconds(基本上,请参见doc类以了解具体细节).因为您的大部分业务逻辑、数据存储和数据交换都应该在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早或晚UTC的小时-分钟-秒数.

ZoneOffset只是小时-分钟-秒的数字,仅此而已.分区的意义要大得多,因为它有一个名称和要偏移的修改历史.因此,使用分区总是比仅使用偏移更可取.

ZoneId

enter image description here

time zoneZoneId级表示.

例如,新的一天在Paris年比在Montréal年来得早.因此,我们需要移动时钟指针,以便更好地反射给定区域的noon(当太阳在正上方时).在西欧/非洲,距离UTC线东/西越远,偏移量越大.

时区是当地社区或地区处理调整和异常情况的一套规则.最常见的异常现象是被称为Daylight Saving Time (DST)的非常流行的精神病.

时区有过go 的规则、现在的规则和为不久的将来确定的规则的历史.

这些规则的变化比你想象的要频繁.确保你的约会时间库的规则是最新的,通常是the 'tz' database的副本.随着甲骨文发布了Timezone Updater Tool,在Java8中保持最新比以往任何时候都要容易.

Continent/Region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland.千万不要使用2-4个字母的缩写,例如ESTIST,因为它们是not个真实时区,不是标准化的,甚至不是唯一的(!).

时区=偏移量+调整规则

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

ZonedDateTime

enter image description here

从概念上来说,把ZonedDateTime想象成一个Instant和一个ZoneId.

ZoneDateTime=(即时+区域ID)

要捕捉特定地区(时区)的人使用的挂钟时间中显示的当前时刻,请执行以下操作:

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

LocalDate, LocalTime, LocalDateTime

Diagram showing only a calendar for a LocalDate.

Diagram showing only a clock for a LocalTime.

Diagram showing a calendar plus clock for a LocalDateTime.

"本地"日期时间类LocalDateTimeLocalDateLocalTime是另一种生物.这些数据不与任何一个地点或时区相关联.它们与时间线无关.They have no real meaning,直到你把它们应用到一个地方,在时间线上找到一个点.

这些类名中的"Local"一词对新手来说可能是违反直觉的.这个词的意思是any个地方,或every个地方,但not个是一个特定的地方.

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

那我们什么时候用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. 

另一个例子是LocalTime.要想有真正的意义,你需要把它应用到时间线上,计算出Stuttgart工厂的12:30或Rabat工厂的12:30或Sydney工厂的12:30.

预约预约

使用LocalDateTime的另一种情况是预订future 的活动(例如:牙医预约).这些任命在future 可能会非常遥远,以至于政客们可能会重新定义时区.政客们通常很少预先警告,甚至根本没有警告.如果你的意思是"明年1月23日下午3点",不管政客们如何摆弄时钟,那么你不能记录一个时刻——例如,如果该地区采用或取消夏令时,下午3点会变成下午2点或4点.

预约时,储存一张LocalDateTime和一张ZoneId,分开保存.随后,当生成时间表时,飞翔上通过调用LocalDateTime::atZone( ZoneId )来生成ZonedDateTimeObject来确定时刻.

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.

我认为这种情况是不恰当的,也是不明智的.如果一个分区或偏移是预期的,但尚未确定,则表示数据不正确.这就像在不知道预期货币(美元、英镑、欧元等)的情况下存储产品的价格.这不是个好主意.

All date-time types

为了完整起见,这里有一个表,列出了所有可能的日期时间类型,包括Java中的现代日期时间类型和传统日期时间类型,以及SQL标准定义的日期时间类型.这可能有助于放置Instant&;在更大范围内有LocalDateTime门课.

Table of all date-time types in Java (both modern & legacy) as well as SQL standard.

请注意Java团队在设计JDBC4.2时做出的奇怪 Select .他们 Select 支持所有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 ) ; 

About java.time

java.time框架内置于Java8及更高版本中.这些类取代了麻烦的旧legacy日期时间类,如java.util.DateCalendar和;SimpleDateFormat

要了解更多信息,请参阅Oracle Tutorial.并在Stack Overflow中搜索许多示例和解释.规格是JSR 310.

Joda-Time项目,现在是maintenance mode,建议迁移到java.time个类.

您可以直接与数据库交换java.time个对象.使用符合JDBC 4.2或更高版本的JDBC driver.不需要字符串,不需要java.sql.*个类.冬眠5&;JPA 2.2支持java.time.

从哪里获得java.time类?

Table of which java.time library to use with which version of Java or Android

ThreeTen-Extra项目扩展了java.有额外课程的时间.这个项目是javafuture 可能增加的一个试验场.时间你可以在这里找到一些有用的类,比如IntervalYearWeekYearQuartermore.

Java相关问答推荐

在这种情况下我应该/可以使用Java抽象工厂(或工厂方法)吗?

将具有多个未知字段的SON映射到Java POJO

为什么如果数组列表中有重复项,我的代码SOMETIMES不返回true?

JsonPath在多个线程中返回错误的值

将成为一个比较者.比较…在现代Java中,编译器会对`CompareTo`方法进行优化吗?

我无法将附件发送到NetBeans之外

如何以干净的方式访问深度嵌套的对象S属性?

扩展到弹出窗口宽度的JavaFX文本字段

在springboot 3中,当我调用api endpoint时,会出现404

Jenv-相同的Java版本,但带有前缀

在Eclipse中数组的可空性

如何只修改父类ChroniclerView位置0处的第一个嵌套ChroniclerView(child)元素?

如何在JavaFX中制作鼠标透明stage

Java中不兼容的泛型类型

如果第一位数字和最后一位数字相差超过一位,您将如何获得随机数?

使IntelliJ在导入时优先 Select 一个类或将另一个标记为错误

我的代码是线程安全的吗?[Java、CAS、转账]

在ECLIPSE上的M1 Pro上运行JavaFX的问题

整数->;双取消框,但双->;int不';t开箱.为什么?

java.lang.NoSuchMethodError:';org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream$Builder org.apache.poi-poi-ooxml-5.2.4