java - Instant 和 LocalDateTime 有什么区别?

标签 java datetime java-8

我知道:

  • 即时 而是用于计算的“技术”时间戳表示(纳秒)。
  • 本地日期时间 而是日期/时钟表示,包括人类的时区。

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

    你能说出一些应用程序示例,其中应该只使用 Instant 或 LocalDateTime 吗?

    编辑:当心误读 LocalDateTime 有关精度和时区的文档

    最佳答案

    Table of all date-time types in Java, both modern and legacy
    tl;博士InstantLocalDateTime是两种完全不同的动物:一种代表片刻,另一种则不代表。

  • 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 enter image description here
    Instant 是时间线上的一个时刻 UTC ,计数 nanoseconds自 1970 UTC 第一个时刻以来(基本上,请参阅类(class)文档以了解详细信息)。由于您的大部分业务逻辑、数据存储和数据交换都应采用 UTC,因此这是一个经常使用的方便类。
    Instant instant = Instant.now() ;  // Capture the current moment in UTC.
    
    OffsetDateTime enter image description here
    类(class) OffsetDateTime 类将一个时刻表示为日期和时间,其上下文在 UTC 之前或之后一定数量的小时-分钟-秒。偏移量,即小时-分钟-秒数,由 ZoneOffset 表示类(class)。
    如果小时-分钟-秒数为零,则 OffsetDateTime 代表 UTC 中的一个时刻,与 Instant 相同.ZoneOffset enter image description here
    ZoneOffset 类代表一个 offset-from-UTC , UTC 之前或之后的小时-分钟-秒数。
    一个 ZoneOffset只是几个小时-分钟-秒,仅此而已。一个区域远不止这些,有一个名称和一个要偏移的更改历史。因此,使用区域总是比仅使用偏移更可取。ZoneId enter image description here
    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 个字母的缩写,例如 ESTIST因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

    Time Zone = Offset + Rules of Adjustments

    ZoneId z = ZoneId.of( “Africa/Tunis” ) ; 
    
    ZonedDateTime enter image description here
    想想 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 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.
    “本地”日期时间类, LocalDateTime , LocalDate , LocalTime ,是一种不同的小动物。与任何一个地点或时区无关。它们与时间线无关。 它们没有实际意义直到您将它们应用于某个地点以在时间轴上找到一个点。
    这些类名中的“本地”这个词对于不熟悉的人来说可能是违反直觉的。这个词的意思是任何地方,或每一个地方,但不是一个特定的地方。
    因此,对于商业应用程序,“本地”类型并不常用,因为它们仅代表可能的日期或时间的一般概念,而不是时间线上的特定时刻。商业应用程序往往关心发票到达、运输产品、雇用员工或出租车离开车库的确切时间。所以商业应用开发者使用 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. 
    
    另一个示例,“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更大范围内的类。
    Table of all date-time types in Java (both modern & legacy) as well as SQL standard.
    请注意 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 类?
  • Java SE 8 , Java SE 9 , Java SE 10 , Java SE 11 ,以及更高版本 - 标准 Java API 的一部分,具有捆绑的实现。
  • Java 9带来了一些小功能和修复。

  • Java SE 6Java SE 7
  • 大多数 java.time 功能在 ThreeTen-Backport 中向后移植到 Java 6 和 7。 .

  • Android
  • 更高版本的 Android (26+) 捆绑了 java.time 类的实现。
  • 对于早期的 Android (<26),一个称为 API desugaring 的进程带来了 subset of the java.time最初未内置于 Android 中的功能。
  • 如果脱糖不能满足您的需求,ThreeTenABP项目适应 ThreeTen-Backport (上面提到的)到Android。见 How to use ThreeTenABP… .



  • Table of which java.time library to use with which version of Java or Android
    ThreeTen-Extra项目使用附加类扩展 java.time。该项目是 future 可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如 Interval , YearWeek , YearQuarter , 和 more .

    关于java - Instant 和 LocalDateTime 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32437550/

    相关文章:

    java - 克隆一个整数

    Java 8 :How to remove duplicates from the List based on multiple properties preserving the order

    Java 8 javadoc 工具差异和 gradle 错误 : how to work around it?

    java - 输入不匹配 JNA

    java - 如何使用spring注解将一个POJO对象注入(inject)到另一个POJO?

    java - Java 中 Google App Engine 中的 SQL 查询?

    Jpa @OnetoOne 与 Java8 的关系

    azure - KQL 日期时间格式

    mysql - 使用字符串日期的转换更新日期时间

    python - 从一系列开始和结束日期生成 Pandas 数据框