tl; dr
Instant
和LocalDateTime
是两个完全不同的动物:一个表示了一下,其他没有。
Instant
代表时刻,是时间轴中的特定点。
LocalDateTime
代表日期和时间。但是由于缺少时区或UTC偏移量,因此此类无法表示一个时刻。它代表了大约26到27小时(全球所有时区的范围)内的潜在时刻。
不正确的推定
LocalDateTime
而是日期/时钟表示,包括人类的时区。
你的说法是不正确:一个LocalDateTime
有没有时区。没有时区是该课程的重点。
引用该类的文档:
此类不存储或表示时区。相反,它是对用于生日的日期的描述,以及在墙上时钟上看到的本地时间。如果没有其他信息(例如偏移量或时区),则无法在时间线上表示时刻。
因此Local…
意味着“不分区,不偏移”。
Instant
An Instant
是UTC时间轴上的一刻,是自1970年UTC的第一刻的纪元以来的十亿分之一秒(基本上,请参阅class doc了解更多细节)。由于您的大多数业务逻辑,数据存储和数据交换都应使用UTC,因此这是经常使用的方便类。
Instant instant = Instant.now() ; // Capture the current moment in UTC.
OffsetDateTime
class OffsetDateTime
类将时刻表示为日期和时间,并且上下文比UTC早或晚一些小时-分钟-秒。偏移量(小时-分钟-秒的数量)由此ZoneOffset
类表示。
如果时分秒数为零,则OffsetDateTime
表示UTC中与相同的时刻Instant
。
ZoneOffset
所述ZoneOffset
类表示偏移从-UTC,若干小时-分钟-秒比UTC或后面UTC。
A ZoneOffset
仅是小时-分钟-秒的数量,仅此而已。区域更多,具有名称和偏移更改的历史记录。因此,使用区域总是优于仅使用偏移量。
ZoneId
阿时区是由表示ZoneId
类。
例如,巴黎的新天比蒙特利尔早。因此,我们需要移动时钟指针以更好地反映给定区域的正午(当太阳直接在头顶上方)。西欧/非洲的UTC线向东/向西越远,偏移量越大。
时区是一组规则,用于处理本地社区或区域所实施的调整和异常情况。最常见的异常是称为“ 夏令时(DST)”的太流行的疯狂。
时区具有过去规则,当前规则和在不久的将来已确认的规则的历史。
这些规则更改的频率超出您的预期。确保保持日期时间库的规则(通常是'tz'数据库的副本)是最新的。随着Oracle发布了Timezone Updater Tool,在Java 8中保持最新状态比以往更加容易。
指定适当的时区名称,格式Continent/Region
,如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。切勿使用2-4字母的缩写,例如EST
或,IST
因为它们不是真实的时区,不是标准化的,甚至不是唯一的(!)。
时区=偏移量+调整规则
ZoneId z = ZoneId.of( “Africa/Tunis” ) ;
ZonedDateTime
在ZonedDateTime
概念上将其视为Instant
具有分配的对象ZoneId
。
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
,LocalTime
,LocalDateTime
“本地”的日期时间类,LocalDateTime
,LocalDate
,LocalTime
,有一种别样的小动物的。不受任何地区或时区的限制。它们不受时间限制。除非您将它们应用于某个地方以在时间轴上找到一个点,否则它们没有真正的意义。
这些类名称中的“本地”一词可能与未使用的单词相反。该词表示任何地点,或每个地点,但不是特定地点。
因此,对于商务应用程序,“本地”类型不常用,因为它们仅表示可能的日期或时间的一般概念,而不是时间轴上的特定时刻。商业应用程序倾向于关心发票到达的确切时间,运输产品的运输,雇用员工或出租车离开车库的确切时间。因此,业务应用程序开发人员最常使用Instant
和ZonedDateTime
分类。
那我们LocalDateTime
什么时候用?在以下三种情况下:我们要在多个位置应用特定的日期和时间,我们要进行预约,或者我们有一个尚未确定的时区。请注意,这三种情况都不是时间轴上的某个特定点,所有这些都不是片刻。
一天中的多个时间
有时我们想代表某个日期的某个特定时间,但是想要将其应用于跨时区的多个地区。
例如,“圣诞节从2015年12月25日午夜开始”是一个LocalDateTime
。巴黎的午夜罢工与蒙特利尔的罢工时间不同,西雅图和奥克兰的午夜罢工又有所不同。
LocalDate ld = LocalDate.of( 2018 , Month.DECEMBER , 25 ) ;
LocalTime lt = LocalTime.MIN ; // 00:00:00
LocalTime ldt = LocalDateTime.of( ld , lt ) ; // Xmas morning anywhere.
另一个示例是“ Acme公司有一项政策,即在全球每个工厂的午餐时间开始于12:30 PM” LocalTime
。要具有真正的意义,您需要将其应用于时间轴,以计算斯图加特工厂的12:30时刻或拉巴特工厂的12:30时刻或悉尼工厂的12:30时刻。
预约预约
使用的另一种情况LocalDateTime
是用于预订将来的事件(例如:牙医预约)。这些任命将来可能远远不够,您可能会冒着政治家重新定义时区的风险。政客们很少发出预警,甚至根本没有发出警告。如果您的意思是“明年1月23日下午3点”,无论政治人物如何打钟,那么您就无法记录时间-如果该地区采用或放弃了夏时制,那将导致下午3点变成下午2点或下午4点,例如。
对于约会,请分别存储a LocalDateTime
和a 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
在时区或偏移量未知的情况下使用。
我认为这种情况是不适当和不明智的。如果要确定区域或偏移量但不确定,则数据有误。这就像在不知道预期货币的情况下存储产品的价格一样。这不是一个好主意。
所有日期时间类型
为了完整起见,这里列出了所有可能的日期时间类型,包括Java中的现代和遗留类型以及SQL标准定义的日期时间类型。这可能有助于将Instant
&LocalDateTime
类放在更大的上下文中。
注意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和更高版本。这些类取代麻烦的老传统日期时间类,如java.util.Date
,Calendar
,和SimpleDateFormat
。
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
要了解更多信息,请参见Oracle教程。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
您可以直接与数据库交换java.time对象。使用与JDBC 4.2或更高版本兼容的JDBC驱动程序。不需要字符串,不需要类。java.sql.*
在哪里获取java.time类?
该ThreeTen-额外项目与其他类扩展java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。你可能在这里找到一些有用的类,比如Interval
,YearWeek
,YearQuarter
,和更多。