我知道那件事:
Instant 是一种用于计算的“技术”时间戳表示形式(纳秒)。
LocalDateTime 是日期/时钟表示形式,包括人类的时区。
尽管如此,最终 IMO 都可以作为大多数应用程序用例的类型。例如:当前,我正在运行一个批处理作业,我需要根据日期计算下一次运行,并且我正在努力寻找这两种类型之间的优/弊(除了纳秒精度优势和时区部分)。InstantLocalDateTime
您能否列举一些仅使用或应该使用的应用示例?InstantLocalDateTime
另外:
Java 中所有日期时间类型的表,包括现代日期时间和传统日期时间类型
tl;博士
Instant并且是两种完全不同的动物:一个代表一个时刻,另一个则不代表。LocalDateTime
Instant表示一个时刻,即时间轴中的特定点。
LocalDateTime表示日期和时间。但是,由于缺少时区或与 UTC 的偏移量,此类无法表示时刻。它表示大约 26 到 27 小时范围内的潜在时刻,即全球所有时区的范围。值本质上是不明确的。LocalDateTime
不正确的推定
LocalDateTime而是日期/时钟表示,包括人类的时区。
您的语句不正确:LocalDateTime 没有时区。没有时区是该类的全部意义所在。
引用该类的文档:
此类不存储或表示时区。相反,它是对日期的描述,用于生日,结合挂钟上看到的当地时间。它不能在没有其他信息(如偏移量或时区)的情况下表示时间线上的某个时刻。
So 的意思是 “未分区,无偏移”。Local…
Instant
在此处输入图像描述
瞬间是 UTC 时间轴上的一个时刻,自 1970 UTC 的第一个时刻以来的纳秒计数(基本上,请参阅类 doc 了解细节)。由于您的大多数业务逻辑、数据存储和数据交换都应该使用 UTC,因此这是一个经常使用的方便类。
Instant instant = Instant.now() ; // Capture the current moment in UTC.
OffsetDateTime
在此处输入图像描述
类 OffsetDateTime 类将时刻表示为日期和时间,其上下文为 UTC 之前或之后的某个小时-分钟-秒数。偏移量(小时-分钟-秒数)由 ZoneOffset 类表示。
如果小时-分钟-秒数为零,则 OffsetDateTime 表示 UTC 中的时刻,与 Instant相同。
ZoneOffset
在此处输入图像描述
ZoneOffset 类表示与 UTC 的偏移量,即 UTC 之前或 UTC 之后的小时-分钟-秒数。
A 只是小时-分钟-秒的数量,仅此而已。区域的作用要多得多,它有一个名称和要偏移的更改历史。因此,使用 zone 总是比仅使用 offset 更可取。ZoneOffset
ZoneId
enter image description here
时区由 ZoneId 类表示。
例如,巴黎的新一天比蒙特利尔更早。因此,我们需要移动时钟的指针,以更好地反映给定区域的正午(当太阳正好在头顶时)。在西欧/非洲,距离 UTC 线向东/向西越远,偏移量就越大。
时区是当地社区或地区用于处理调整和异常的一组规则。最常见的异常情况是被称为夏令时 (DST) 的非常流行的疯狂。
时区包含过去规则、当前规则和近期确认规则的历史记录。
这些规则的更改频率可能比您预期的要高。请务必使日期时间库的规则(通常是 'tz' 数据库的副本)保持最新。在 Java 8 中,随着 Oracle 发布了 Timezone Updater Tool,保持最新状态比以往任何时候都更容易。
以 格式指定适当的时区名称,例如 、 或 。切勿使用 2-4 个字母的缩写,例如 或 因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!Continent/RegionAmerica/MontrealAfrica/CasablancaPacific/AucklandESTIST
时区 = 偏移量 + 调整规则
ZoneId z = ZoneId.of( “Africa/Tunis” ) ;
ZonedDateTime
在此处输入图像描述
从概念上将 ZonedDateTime 视为具有分配的 .InstantZoneId
ZonedDateTime = ( 即时 + ZoneId )
要捕获特定区域(时区)的人们使用的挂钟时间中看到的当前时刻,请执行以下操作:
ZonedDateTime zdt = ZonedDateTime.now( z ) ; // Pass a ZoneId
object such as ZoneId.of( "Europe/Paris" )
.
几乎所有的后端、数据库、业务逻辑、数据持久性、数据交换都应该使用 UTC。但是为了向用户展示,您需要调整到用户期望的时区。这是该类和用于生成这些日期时间值的 String 表示形式的格式化程序类的用途。ZonedDateTime
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, ,LocalTimeLocalDateTime
Diagram showing only a calendar for a LocalDate.
Diagram showing only a clock for a LocalTime.
显示 LocalDateTime 的日历加时钟的图表。
“本地”日期时间类 LocalDateTime、LocalDate、LocalTime 是一种不同类型的小动物。它们不局限于任何一个地方或时区。它们不受时间线的约束。它们没有真正的意义,直到你把它们应用到一个地方,在时间轴上找到一个点。
这些类名中的“Local”一词对于外行来说可能违反直觉。这个词的意思是任何地方,或每个地方,但不是特定的地方。
因此,对于商业应用程序,“Local” 类型并不经常使用,因为它们只表示可能的日期或时间的一般概念,而不是时间轴上的特定时刻。商业应用程序往往关心发票到达的确切时间、产品运输、员工被雇用或出租车离开车库的确切时间。因此,商业应用程序开发人员最常使用 and 类。InstantZonedDateTime
那么我们什么时候会使用 ?在三种情况下:LocalDateTime
我们希望在多个位置应用特定的日期和时间。
我们正在预约。
我们有一个预期但尚未确定的时区。
请注意,这三种情况都不涉及时间轴上的某个特定点,都不是时刻。
一天中的一个时间,多个时刻
有时我们想表示某个日期的某个时间,但又想将其应用于跨时区的多个地区。
例如,“圣诞节从 2015 年 12 月 25 日午夜开始”是一个 .午夜来袭的时刻在巴黎和蒙特利尔不同,西雅图和奥克兰也不同。LocalDateTime
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 Company 有一项政策,即其全球每个工厂的午餐时间从下午 12:30 开始”是一个 .要获得真正的意义,您需要将其应用于时间线,以计算斯图加特工厂的 12:30 或拉巴特工厂的 12:30 或悉尼工厂的 12:30 的时刻。LocalTime
预约
另一种情况是预订未来的活动(例如:牙医预约)。这些任命可能在未来足够遥远,以至于您冒着政客重新定义时区的风险。政客们往往很少发出预警,甚至根本没有预警。如果你的意思是“明年 1 月 23 日下午 3 点”,无论政客们如何玩弄时钟,那么你都无法记录一个时刻——例如,如果该地区采用或放弃夏令时,那么下午 3 点就会变成下午 2 点或 4 点。LocalDateTime
对于约会,将 a 和 a 分开保存。稍后,在生成计划时,通过调用 Generate Object 来动态确定时刻。LocalDateTimeZoneIdLocalDateTime::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。从 中提取 an 。InstantZonedDateTime
Instant instant = zdt.toInstant() ; // Adjust from some zone to UTC. Same moment, same point on the timeline, different wall-clock time.
未知区域
有些人可能会在时区或偏移量未知的情况下使用。LocalDateTime
我认为这个案子不合适,也不明智。如果区域或偏移量是预期的,但尚未确定,则您的数据是错误的。这就像在不知道预期货币(美元、英镑、欧元等)的情况下存储产品的价格。这不是一个好主意。
所有日期时间类型
为了完整起见,下表列出了所有可能的日期时间类型,包括 Java 中的现代和传统类型,以及 SQL 标准定义的日期时间类型。这可能有助于将 & 类置于更大的上下文中。InstantLocalDateTime
Java(包括现代和遗留的)以及SQL标准中的所有日期时间类型的表。
请注意 Java 团队在设计 JDBC 4.2 时所做的奇怪选择。他们选择支持所有 java.time 时间...除了两个最常用的类: & .InstantZonedDateTime
但不用担心。我们可以轻松地来回转换。
转换。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 及更高版本中。这些类取代了麻烦的旧的遗留日期时间类,如java.util.Date、Calendar和SimpleDateFormat。
要了解更多信息,请参阅 Oracle 教程。并在 Stack Overflow 中搜索许多示例和解释。规范为 JSR 310。
Joda-Time 项目现在处于维护模式,建议迁移到 java.time 类。
您可以直接与数据库交换 java.time 对象。使用符合 JDBC 4.2 或更高版本的 JDBC 驱动程序。不需要字符串,不需要类。Hibernate 5 & JPA 2.2支持java.time。java.sql.*
从哪里获得 java.time 类?
Java SE 8、Java SE 9、Java SE 10、Java SE 11 及更高版本 - 标准 Java API 的一部分,具有捆绑实施。
Java 9 带来了一些小功能和修复。
Java SE 6 和 Java SE 7
大部分java.time功能在ThreeTen-Backport中被反向移植到Java 6和7。
人造人
更高版本的 Android (26+) bundle 实现了 java.time 类。
对于早期的 Android (<26),称为 API 脱糖的过程带来了 java.time 功能的一部分,该功能最初未内置于 Android 中。
如果脱糖不能提供您需要的东西,ThreeTenABP 项目会将 ThreeTen-Backport(如上所述)适应 Android。请参阅如何使用 ThreeTenABP...。
哪个 java.time 库与哪个版本的 Java 或 Android 一起使用的表
ThreeTen-Extra 项目使用其他类扩展了 java.time。该项目是将来可能添加到 java.time 的试验场。您可以在此处找到一些有用的类,例如 Interval、YearWeek、YearQuarter 等。
共享
改进此答案
跟随
编辑于 2022 年 8 月 15 日 14:35
Ahmed Sayed 的用户头像
艾哈迈德·赛义德
46611 枚金徽章99 枚银质徽章1616 枚铜牌
回答 2015年9月 7日 (星期日) 16:40
Basil Bourque 的用户头像
巴兹尔·布尔克
336 千米119119 枚金质徽章917917 枚银质徽章1,2千米1.2k 铜徽章
88
很好的回答。我认为一些混淆(至少是我的)来自本地命名。我对 Local 的直觉意味着与我所处的位置和我何时 (?!) 有关,这让我相信它实际上就是 ZonedDateTime 是什么。
–
mkobit
评论9月 8, 2015 在 13:55
8
是的,这很令人困惑。这就是为什么 java.time 巧妙地在其前身 Joda-Time(生成 ZonedDateTime)使用的 DateTime 类名中添加“Zoned”一词,以强调与“Local”类的区别。将名称 “Local” 视为 “need to be applied to some particular locality” 的简写。
–
巴兹尔·布尔克
评论9月 8, 2015 在 16:14
2
以单词 Local 为前缀也可能是与 java.util 包区分开来的一种方式,尽管不知何故,我觉得可能有更好的单词选择。
–
riddle_me_this
评论3月 31, 2016 在 18:23
2
@simonh 恰恰相反......当该新员工签署他/她的招聘文件,定义他们的福利(包括人寿保险),然后该新员工走出去喝咖啡却被卡车撞死时,会有很多人,如人力资源经理、保险代理人和律师,他们想知道新工作生效的确切时间。
–
巴兹尔·布尔克
评论4月 7, 2017 在 21:45
3
@simonh 是的,在某些情况下,“本地”日期时间是合适的。除了我的回答中提到的那些之外,商业中的另一个常见情况是在未来几个月内进行预约,时间足够长,以至于政客们可能会改变时区规则,通常几乎没有预先警告。政客经常进行这些更改,例如更改开启/关闭夏令时 (DST) 的日期或永久开启/关闭 DST。