tl;dr
Instant
和LocalDateTime
是两种完全不同的动物:一种代表瞬间,另一种不代表瞬间.
Instant
代表一个时刻,时间线上的一个特定点.
LocalDateTime
表示日期和一天中的时间.但是缺少时区或与UTC的偏移,this class cannot represent a moment.它代表了大约26到27小时范围内的potential个时刻,这是全球所有时区的范围.值LocalDateTime
是inherently ambiguous.
Incorrect Presumption
LocalDateTime
相当于日期/时钟表示,包括人类的时区.
你的说法不正确:A 100 has no time zone.没有时区是这门课的重点.
引用该类文档:
此类不存储或表示时区.相反,它是对日期的描述,用于生日,与挂钟上显示的当地时间相结合.如果没有偏移量或时区等附加信息,它不能表示时间线上的某个瞬间.
所以Local…
意味着"没有分区,没有偏移".
Instant
Instant
是UTC中的时间轴上的一个时刻,自1970UTC的第一个时刻以来的计数是nanoseconds(基本上,请参见doc类以了解具体细节).因为您的大部分业务逻辑、数据存储和数据交换都应该在UTC中,所以这是一个经常使用的方便类.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
OffsetDateTime
OffsetDateTime
类课程将某个时刻表示为日期和时间,上下文为UTC之前或之后的时分秒数.偏移量(小时分秒数)由ZoneOffset
类表示.
如果小时-分钟-秒数为零,则OffsetDateTime
表示UTC中的时刻,与Instant
相同.
ZoneOffset
ZoneOffset
级表示offset-from-UTC,即比UTC早或晚UTC的小时-分钟-秒数.
ZoneOffset
只是小时-分钟-秒的数字,仅此而已.分区的意义要大得多,因为它有一个名称和要偏移的修改历史.因此,使用分区总是比仅使用偏移更可取.
ZoneId
time zone由ZoneId
级表示.
例如,新的一天在Paris年比在Montréal年来得早.因此,我们需要移动时钟指针,以便更好地反射给定区域的noon(当太阳在正上方时).在西欧/非洲,距离UTC线东/西越远,偏移量越大.
时区是当地社区或地区处理调整和异常情况的一套规则.最常见的异常现象是被称为Daylight Saving Time (DST)的非常流行的精神病.
时区有过go 的规则、现在的规则和为不久的将来确定的规则的历史.
这些规则的变化比你想象的要频繁.确保你的约会时间库的规则是最新的,通常是the 'tz' database的副本.随着甲骨文发布了Timezone Updater Tool,在Java8中保持最新比以往任何时候都要容易.
以Continent/Region
的格式指定proper time zone name,例如America/Montreal
、Africa/Casablanca
或Pacific/Auckland
.千万不要使用2-4个字母的缩写,例如EST
或IST
,因为它们是not个真实时区,不是标准化的,甚至不是唯一的(!).
时区=偏移量+调整规则
ZoneId z = ZoneId.of( “Africa/Tunis” ) ;
ZonedDateTime
从概念上来说,把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
"本地"日期时间类LocalDateTime
、LocalDate
、LocalTime
是另一种生物.这些数据不与任何一个地点或时区相关联.它们与时间线无关.They have no real meaning,直到你把它们应用到一个地方,在时间线上找到一个点.
这些类名中的"Local"一词对新手来说可能是违反直觉的.这个词的意思是any个地方,或every个地方,但not个是一个特定的地方.
因此,对于商业应用程序,"Local"类型并不经常使用,因为它们只表示可能的日期或时间的一般概念,而不是时间线上的特定时刻.商业应用程序往往关心发票到达的确切时刻,运输中的产品,雇用员工的时间,或者出租车离开车库的时间.因此,业务应用程序开发人员最常用的是Instant
和ZonedDateTime
个类.
那我们什么时候用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 )
来生成ZonedDateTime
Object来确定时刻.
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
门课.
请注意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.Date
、Calendar
和;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类?
ThreeTen-Extra项目扩展了java.有额外课程的时间.这个项目是javafuture 可能增加的一个试验场.时间你可以在这里找到一些有用的类,比如Interval
、YearWeek
、YearQuarter
和more.