将java.util.Date转换为什么“java.time”types?

我有一个java.util.Date对象或一个java.util.Calendar对象。 如何将其转换为java.time框架中的正确types?

我听说现在我们应该用java.timetypes来完成大部分业务逻辑。 当使用旧时间代码尚未更新的时间我需要能够来回转换。 什么types映射到java.util.Datejava.util.Calendar

是的,你绝对应该尽可能使用java.time框架。

避免旧的date时间课程

包括java.util.Datejava.util.Calendarjava.text.SimpleTextFormat等在内的旧date时间类已被certificate是devise不佳,令人困惑和麻烦的 。 避免他们在可能的地方。 但是,当你必须与这些旧的types互操作时,你可以在新旧之间进行转换。

请继续阅读以获得基本介绍,稍微简化一下,以便让您在旧date和新date时间之间来回移动。

java.time

java.time框架由JSR 310定义,受到高度成功的Joda-Time库的启发,并由ThreeTen-Extra项目扩展。 在ThreeTen-Backport项目中,大部分function都被移植到了Java 6和7中,并在ThreeTenABP项目中进一步改进了Android。

什么java.timetypes与java.util.Date匹配? 那么, java.util.Date对象基本上代表了UTC时间轴上的一个时刻,它是date和时间的组合。 我们可以把它翻译成java.time中的任何几种types。 每个都在下面讨论。 请注意,一些新的方法已被添加到旧的date时间类,以促进转换。

通过ZonedDateTime(或OffsetDateTime)从java.util.Date/.Calendar转换为三个<code> Local ... </ code>类型的图

Instant

java.time中的构build块是一个Instant , UTC中的时间轴上的一个分辨率为纳秒的时刻。

一般来说,你应该用UTC来完成大部分业务逻辑。 在这样的工作中, Instant会经常使用。 传递Instant对象,仅将时区应用于用户呈现。 如果需要应用偏移量或时区,请使用下面进一步介绍的types。

java.util.DateInstant

鉴于Instantjava.util.Date都是UTC时间轴上的一个时刻,我们可以很容易地从java.util.Date移动到Instant 。 旧类已经获得了一个新的方法java.util.Date::toInstant

 Instant instant = myUtilDate.toInstant(); 

你可以从另一个方向,从Instantjava.util.Date 。 但是,您可能会丢失关于小数秒的信息。 Instant追踪纳秒 ,小数点后最多九位数字,如2016-01-23T12:34:56.123456789Z 。 java.util.Date&.Calendar都被限制为毫秒 ,小数点后最多三位数,如2016-01-23T12:34:56.123Z 。 在这个例子中,从InstantDate意味着截断456789

 java.util.Date myUtilDate = java.util.Date.from( instant ); 

java.util.CalendarInstant

怎么样java.util.Calendar而不是java.util.Date ? 在Calendar对象的内部,date时间被跟踪为以UTC( 1970-01-01T00:00:00.0Z )的1970年第一时间的历元引用date时间的毫秒数。 所以这个值可以很容易地转换成Instant

 Instant instant = myUtilCalendar.toInstant() ; 

java.util.GregorianCalendarZonedDateTime

更妙的是,如果你的java.util.Calendar对象实际上是一个java.util.GregorianCalendar你可以直接进入一个ZonedDateTime 。 这种方法有保留embedded的时区信息的好处。

Calendar的界面 下降到GregorianCalendar的具体类 。 然后调用toZonedDateTimefrom方法来回。

 if( myUtilCalendar instanceof GregorianCalendar ) { GregorianCalendar gregCal = (GregorianCalendar) myUtilCalendar; // Downcasting from the interface to the concrete class. ZonedDateTime zdt = gregCal.toZonedDateTime(); // Create `ZonedDateTime` with same time zone info found in the `GregorianCalendar` end if 

走向另一个方向

  java.util.Calendar myUtilCalendar = java.util.GregorianCalendar.from( zdt ); // Produces an instant of `GregorianCalendar` which implements `Calendar` interface. 

如上所述,请注意,您可能会丢失有关秒的小数部分的信息.Calendar / .GregorianCalendar中的java.timetypes( ZonedDateTime )中的毫微秒会被截断为毫秒 。

OffsetDateTime

Instant我们可以应用从UTC的偏移量移动到某个地点的挂钟时间 。 偏移量是UTC (向东)或UTC(西向)之后的小时数,可能是分钟和秒。 ZoneOffset类表示这个想法。 结果是一个OffsetDateTime对象。

 ZoneOffset offset = ZoneOffset.of( "-04:00" ); OffsetDateTime odt = OffsetDateTime.ofInstant( instant , zoneOffset ); 

你可以走另一个方向,从OffsetDateTimejava.util.Date 。 提取Instant ,然后按照上面的代码进行操作。 如上所述,任何纳秒都会被截断到毫秒 ( 数据丢失 )。

 java.util.Date myUtilDate = java.util.Date.from( odt.toInstant() ); 

ZonedDateTime

更好的是,应用一个全时区 。 时区是偏移加上处理exception情况(如夏令时(DST))的规则 。

应用ZoneId会为您提供一个ZonedDateTime对象。 使用适当的时区名称 (大陆/地区)。 切勿使用通常所见的3-4字母缩写(如ESTIST因为它们既不标准也不唯一。

 ZoneId zoneId = ZoneId.of( "America/Montreal" ); ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId ); 

你可以从ZonedDateTime转到java.util.Date 。 提取Instant ,然后按照上面的代码进行操作。 如上所述,任何纳秒都会被截断到毫秒 ( 数据丢失 )。

 java.util.Date myUtilDate = java.util.Date.from( zdt.toInstant() ); 

而且我们在上面看到, ZonedDateTime可能会转换为GregorianCalendar

LocalDate

有时你可能想要一个只有date的值,没有时间和没有时区。 为此,使用java.time.LocalDate对象。

请参阅这个问题的更多讨论, 转换java.util.Date到java.time.LocalDate ,特别是这个答案写的主要背后的人Joda-Time和java.time的发明。

关键是要通过一个ZonedDateTime (如上面的代码生成)。 我们需要一个时区来确定一个date。 date在世界各地不同,在东部早些时候有了新的一天。 例如,巴黎的午夜过后是新的一天,而在蒙特利尔仍然是“昨天”。 因此,当LocalDate包含时区时,需要时区来确定 LocalDate

 LocalDate localDate = zdt.toLocalDate(); 

LocalDate转换到date时间意味着创build一个时间。 您可以select在您的业务场景中有意义的任何时间。 对大多数人来说,一天中的第一个时刻是有意义的。 在00:00:00.0的时候,你可能会试图在第一时间硬编码。 在某些时区,由于夏令时(DST)或其他exception情况,这段时间可能无法在第一时间有效。 所以让java.time通过调用atStartOfDay来确定正确的时间。

 ZonedDateTime zdt = localDate.atStartOfDay( zoneId ); 

LocalTime

在极less数情况下,您可能只需要一个没有date和时区的时间。 这个概念由LocalTime类表示。 正如上面用LocalDate所讨论的,即使LocalTime对象不包含(不记住)该时区,我们也需要一个时区来确定LocalTime 。 所以,我们再次通过一个从Instant获得的ZonedDateTime对象,如上所示。

 LocalTime localTime = zdt.toLocalTime(); 

LocalDateTime

与其他两个Local…types一样, LocalDateTime没有时区和偏移量。 因此你可能很less使用这个。 它给你一个date时间的概念,但不是时间轴上的一个点。 如果你的意思是一些普通的date和一些可能适用于某个时区的时间,请使用它。

例如,“今年圣诞节开始”将是2016-12-25T00:00:00.0 。 请注意, LocalDateTime文本表示中缺less任何偏移量或时区。 德里印度的圣诞节早于巴黎法国,后来在加拿大魁北克省的蒙特利尔。 应用这些区域的每个时区将在时间轴上产生不同的时刻。

 LocalDateTime ldt = zdt.toLocalDateTime();